View on GitHub

Cycle263 Blog

Stay hungry, stay foolish.

this对象

this对象根据函数如何被执行而动态绑定的,不是编写时绑定,而是运行时绑定,谁调用绑定谁。如果有new关键字,this指向new出来的那个实例对象。和this密切相关的是对象原型属性,它是一种属性的向上追溯。

当一个函数被调用时,会建立一个称为执行环境的活动记录。这个记录包含函数是从何处(调用栈 —— call-stack)被调用的,函数是 如何 被调用的,被传递了什么参数等信息。这个记录的属性之一,就是在函数执行期间将被使用的 this 引用。

this 机制设计的目的,是为了提供更优雅的方式来隐含地“传递”一个对象引用,从而有更加干净的API设计和更容易的复用。

独立函数调用,默认绑定this,这种 this 规则是在没有其他规则适用时的默认规则。

function func() { console.log(this); }      // window object
func();

调用点是否有一个环境对象(context object),当一个方法引用存在一个环境对象时,隐含绑定规则会说:是这个对象应当被用于这个函数调用的 this 绑定,并且只有对象属性引用链的最后一层是影响调用点的。

function foo() {
    console.log( this.a );
}
var obj2 = {
    a: 42,
    foo: foo
};
var obj1 = {
    a: 2,
    obj2: obj2
};
obj1.obj2.foo(); // 42

var student = {
    func: function() {
        console.log(this);
    };
};

student.func(); // student object
var studentFunc = student.func;
studentFunc();  // window,相当于window.studentFunc()

当一个隐含绑定丢失了它的绑定,这通常意味着它会退回到默认绑定, 根据 strict mode 的状态,其结果不是全局对象就是 undefined。参数传递仅仅是一种隐含的赋值,而且因为我们在传递一个函数,它是一个隐含的引用赋值,最终隐含会丢失。

function foo() {
    console.log( this.a );
}
var obj = {
    a: 2,
    foo: foo
};
var bar = obj.foo; // 函数引用!
var a = "oops, global"; // `a` 也是一个全局对象的属性
bar(); // "oops, global"

function foo() {
    console.log( this.a );
}
var obj = {
    a: 2,
    foo: foo
};
var a = "oops, global"; // `a` 也是一个全局对象的属性
setTimeout( obj.foo, 100 ); // "oops, global"

函数拥有 call(..) 和 apply(..) 方法,它们接收的第一个参数都是一个用于指定 this 的对象。如果你传递一个简单基本类型值(string,boolean,或 number 类型)作为 this 绑定,那么这个基本类型值会被包装在它的对象类型中(分别是 new String(..),new Boolean(..),或 new Number(..))。这通常称为“封箱(boxing)”。

JavaScript 拥有 new 操作符,当在函数前面被加入 new 调用时,也就是构造器调用时,下面这些事情会自动完成:

如果你想调查this 绑定,可以使用开发者工具取得调用栈,之后从上向下找到第二个记录,那就是你真正的调用点。

判断this