js的this作用域

作者:zccst

this作用域以前专门学习研究过,但发现依然不够全面和完整。现在继续学习

先列出之前看过的结论:

函数在被调用的时候会意外接受两个参数:this和argument,其中this的值跟取决于函数的调用模式
1,方法调用模式 o.a() //this指的o
2,函数调用模式 a() //this指的windows
3,构造器调用模式 new a() //this为a的实例对象
4,apply(call)的间接调用模式 a.apply(xx,[yy]) //this指的xx

 

但是,上面的描述并没有指出背后的联系,换一种描述方式:

在这里列出this在ECMAScript中的不同含义:

(1) 在全局执行环境中使用this,表示Global对象,在浏览器中就是window对象。

(2) 当在函数执行环境中使用this时,情况就有些复杂了。如果函数没有明显的作为非window对象的属性,而只是定义了函数,不管这个函数是不是定义在另一个函数中,这个函数中的this仍然表示window对象。如果函数显示地作为一个非window对象的属性,那么函数中的this就代表这个对象。(当然可以使用apply或者call函数来取代默认this的引用,详见[P88])

(3) 当通过new运算符来调用函数时,函数被当做一个构造函数,this指向构造函数创建出来的对象。 
参考: 
《JavaScript基础与案例开发详解》清华大学出版社

 

场景一,一个函数的this与内部函数的this是否相等

var a = 1;
function f1(){
    this.a = 2;
    console.log(this.a+a);// 4
    function f2(){
        this.a = 3;
        console.log(this.a+a); // 6 如果注释掉this.a=3,则是4
    }
    f2();
}
f1();

根据新的描述,虽然嵌套定义,但只是定义了函数,所以this作用域仍是window。经测试,三层嵌套后,this也指向window。

很早就看过this的四种总结,但实际应用中还是远远不够,各种情况下还需要继续深入理解。

在 JavaScript 中,上下文对象就是 this 指针,即被调用函数所处的环境。上下文对象的作用是在一个函数内部引用调用它的对象本身。
在 JavaScript 中,本质上,函数类型的变量是指向这个函数实体的一个引用,在引用之间赋值不会对对象产生复制行为。我们可以通过函数的任何一个引用调用这个函数,不同之 处仅仅在于上下文。
仔细观察上面的例子,使用不同的引用来调用同一个函数时,this 指针永远是这个引用所属的对象

var scope = 'top';
var f1 = function() { 
    console.log(scope);
};
f1(); // 输出 top
var f2 = function() { 
    var scope = 'f2'; 
    f1(); // 输出 top
};
f2();

函数作用域的嵌套关系是定义时决定的,而不是调用时决定的,也就是说,JavaScript 的作用域是静态作用域,又叫词法作用域,这是因为作用域的嵌套关系可以在语法分析时确定,而不必等到运行时确定

 

 

 

场景二,定义一个函数,在不同的作用域中调用时this指代不同

当this使用在函数代码中事情就变得有趣多了。这种情况是最难的也会引发很多的问题。在函数代码中,this值的第一(可能也是最重要的)特性就是不能 静态的绑定到一个函数上。正如上面已经提到的,this值在进入上下文时就已经被决定了,在函数代码的情形下,每次this值可以是完全不一样的。

然而,在代码运行时,this值是不可改变的。例如,不能给this赋一个新值,因为this不是变量(相反,python编程语言中,可以显式的定义self对象,在运行的时候self对象可重复改变)

var foo={x:10};
var bar={
    x:20,
    test:function(){
        console.log(this===bar);//true
        console.log(this.x);//20
        //this=foo;//error,不能改变this值
    }
};
//当进入上下文时,this值由"bar"对象决定的。为什么这样-将在下面详细讨论
bar.test();//true,20
foo.test=bar.test;
//然而,此时在这里的this将指向"foo"-即使我们调用同一个函数
foo.test();//false,10

 

(当我们在一些关于javascript 的文章和书本中会看到“this值由函数如何定义来决定:如果是全局函数,this值被设置为全局对象,如果函数时一个对象的方法,this值设置为这个 对象”-这是一个错误的描述)。从下面我们可以看出即使是一般的全局函数,也能够被产生不同this值的调用表达式所触发。

function foo(){
    console.log(this);
}
foo();//打印this为Window
console.log(foo===foo.prototype.constructor);//true
//但是对于同一函数的另一种调用表达式形式,this值是不同的
foo.prototype.constructor();//打印this为foo

调用一个被定义为对象方法的函数,但是this值不会被设置为这个对象也是同样可能的:

var foo={
    bar:function(){
        console.log(this);
        console.log(this===foo);
    }
};
foo.bar();//foo,true
var exampleFunc=foo.bar;
console.log(exampleFunc===foo.bar);//true
//同一函数的另一种调用表达式形式,得到不同的this值
exampleFunc();//global,false

  

posted @ 2014-05-07 09:48  走走停停走走  Views(741)  Comments(0Edit  收藏  举报