You Don't Know JS: this & Object Prototypes( 第2章 this)

Posted Mr-chen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了You Don't Know JS: this & Object Prototypes( 第2章 this)相关的知识,希望对你有一定的参考价值。

this is a binding made for each function invocation, based entirely on its call-site (how the function is called).

this是为函数被引用而创建的绑定!完全地基于函数如何被调用/函数的call-site!

 


 

 

Call-site

:the location in code where a function is called 

 

call-stack: 调用函数的堆栈。(函数的调用链条,函数的call-site的移动形成了stack。)

The call-site  is in the invocation before the currently executing function.

function baz() {
    // call-stack is: `baz`
    // so, our call-site is in the global scope

    console.log( "baz" );
    bar(); // <-- 下一个调用位置是‘bar‘
}

function bar() {
    // call-stack is: `baz` -> `bar`
    // so, 我们的call-site是在‘baz‘内。

    console.log( "bar" );
    foo(); // <-- call-site for `foo`
}

function foo() {
    // call-stack is: `baz` -> `bar` -> `foo`
    // so, our call-site is in `bar`

    console.log( "foo" );
}

baz(); // <-- call-site for `baz`

 

在浏览器inspector中,可以使用debugger工具观察call-site。

function baz() {
    console.log(this);
    console.log( "baz" );
    bar(); // <-- call-site for `bar`
}

function bar() {
    console.log(this)
    console.log( "bar" );
    foo(); // <-- call-site for `foo`
}

function foo() {
    console.log(this);
    console.log( "foo" );
}

baz();
最后的结果是3个this都指向window对象。

 

 


 

 

Nothing But Rules

在函数执行期间,call-site如何决定this指向哪里?

有:4条法则!及这4条法则的优先级。

 

default Binding

第一条法则来自最常用的函数调用: 独立的函数引用。(没有其他法则影响的函数)

function foo() {
    console.log( this.a );
}

var a = 2;

foo(); // 2

this指向全局对象,变量a是全局对象的属性。

如果是严格模式,this指向undefined!

 

第一条:this绑定完全基于call-site,非严格模式下,全局对象是默认的绑定对象。

注意:不要混用严格模式和非严格模式!

 

Implicit Binding

第2条:如果call-site有一个context对象,也涉及一个拥有或包含的对象。

function foo() {
    console.log( this.a );
}

var obj = {
    a: 2,
    foo: foo
};

obj.foo(); // 2   因为obj就foo()调用的this, 所以this.a等同于obj.a

当有一个content object 拥有一个函数引用时,
Implicit Binding Rule 就是那个对象应当拥有这个函数调用的this绑定

 

??:Only the top/last level of an object property reference chain matters to the call-site.

也就是说假如有:  obj1.obj2.obj3.foo(), 调用foo()函数的this绑定在obj3上。

 

Implicitly Lost

当一个Implicit bound 函数丢弃了context对象的binding, 就会使用默认binding。或用全局对象,或undefined(use strict)。

function foo() {
    console.log( this.a );
}

var obj = {
    a: 2,
    foo: foo
};

var bar = obj.foo; // function reference/alias!

var a = "oops, global"; // `a` also property on global object

bar(); // "oops, global"
 
obj.foo 
结果是: ? foo() { console.log(
this.a ); }
bar      //变量bar的值就是函数foo, 因为bar被分配了obj.foo
结果是 ? foo() { console.log(
this.a ); }


所以: this指向全局对象window, this.a就是 window.a

 

 

另一个例子:参数传递

其实就是把obj.foo的值,分配给fn参数。等同于在doFoo函数内,声明了变量:var fn = obj.foo;

function foo() {
    console.log( this.a );
}

function doFoo(fn) {
    // `fn` is just another reference to `foo`

    fn(); // <-- call-site!
}

var obj = {
    a: 2,
    foo: foo
};

var a = "oops, global"; // `a` also property on global object

doFoo( obj.foo ); // "oops, global"

看到了吧: 结果this绑定的是全局对象。this.a就是window.a

 

 

javascript内建函数也同样:

function foo() {
    console.log( this.a );
}

var obj = {
    a: 2,
    foo: foo
};

var a = "oops, global"; // `a` also property on global object

setTimeout( obj.foo, 100 ); // "oops, global"

setTimeout()函数相当于:

function MySetTimeout(fn) {
    //0.1秒后;
    fn();
}

MySetTimeout( obj.foo )

 

函数回调丢失它们的this绑定是很常见的。

 

还有一类方式,是主动改变this:

Event handlers就会强制你的回调有一个this指向DOM中被激活的元素。

 

如果有一种方法可以固定住this,就好了!当然有了,见??,明确的绑定!

 

Explicit Binding

call()方法,apply()方法。第一个参数是一个对象的话,这个对象就绑定了this。

function foo() {
    console.log( this.a );
}

var obj = {
    a: 2
};

foo.call( obj ); // 2

 

??,call(..),apply(..)可接受多个参数,它们的用途这里不谈!

 

不幸的是,明确绑定,不能解决一个函数丢失它想要的this绑定的问题。

 

Hard Binding(explict and strong)

var bar = function() {
	foo.call( obj );
};

 

 

API Call "Contexts"

 

new Binding

 


 

 

Everything In Order

 

Determining this

 


 

 

 

Binding Exceptions

 

Ignored this

 

Safer this

 

Indirection

 

Softening Binding

 


 

 

Lexical this

 

 


 

 

Review (TL;DR)

4条rule

小心:

箭头函数

 
















以上是关于You Don't Know JS: this & Object Prototypes( 第2章 this)的主要内容,如果未能解决你的问题,请参考以下文章

You Don't Know JS: this & Object Prototypes( 第2章 this)

You Don't Know JS: Scope & Closures (第4章: Hoisting)

You Don't Know JS: Scope & Closures (附加:Lexical/dynamic作用域)

You Don't Know JS: Scope & Closures (第3章: 函数 vs 块作用域)

You Don't Know JS: this & Object Prototypes( 第一章 this or That?)

(未完成👃)You Don't Know JS: Scope & Closures (第5章: Scope & Closures)