this綁定方式和優先級比較

上篇文章介紹了this的隱式綁定(implicit binding),接着介紹this其餘三種綁定方式segmentfault

  1. 默認綁定 (Default Binding)app

  2. 顯式綁定 (Explicit Binding)ide

  3. new綁定(new Binding)函數

默認綁定 (Default Binding)

這個是最簡單的綁定,最經常使用的調用類型:獨立函數調用測試

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

var a = 2;

foo(); // 2

首先foo()在全局做用域中被調用,根據調用域(call-site),此時this綁定到了全局,因此結果很明顯。this

但在嚴格模式下,默認綁定不起做用prototype

function foo() {
    "use strict";

    console.log( this.a );
}

var a = 2;

foo(); // TypeError: `this` is `undefined`

顯式綁定 (Explicit Binding)

顯式綁定用到了call()和apply()方法,由於能夠直接指定this的綁定對象,所以稱之爲顯式綁定。code

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

var obj = {
    a: 2
};

foo.call( obj ); // 2

經過foo.call(),咱們能夠在調用foo時強制把它this綁定到obj上。對象

硬綁定(Hard Binding)

由於咱們強制把foo的this綁定到了obj,不管以後如何調用bar,以後的操做並不會覆蓋以前的,它總會在obj上調用foo。ci

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

var obj = {
    a: 2
};

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

bar(); // 2
setTimeout( bar, 100 ); // 2

// `bar` hard binds `foo`'s `this` to `obj`
// so that it cannot be overriden
bar.call( window ); // 2

硬綁定的應用場景就是建立一個包裹函數,負責接收參數並返回值:

function foo(something) {
    console.log( this.a, something );
    return this.a + something;
}

var obj = {
    a: 2
};

var bar = function() {
    return foo.apply( obj, arguments );
};

var b = bar( 3 ); // 2 3
console.log( b ); // 5

另外一種使用方法是建立一個能夠重複使用的輔助函數

function foo(something) {
    console.log( this.a, something );
    return this.a + something;
}

// simple `bind` helper
function bind(fn, obj) {
    return function() {
        return fn.apply( obj, arguments );
    };
}

var obj = {
    a: 2
};

var bar = bind( foo, obj );

var b = bar( 3 ); // 2 3
console.log( b ); // 5

因爲硬綁定是很是經常使用的,因此ES5提供了內置方法Function.prototype.bind()

function foo(something) {
    console.log( this.a, something );
    return this.a + something;
}

var obj = {
    a: 2
};

var bar = foo.bind( obj );

var b = bar( 3 ); // 2 3
console.log( b ); // 5

new Binding

使用new來調用foo()時,咱們會構造一個新對象並把它綁定到foo()調用中的this上。

function foo(n) {
    this.studentNum = n;
    this.name = 'cnio'
}
  
var bar =  new foo(1)

console.log(bar) // foo {studentNum: 1, name: "cnio"}

若是foo原型鏈上也有內容,好比添加

foo.prototype.getName = function() {
    return this.name;
}

在控制檯打印出的proto中,就有getName屬性。
使用new關鍵字時,會發生以下幾個步驟

  1. 建立一個全新的對象。

  2. 這個新對象會被執行[[Prototype]]鏈接。

  3. 這個新對象會綁定到函數調用的this。

  4. 若是函數沒有返回其餘對象,那麼new表達式中的函數調用會自動返回這個新對象。

優先級比較

前面已經瞭解了this綁定的四條規則,可是這幾種某次應用了多條該怎麼辦?因此須要測試一下優先級,也就是誰的權利更大些,就聽誰的,不然小弟this將不知所措了。

隱式綁定 VS 顯式綁定

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

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

var obj2 = {
    a: 3,
    foo: foo
};

obj1.foo(); // 2
obj2.foo(); // 3

obj1.foo.call( obj2 ); // 3
obj2.foo.call( obj1 ); // 2

當咱們使用call(obj2)顯式綁定時,輸出的值爲obj2的值(a=3),因此顯式綁定的優先級更高。

new綁定 VS 隱式綁定

function foo(something) {
    this.a = something;
}

var obj1 = {
    foo: foo
};

var obj2 = {};

obj1.foo( 2 );
console.log( obj1.a ); // 2

obj1.foo.call( obj2, 3 );
console.log( obj2.a ); // 3

var bar = new obj1.foo( 4 );
console.log( obj1.a ); // 2
console.log( bar.a ); // 4

能夠看到,new綁定的優先級>隱式綁定
那麼new綁定的優先級與顯式綁定優先級呢?由於new和apply/call沒法一塊兒使用,但硬綁定也是顯式綁定的一種,能夠替換測試

function foo(something) {
    this.a = something;
}

var obj1 = {};

var bar = foo.bind( obj1 );
bar( 2 );
console.log( obj1.a ); // 2

var baz = new bar( 3 );
console.log( obj1.a ); // 2
console.log( baz.a ); // 3

new修改了硬綁定調用bar()中的this,代碼感受沒法修改this綁定,可是又的確修改了this綁定,這個很特殊,理論上咱們能夠認爲new綁定優先級>顯式綁定

綜上,優先級比較以下

new綁定 > 顯式綁定 > 隱式綁定
相關文章
相關標籤/搜索