this, call, apply 和 bind
這篇關於this
的文章,僅僅是自己認為比較重要且易混淆的知識點。
內容
1.含義:
在JavaScript
中,this
物件是指
當前函式
中正在執行的上下文環境,因此this
並非是定義時(箭頭函式除外)。
2.this
指向:
永遠指向最後呼叫它的物件。簡單記憶:A.B()
這裡的this
就指.
左邊的A
.
3.this
物件分類:
-
this
物件分類:- 全域性物件
- 當前物件
- 任意物件
判斷處於哪種this物件,這個取決於函式的呼叫方式。而JavaScript中的函式呼叫方式又分為四種:
-
JavaScript
中的函式呼叫方式:call 、apply 、bind
4. 具體內容:
4.1 函式呼叫
var a = 11; function foo() { var a = 22; console.log(this.a);//11 } foo(); console.log(this.a);//11 複製程式碼
函式呼叫:在
獨立呼叫
中,this
在非嚴格模式下指向全域性物件window
.在嚴格模式下this
是undefined
。在這裡,用var
宣告一個變數和給this
以及window
新增屬性是等價的。
var myname = "princess"; console.log(this.myname); //princess console.log(window.myname); //princess 複製程式碼
接著可能會有下面的疑惑:
var foo = 123;//foo 是變數 window.bar = 345;//bar 是屬性 delete foo; delete bar; console.log(this.foo,this.bar);//123,undefined為什麼不一樣呢? 複製程式碼
delelte刪除不了變數、刪除不了原型鏈中的變數、可以刪掉物件屬性!
還得注意以下一點:
被(…)();
這樣形式(IIFE(立即呼叫的函式表示式))
封裝的函式會立即被呼叫,也就是說等同於被獨立呼叫,因此它內部的this
是
全域性變數
,所以輸出的是全域性變數。
4.2 作為物件的方法呼叫
var b = 33; var o = { b: 44, f: function() { return this.b; } }; console.log(o.f());//44 複製程式碼
作為物件的方法呼叫:this
指向該物件(這裡即物件o
)。
但是當物件的方法被賦予給一個變數時,其相當於函式觸發,此時的this為 window (非嚴格模式下)或者 undefined(嚴格模式下)。
var b = 33; var o = { b: 44, f: function() { return this.b; } }; console.log(o.f());//44 var c = o.f;// this == window || undefined c();//33 複製程式碼
4.3 建構函式呼叫
-
new
方法建立物件的時候,會經過如下過程:this this this
注意關鍵字 new
function Person(name, age) { this.name = name; this.age = age; return { name: 'Mary' }; } var person1 = new Person('Jack'); console.log(person1.name);// 'Mary' console.log(person1.age);// undefined 複製程式碼
而下面的情況:
function Person(name, age) { this.name = name; this.age = age; return this; } var person1 = Person('Bob', 18); console.log(person1.name);// Bob console.log(window.name);// Bob console.log(person1 === window);// true 複製程式碼
建構函式呼叫:this
指向該例項物件。
4.4call 、apply 、bind
call
和apply
均可以改變this
指向,差別在於傳入引數的不同。
A.call(this,arg1,arg2...,argn)
A.apply(this,[arg1,arg2...,argn])
如果第一個引數為null
或者undefined
,那麼就非嚴格模式下預設為此時的this
為window
物件,嚴格模式下為undefined
.而bind
函式返回的是一個新的函式,即方法,不是立即執行函式,需要手動去呼叫bind()
.
使用 bind()方法建立的上下文,其為永久的上下文環境,不可修改,即使是使用 call 或者 apply方法,也無法修改 this 所指向的值。
5. 還有一種情況:
箭頭函式:此時會從
包裹
它的函式或作用域中獲取this
的值。
箭頭函式中的this
在
定義
它的時候已經決定了,與如何呼叫以及在哪裡呼叫它無關,包括(call, apply, bind)
等操作都無法改變它的this
。
var x=11; var obj={ x:22, y:this, say:()=>{ console.log(this.x); } } obj.say();//11 console.log(obj.y);//window 複製程式碼
這裡按照上述“定義”時決定this
指向,應該輸出22
,但是又可以看出obj
物件中的this
指代的是window
,也就是全域性環境,故箭頭函式中的this
就會就近找到上一個物件中this
所指代的物件。obj
內部屬性y
就為obj
內部this
指代的物件,輸出是window
.