this全面解析(二)

上篇文章this全面解析(一)中,咱们说了几个常见的错误认识。javascript

接下来,咱们来看看this究竟是一种什么样的机制java

this是运行时绑定,并非在编译时,上下文取决于函数调用时的各类条件。this绑定和函数的声明位置没有任何关系,只取决于函数的调用方式。编程

调用位置

调用位置是函数在代码中被调用的位置(不是声明的位置)。函数

通常来讲,寻找调用位置就是找“函数被调用的位置”,但这并不一直是一件简单事,有些时候,编程模式会隐藏真正的调用位置。oop

不过咱们仍是有办法的!咱们能够经过分析调用栈(为了达到当前执行位置所调用的全部函数),那么咱们关心的,就是当前执行函数的前一个调用中。post

function baz() {
    //当前调用栈:baz
    //调用位置是全局做用域
    console.log('baz');
    bar(); //bar 的调用位置
}

function bar() {
    //当前调用栈 baz--> bar
    //所以当前调用位置在 baz 中
    console.log('bar');
    foo(); // foo的调用位置
}

function foo() {
    //当前调用栈 baz-> bar ->foo
    //当前调用位置在 bar 中
    console.log('foo');
}

baz(); //baz调用位置
复制代码

其实,函数的调用栈也能够被想象成一个函数调用链~ui

绑定规则

默认绑定

独立函数调用(没法应用其余规则时,默认规则就是它了!)this

看这段代码spa

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

var a = 1;

foo(); //2
复制代码

首先,咱们须要明白一个知识点:声明在全局做用域中的变量就是全局对象的一个同名属性,本质是一个东西,不是复制获得的code

当咱们调用foo,this.a 被解析成 全局变量a ,调用函数应用了this的默认绑定,this指向全局对象。

不过这里有一点

虽然this的绑定规则彻底取决于调用位置,可是只有 foo() 运行在 非严格模式下,默认绑定才会绑定到全局,严格模式下,与foo()的调用位置无关。

隐式绑定

考虑调用位置,是否有上下文对象。

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

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

obj.foo(); //2
复制代码

咱们先来看 foo() 的声明方式,不管是直接在obj中定义仍是先定义,再添加为引用属性,这个函数严格来讲都不属于obj对象。

可是,调用位置会使用obj上下文来引用函数,因此,你能够说,调用obj对象时,拥有或者包含它。调用foo()时,this被绑定到obj。this.a 和 obj.a 是同样的。

对象属性引用链中,只有最后一层影响调用位置

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

var obj2 = {
    a: 42,
    foo: foo
}

var obj1 = {
    a: 2,
    obj2: obj2
}

obj1.obj2.foo(); //42
复制代码

隐式丢失

function foo() { 
    console.log( this.a );
}
var obj = { 
    a: 2,
    foo: foo 
    
};
var bar = obj.foo; // 函数别名!
var a = "oops, global"; // a 是全局对象的属性 bar(); // "oops, global"
复制代码

虽然,bar是obj.foo的一个引用,实际上,引用的是foo函数自己!因此此时 bar() 是一个不带任何修饰的函数调用。

传入回调函数

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

function doFoo(fn) {
    fn(); //调用位置
}

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

var a = "global";
doFoo( obj.foo ); //global
复制代码

参数传递其实就是一种隐式赋值,所以咱们传入函数时也会被隐式赋值,因此结果和上一 个例子同样。

下篇文章将介绍:显式绑定和new绑定两种方式。

相关文章
相关标签/搜索