JavaScript中5种调用函数的方法


Posted in Javascript onMarch 12, 2015

这篇文章详细的介绍了Javascript中各种函数调用的方法及其原理,对于理解JavaScript的函数有很大的帮助!

JavaScript,调用函数的5种方法

一次又一次的,我发现,那些有bug的Javascript代码是由于没有真正理解Javascript函数是如何工作而导致的(顺便说一下,许多那样的代码是我写的).JavaScript拥有函数式编程的特性, 当我们选择面对它的时候,这将成为我们前进的阻碍.

作为初学者,我们来测试五种函数调用的方法,从表面来看我们会认为那些函数与C#中函数的作用非常相似,但是我们一会儿可以看到还是有非常重要的不同的地方的,忽视这些差异无疑会导致难于跟踪的bug。首先让我们创建一个简单的函数,这个函数将在将在下文中使用,这个函数仅仅返回当前的this的值和两个提供的参数.

<script type="text/javascript">

function makeArray(arg1, arg2){

    return [ this, arg1, arg2 ];

}

</script>

最常用的方法,但不幸的,全局的函数调用
当我们学习Javascript时,我们了解到如何用上面示例中的语法来定义函数。
,我们也知道调用这个函数非常的简单,我们需要做的仅仅是:

makeArray('one', 'two');

// => [ window, 'one', 'two' ]

 

Wait a minute. What's that window

 

 

alert( typeof window.methodThatDoesntExist );

// => undefined

alert( typeof window.makeArray);

// =>

 

 

window.makeArray('one', 'two');

// => [ window, 'one', 'two' ]

我说最普遍的调用方法是不幸的是因为它导致我们声明的函数默认是全局的.我们都知道全局成员不是编程的最佳实践.这在JavaScript里是特别的正确,在JavaScript中避免使用全局的成员,你是不会为之后悔的.

JavaScript函数调用规则1
在没有通过明确所有者对象而直接调用的函数中,如myFunction(),将导致this的值成为默认对象(浏览器中的窗口)。

函数调用

让我们现在创建一个简单的对象,使用 makeArray函数作为它的一个方法,我们将使用json的方式来声明一个对象,我们也来调用这个方法

//creating the object

var arrayMaker = {

    someProperty: 'some value here',

    make: makeArray

};

 

//invoke the make() method

arrayMaker.make('one', 'two');

// => [ arrayMaker, 'one', 'two' ]

// alternative syntax, using square brackets

arrayMaker['make']('one', 'two');

// => [ arrayMaker, 'one', 'two' ]

看到这里的不同了吧,this的值变成了对象本身.你可能会疑问原始的函数定义并没有改变,为何它不是window了呢.好吧,这就是函数在JSavacript中传递的方式,函数在JavaScript里是一个标准的数据类型,确切的说是一个对象.你可以传递它们或者复制他们.就好像整个函数连带参数列表和函数体都被复制,且被分配给了 arrayMaker里的属性make,那就好像这样定义一个 arrayMaker:

var arrayMaker = {

    someProperty: 'some value here',

    make: function (arg1, arg2) {

        return [ this, arg1, arg2 ];

    }

};

JavaScript函数调用规则2

在一个使用方法调用语法,像 obj.myFunction()或者 obj['myFunction'](),这时this的值为obj

这是事件处理代码中bug的主要源头,看看这些例子

<input type="button" value="Button 1" id="btn1"  />

<input type="button" value="Button 2" id="btn2"  />

<input type="button" value="Button 3" id="btn3"  onclick="buttonClicked();"/>

 

<script type="text/javascript">

function buttonClicked(){

    var text = (this === window) ? 'window' : this.id;

    alert( text );

}

var button1 = document.getElementById('btn1');

var button2 = document.getElementById('btn2');

 

button1.onclick = buttonClicked;

button2.onclick = function(){   buttonClicked();   };

</script>

点击第一个按钮将会显示”btn”因为它是一个方法调用,this为所属的对象(按钮元素) 点击第二个按钮将显示”window”因为 buttonClicked是被直接调用的(不像 obj.buttonClicked().) 这和我们第三个按钮,将事件处理函数直接放在标签里是一样的.所以点击第三个按钮的结果是和第二个一样的.
使用像jQuery的JS库有这样的优点,当在jQuery里定义了一个事件处理函数,JS库会帮助重写this的值以保证它包含了当前事件源元素的引用,

//使用jQuery

$('#btn1').click( function() {

    alert( this.id ); // jQuery ensures 'this' will be the button

});

jQuery是如何重载this的值的呢?继续阅读

另外两个:apply()和call()

你越多的使用JavaScript的函数,你就越多的发现你需要传递函数并在不同的上下文里调用他们,就像Qjuery在事件处理函数里所做的一样,你往往经常需要重置this的值.记住我告诉你的,在Javascript中函数也是对象,函数对象包含一些预定义的方法,其中有两个便是apply()和call(),我们可以使用它们来对this进行重置.

var gasGuzzler = { year: 2008, model: 'Dodge Bailout' };

makeArray.apply( gasGuzzler, [ 'one', 'two' ] );

// => [ gasGuzzler, 'one' , 'two' ]

makeArray.call( gasGuzzler,  'one', 'two' );

// => [ gasGuzzler, 'one' , 'two' ]

这两个方法是相似的,不同的是后面的参数的不同,Function.apply()是使用一个数组来传递给函数的,而Function.call()是将这些参数独立传递的,在实践中你会发现apply()在大多数情况下更方便.

JSavacript函数调用规则3

如果我们想在不复制函数到一个方法而想重载this的值的时候,我们可以使用 myFunction.apply( obj ) 或 myFunction.call( obj ).

构造器

我不想深入研究在Javascript中类型的定义,但是在此刻我们需要知道在Javascript中没有类,而且任何一个自定义的类型需要一个初始化函数,使用原型对象(作为初始化函数的一个属性)定义你的类型也是一个不错的主义,让我们来创建一个简单的类型

//声明一个构造器

function ArrayMaker(arg1, arg2) {

    this.someProperty = 'whatever';

    this.theArray = [ this, arg1, arg2 ];

}

// 声明实例化方法

ArrayMaker.prototype = {

    someMethod: function () {

        alert( 'someMethod called');

    },

    getArray: function () {

        return this.theArray;

    }

};

 

var am = new ArrayMaker( 'one', 'two' );

var other = new ArrayMaker( 'first', 'second' );

 

am.getArray();

// => [ am, 'one' , 'two' ]

一个非常重要并值得注意的是出现在函数调用前面的new运算符,没有那个,你的函数就像全局函数一样,且我们创建的那些属性都将是创建在全局对象上(window),而你并不想那样,另一个话题是,因为在你的构造器里没有返回值,所以如果你忘记使用new运算符,将导致你的一些变量被赋值为 undefined.因为这个原因,构造器函数以大写字母开头是一个好的习惯,这可以作为一个提醒,让你在调用的时候不要忘记前面的new运算符.

带着这样的小心,初始化函数里的代码和你在其他语言里写的初始化函数是相似的.this的值将是你将创建的对象.

Javascript函数调用规则4

当你将函数用作初始化函数的时候,像MyFunction(),Javascript的运行时将把this的值指定为新建的对象.

我希望理解各种函数调用方式的不同会使你的Sjavacript代码远离bugs,有些这样的bug会确保你总是知道this的值是避免他们第一步。

Javascript 相关文章推荐
JQuery AJAX实现目录浏览与编辑的代码
Oct 21 Javascript
基于Jquery的$.cookie()实现跨越页面tabs导航实现代码
Mar 03 Javascript
比例尺、缩略图、平移缩放之百度地图添加控件方法
Aug 03 Javascript
js实现简洁的TAB滑动门效果代码
Sep 06 Javascript
JS实现按比例缩放图片的方法(附C#版代码)
Dec 08 Javascript
Jquery插件仿百度搜索关键字自动匹配功能
May 11 Javascript
文本框只能输入数字的js代码(含小数点)
Jul 10 Javascript
关于vue.extend和vue.component的区别浅析
Aug 16 Javascript
js实现HTML中Select二级联动的实例
Jan 05 Javascript
小程序实现自定义导航栏适配完美版
Apr 02 Javascript
vue动态禁用控件绑定disable的例子
Oct 28 Javascript
jQuery实现简单全选框
Sep 13 jQuery
JavaScript实现的一个倒计时的类
Mar 12 #Javascript
JavaScript将XML转成JSON的方法
Mar 12 #Javascript
JavaScript中诡异的delete操作符
Mar 12 #Javascript
JavaScript实现计算字符串中出现次数最多的字符和出现的次数
Mar 12 #Javascript
jquery实现页面关键词高亮显示的方法
Mar 12 #Javascript
JavaScript设计模式学习之“类式继承”
Mar 12 #Javascript
鼠标事件的screenY,pageY,clientY,layerY,offsetY属性详解
Mar 12 #Javascript
You might like
以文本方式上传二进制文件的PHP程序
2006/10/09 PHP
我的论坛源代码(六)
2006/10/09 PHP
Ubuntu下安装PHP的mongodb扩展操作命令
2015/07/04 PHP
PHP中Closure类的使用方法及详解
2015/10/09 PHP
PHP实现补齐关闭的HTML标签
2016/03/22 PHP
Laravel Intervention/image图片处理扩展包的安装、使用与可能遇到的坑详解
2017/11/14 PHP
在jQuery 1.5中使用deferred对象的代码(翻译)
2011/03/10 Javascript
百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换
2016/02/19 Javascript
Bootstrap按钮下拉菜单组件详解
2016/05/10 Javascript
js/jquery控制页面动态加载数据 滑动滚动条自动加载事件的方法
2017/02/08 Javascript
JS中mouseup事件丢失的原因与解决办法
2017/06/14 Javascript
js数字滑动时钟的简单实现(示例讲解)
2017/08/14 Javascript
vue中的provide/inject的学习使用
2018/05/09 Javascript
详解如何在Node.js的httpServer中接收前端发送的arraybuffer数据
2018/11/11 Javascript
Vue实现微信支付功能遇到的坑
2019/06/05 Javascript
js实现省级联动(数据结构优化)
2020/07/17 Javascript
python 获取本机ip地址的两个方法
2013/02/25 Python
用Python给文本创立向量空间模型的教程
2015/04/23 Python
浅谈Python中的可变对象和不可变对象
2017/07/07 Python
详解用python实现简单的遗传算法
2018/01/02 Python
转换科学计数法的数值字符串为decimal类型的方法
2018/07/16 Python
详解Python爬取并下载《电影天堂》3千多部电影
2019/04/26 Python
python编程进阶之异常处理用法实例分析
2020/02/21 Python
兰蔻加拿大官方网站:Lancome加拿大
2016/08/05 全球购物
LN-CC美国:伦敦时尚生活的缩影
2019/02/19 全球购物
TALLY WEiJL法国网上商店:服装、时装及配饰
2019/08/31 全球购物
音乐教学反思
2014/02/02 职场文书
优秀幼教自荐信
2014/02/03 职场文书
文明餐桌行动实施方案
2014/02/19 职场文书
小学校长汇报材料
2014/08/20 职场文书
语文课外活动总结
2014/08/27 职场文书
中学生民族团结演讲稿
2014/08/27 职场文书
教师党的群众路线学习心得体会
2014/11/04 职场文书
小学生六年级作文之关于感恩
2019/08/16 职场文书
python中super()函数的理解与基本使用
2021/08/30 Python
Golang ort 中的sortInts 方法
2022/04/24 Golang