关于 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高级程序设计第二版》】

  1. 创建一个新对象
  2. this指向这个对象【将构造函数的作用域赋给新对象】
  3. 执行构造函数中的代码【为新对象添加属性】
  4. 返回新对象
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);

 

 

解析,仔细想想哦~~~
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");

 

posted @ 2012-08-18 13:57  acjialiren  阅读(1595)  评论(2编辑  收藏  举报