javascript语言精粹学习笔记之函数的四种this调用模式

  最近在看《javascript语言精粹》,感觉里面很多内容写得特别好,这本书不太适合初学者阅读,而是适合有一定js开发基础的的读者,推荐有基础的又想继续学习javascript的去看看。

  这里记录并摘抄了一些书中内容,是关于javascript中函数中的this的使用的问题,归纳得很好,如果有对this的使用还比较模糊不是很清楚的可以在此一起讨论学习。

  调用一个函数会暂停当前函数的执行,传递控制权和参数给新函数。除了声明时定义的形式参数,每个函数还自动接收两个附加的参数:this和arguments。参数this在面向对象编程中十分重要,它的值取决于调用的模式。在javascript中一共有4种调用模式:方法调用模式、函数调用模式、构造器调用模式和apply调用模式。这些模式在如何初始化关键参数this上存在差异。

  调用运算符是跟在任何产生一个函数值的表达式之后的一对圆括号。圆括号内可包含零个或多个用逗号隔开的表达式,每个表达式产生一个参数值,每个参数值被赋予函数声明时定义时的参数名。当实际参数(实参arguments)的个数与形式参数(形参parameters)的个数不匹配时不会导致运行时错误。如果实际参数过多了,超出的参数将被忽略。如果实际参数值过少,缺失的值将会被替换为undefined。对参数值不会进行类型检查:任何类型的值都可以被传递给参数。

  方法调用模式:当一个函数被保存为对象的一个属性时,我们称它为一个方法。当一个方法被调用时,this被绑定到这个对象。如果调用表达式包含一个提取属性的动作(即包含一个 . 点表达式或[subscript]下标表达式),那么它就是被当做一个方法来调用。

 1 //创建myObject对象,他有一个value属性和一个increment方法
 2 //increment方法接受一个可选参数。如果参数不是数字,那么默认使用数字1
 3 var myObject = {
 4     value: 0,
 5     increment:function(inc){
 6         this.value += (typeof inc === "number" ? inc : 1);
 7     }
 8 };
 9 myObject.increment();
10 document.writeln(myObject.value);                //结果为1
11 
12 myObject.increment(2);
13 document.writeln(myObject.value);                  //结果为3
14 
15 //常见的简单事件绑定就属于这种调用模式
16 eleNode.onclick = function(){
17     console.log(this);                    //绑定事件的eleNode
18 }

  函数调用模式:当一个函数并非一个对象的属性时,那么它就是被当做一个函数来调用的:

var sum = add(3,4);                            //sum的值为7,函数调用

  以此方式调用函数时,this被绑定到全局对象(window?)。这是语言设计上的一个错误,倘若语言设计正确,那么当内部函数被调用时,this应该仍然绑定到外部函数的this变量。这个设计错误的后果就是方法不能利用内部函数来帮助它工作,因为内部函数的this函数被绑定错误的值,所以不能共享该方法对对象的访问权。幸运的是,有一个很容易的解决方案:如果该方法定义一个变量并给它赋值为this,那么内部函数就可以通过那个变量访问到this。按照约定,我把那个变量命名为that:

 1 //给myObject增加一个double方法
 2 myObject.double = function(){
 3     var that = this;
 4     var helper = function(){
 5         that.value = add(that.value, that.value);
 6     };
 7     helper();
 8 };
 9 //以方法的形式调用double
10 myObject.double();
11 document.writeln(myObject.value);         //结果为6

  构造器调用模式:如果在一个函数前面带上new来调用,那么背地里将会创建一个链接到该函数的prototype成员的新对象,同时,this会被绑定到那个新对象中。

New前缀也会改变return语句的行为。

 1 //创建一个名为Con的构造器函数,它构造一个带有status属性的对象
 2 var Con = function(string){
 3     this.status = string;
 4 }; 
 5 //给Con的所有实例提供一个名为getStatus的公共方法
 6 Con.prototype.getStatus = function(){
 7     return this.status;
 8 };
 9 //构造一个Con实例。
10 var myCon = new Con("confused");
11 document.writeln(myCon.getStatus());         //打印显示"confused"

  Apply调用模式:apply方法让我们构建一个参数数组传递给调用函数,他也允许我们选择this的值。apply方法接收两个参数,第一个是要绑定给this的值,第二个就是一个参数数组。另一种为Call调用模式,本质上和Apply调用模式是没区别的,只是传递参数的方式有点区别,具体区别可看apply和call方法的讲解。

       构造一个包含两个数字的数组,并将它们相加。

1 var array = [3,4];
2 var sum = add.apply(null,array);             //sum的值为7
3 //构造一个包含status成员的对象
4 var statusObject = {
5     status: "A-OK"
6 };
7 //statusObject并没有继承自Con.prototype,但我们可以在statusObject上调用getStatus方法,尽管statusObject并没有一个名为getStatus的方法
8 var status = Con.prototype.getStatus.apply(statusObject);            //status值为"A-OK"

  前辈们教我们的一句话就是,写代码并不难,只要善于归纳、善于总结,了解其中的规律并记住他们然后拿来运用几次就掌握了。第一次写博客在此分享,难免会有不足的地方,虽然大部分都是书中的内容,有不好的希望各位能指出,我会虚心接受学习。

posted @ 2013-06-09 12:17  张_紫爷  Views(250)  Comments(0Edit  收藏  举报