关于 javascript 中的 this
首先推荐两篇好文章,我对 this 的理解都靠这两篇文章了
http://www.cnblogs.com/rubylouvre/archive/2009/11/13/1602122.html
this 的值取决于 function 被调用的方式,一共有四种,
- 如果一个 function 是一个对象的属性,该 funtion 被调用的时候,this 的值是这个对象。如果 function 调用的表达式包含句点(.)或是 [],this 的值是句点(.)或是 [] 之前的对象。如myObj.func 和myObj["func"] 中,func 被调用时的 this 是myObj。
- 如果一个 function 不是作为一个对象的属性,那么该 function 被调用的时候,this 的值是全局对象。当一个 function 中包含内部 function 的时候,如果不理解 this 的正确含义,很容易造成错误。这是由于内部 function 的 this 值与它外部的 function 的 this 值是不一样的。解决办法是将外部 function 的 this 值保存在一个变量中,在内部 function 中使用它来查找变量。
- 如果在一个 function 之前使用 new 的话,会创建一个新的对象,该 funtion 也会被调用,而 this 的值是新创建的那个对象。如function User(name) {this.name = name}; var user1 = new User("Alex"); 中,通过调用new User("Alex") ,会创建一个新的对象,以user1 来引用,User 这个 function 也会被调用,会在user1 这个对象中设置名为name 的属性,其值是Alex 。
- 可以通过 function 的 apply 和 call 方法来指定它被调用的时候的 this 的值。 apply 和 call 的第一个参数都是要指定的 this 的值。由于它们存在,我们得以创建各种有用的函数。
http://www.cn-cuckoo.com/2010/05/08/about-one-sentence-of-pro-js-2nd-1626.html
- 函数作为哪个对象的方法调用,函数体内的this(不包括嵌套定义在其中的函数中的this)指向的就是那个对象。
- 结合new运算符调用一个构造函数时,系统会先自动生成一个对象,然后在该对象上调用构造函数。此时在构造函数体内,this指向的就是这个对象。
- 直接调用一个函数,相当于把它当作全局对象的方法调用。
- JavaScript中没有类作用域的概念,因此方法内部要访问据以调用此方法的那个对象的属性,必须使用this关键字,按“this.属性名”的语法来访问。
与这个问题相关的还有一个函数体内的名称解析的问题。我看过的JavaScript教材上都说得不太全面。实际上,那种直接引用的名称,其名称解析是在作用域链上进行的;而那种按“obj.属性名”方式引用的名称,其名称解析是在obj的原型对象链上进行的(首先检查obj是否直接定义了同名属性,如果没有,则在其原型对象链上逐层查找)。理解了这一点,就更能搞清前面的this与作用域的瓜葛。
例子:
1.函数作为哪个对象的方法调用,函数体内的this(不包括嵌套定义在其中的函数中的this)指向的就是那个对象。
var person = {};
person.name = "shenmajs";
person.sayName = function(){ alert(this.name); };
person.sayName();
//弹出shenmajs,是person调用了sayName,this指向person
2.直接调用一个函数,相当于把它当作全局对象的方法调用。(window)
var name = "window";
function alertName(){ alert(this.name);
}
alertName();
//弹出window,直接调用alertName方法,相当于全局对象调用了此方法,全局变量name当作了全局对象的属性
3.结合new运算符调用一个构造函数时,系统会先自动生成一个对象,然后在该对象上调用构造函数。此时在构造函数体内,this指向的就是这个对象。
New关键字创建实例时的四个步奏:【来自《javascript高级程序设计第二版》】
- 创建一个新对象
- this指向这个对象【将构造函数的作用域赋给新对象】
- 执行构造函数中的代码【为新对象添加属性】
- 返回新对象
function Person (name){
this.name = name; //构造的过程中,this指向新的那个实例
this.sayhello = function (){
alert(this.name);
}
}
var person = new Person("shenmajs");
person.sayhello(); //弹出shenmajs ,因为sayhello方法是由person调用的
4.javascript中的函数都是对象,函数的名字只是一个包含指针的变量。this是动态的,调用的时候更具情境确定。
function alertName(){
alert(this.name);
}
var name = "window";
var person = {};
person.name = "shenmajs";
person.sayName = alertName; //sayName 与 alertName 都是指向那个方法实例的指针变量而已
person.sayName(); //弹出shenmajs,是person调用了alertName,this指向person
alertName(); //弹出window,直接调用alertName方法,相当于全局对象调用了此方法,全局变量name当作了全局对象的属性
再次强调,函数名称只是指向函数的指针,因此this与它出现的函数在哪里定义无关。
function Person (name,age){ this.age = age; this.name = name; this.sayHello = function(){ alert("hi," +this.name ); }; } var person = new Person("shenmajs",25); var func = person.sayHello;// func 指向 function(){ alert("hi," +this.name ); 它只是一个函数指针,与person.sayHello 指向一个函数
var name = "window"; func(); //func直接调用 this指向全局对象
5.如果 function 调用的表达式包含句点(.)或是 [],this 的值是句点(.)或是 [] 之前的对象。句点的情况已经说明,现在说明下[]的情况。
[]可以用来访问对象的属性
var person = {};
person.name = "shenmajs";
person.sayName = function(){ alert(this.name); };
person["sayName"](); //弹出shenmajs,是person调用了sayName,this指向person,相当于person.sayName();
[]也可以用来访问数组元素
var name = "window";
var arraytest = [function(){alert(this[2]);},function(){alert(this.name);},"shenmajs"];//函数也是一种类型,匿名函数在这里当做数组的一个元素
arraytest.name = "arraytest";
var arrayfunc = [];
function func(){
alert(this[1]);
}
arrayfunc[0] = func;
arrayfunc[1] = 99;
var functest1 = func;
var functest2 = arraytest[1];
arraytest[0]();
//弹出shenmajs ,this指向arraytest,this[2] 等价于 arraytest[2]。我一开始也不理解为什么会指向arraytest,只能死记了。
arraytest[1]();
//弹出arraytest,同样,this指向 arraytest,this.name 相当于arraytest.name . 我给arraytest加了一个name属性。这也是js动态语言的特性
arrayfunc[0]();
//弹出99 ,数组中的第一个元素指向了函数,这样调用时this指向了 arrayfunc数组,同上面的道理 this[1] 相当于 arrayfunc[1]
functest1();
//弹出 undefined ,相当于直接调用 func,this指向全局对象 window[1]未定义,因此弹出undefined
functest2();
//弹出window ,functest2 = arraytest[1],变量functest2指向函数,这里调用 即相当于直接调用,this指向全局变量。
最后给大家个考题,看你弄懂没,有点小变态。
var length = 9; var foo = { bar: function() { return this.length; }, length: 0 }; (function f(a, b) { f.length = 1; alert(arguments[0]()); alert(a()); alert(f.length); alert((foo.bar)()); })(foo.bar,2,"str");
注:
(function(){...})() 是指定义一个函数,并且马上执行它。
(函数定义)(执行函数的参数)
(function(a,b){alert(a+b);})(9,12);
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
length = 9; var foo = { bar: function() { return this.length; }, length: 0 }; (function f(a, b) { f.length = 1; //f.length 表示函数形参个数,就是函数定义的括号里有几个参数,此属性不可写,因此 f.length 永远是2 . // http://ecma-international.org/ecma-262/5.1/#sec-15.3.3.2 alert(arguments[0]()); //argumengts表示实参,即函数时间传递进来的参数,f立即执行时,传进来三个参数 (..f..)(foo.bar,2,"str") //弹出3,this指向arguments,arguments.length 等于 3 alert(a()); //弹出9, a指向 foo.bar所指向的函数,a()直接调用,this相当于window全局对象,this.length 等于 9 alert(f.length); // 弹出2 ,此属性不可写 alert((foo.bar)()); //弹出0,foo调用函数bar,this指向 foo。 需要说明的是 foo.bar() 和 (foo.bar)()的效果一样。 })(foo.bar,2,"str");
q:329952402