關於this繫結的四種方式
一、前言
我們每天都在書寫著有關於this的javascript程式碼,似懂非懂地在用著。前陣子在看了《你不知道的JavaScript上卷》之後,也算是被掃盲了一邊關於this繫結的四種方式。
二、繫結規則
關於this應用的是哪條規則,得先找到呼叫的位置,再判斷應用了哪條規則。
1、預設繫結
先上程式碼:
var a = 2; function foo() { console.log(this.a); } foo(); // 結果:2
先來分析下上面的程式碼宣告,
首先我們在全域性作用域中定義了一個變數a,而在全域性作用域宣告的變數,就相當於為window物件聲明瞭同名屬性a並賦值為2,接著又在全域性作用域下聲明瞭foo函式,最後我們在呼叫foo函式時,是直接不帶任何修飾下呼叫foo函式,此時的this的繫結規則為預設繫結
如果此時使用了嚴格模式,即在程式碼中加了"use strict",this指向undefined,呼叫的結果就會出錯而不是輸出2。
2、隱式繫結
var a = 2; function foo() { console.log(this.a); } var obj = { a: 4, foo:foo }; foo(); // 結果:2 obj.foo(); // 結果4
程式碼還是差不多的程式碼,只是加了一個obj物件,物件有一個a屬性和一個foo屬性引用了foo函式。對於foo();輸出結果2,在上一節已經說明,因為是沒用帶任何修飾的情況下呼叫,應用了預設繫結。而在obj.foo()的呼叫中,foo函式的呼叫上下文是obj物件,obj包含了foo函式,此時this的繫結就發生了隱式繫結
對於這種方式,我在程式碼中也經常用到。把可以歸類的方法、變數都寫成一個物件的形式,就形成了一個模組,也相當於一種設計模式,模組模式。
3、顯示繫結
var a = 2; function foo() { console.log(this.a); } var obj = { a: 4 }; foo.call(obj); // 結果:4 foo.apply(obj); // 結果:4 foo.bind(obj)(); // 結果:4
對於call、apply、bind的這三種呼叫方式都是屬於顯示繫結
call和apply兩個都是顯示改變上下文並執行,唯一不同的就是傳參方式,call是物件後面可以跟著多個引數,而apply傳遞引數,需要傳遞一個數組,即:
foo.call(obj, arg1, arg2, arg3, ...);
foo.apply(obj, [arg1, arg2, arg3, ...])
4、new繫結
學過後端語言的人都知道,通過建構函式,可以new一個物件例項,而在JavaScript中,物件也是通過new建構函式生成的,但,卻和麵向物件語言的new方式是不一樣。下面來看看new操作符到底做了什麼。
當使用new來呼叫函式時,發生了以下步驟:
a、建立了一個全新的物件,如:var obj = {};
b、連線全新物件與呼叫函式之間的[[Prototype]],讓函式的prototype指向全新物件,如obj.__proto__ = foo.prototype;
c、新物件會繫結到函式呼叫的this,如:foo.call(obj);
d、返回物件。如果函式沒有返回其他物件,那麼new操作會自動返回這個新物件。
三、優先順序
一般情況下:new繫結 > 顯示繫結 > 隱式繫結 > 預設繫結
四、總結
還有其他的一些細節知識點,推薦還是看《你不知道的JavaScript上卷》這本書,真心不錯。