前端百題斬——js中的這些“this”指向都值得了解
14.1 簡介
this是javascript中的一個關鍵字,其使用方法類似于一個變量,是執(zhí)行上下文中一個重要組成部分。其作用是可以在函數(shù)體內部獲取當前的運行環(huán)境。
14.2 指向
每個函數(shù)的this是在調用的時候基于函數(shù)的執(zhí)行環(huán)境綁定的,this的指向完全取決于函數(shù)的調用位置。(下面均是在瀏覽器環(huán)境下進行測試的結果)
在全局環(huán)境下,this 始終指向全局對象(window), 無論是否嚴格模式;
- console.log(this); // window
 
普通函數(shù)內部的this分兩種情況,嚴格模式和非嚴格模式。
(1)非嚴格模式下,this 默認指向全局對象window
(2)嚴格模式下, this為undefined
- function fun() {
 - console.log(this); // window
 - }
 
對象內部方法的this指向調用這些方法的對象
(1)函數(shù)的定義位置不影響其this指向,this指向只和調用函數(shù)的對象有關;
(2)多層嵌套的對象,內部方法的this指向離被調用函數(shù)最近的對象(window也是對象,其內部對象調用方法的this指向內部對象, 而非window)。
- const obj = {
 - a: 10,
 - b: 20,
 - add: function () {
 - return this.a + this.b;
 - }
 - };
 - console.log(obj.add()); // 30
 - const add = obj.add;
 - console.log(add()); // NaN
 
原型鏈中的方法的this仍然指向調用它的對象
- const obj = {
 - a: 10,
 - b: 20
 - };
 - const prototypeObj = {
 - add: function () {
 - return this.a + this.b;
 - }
 - };
 - Object.setPrototypeOf(obj, prototypeObj);
 - console.log(obj.add()); // 30
 
當函數(shù)通過Function對象的原型中繼承的方法 call() 和 apply() 方法調用時, 其函數(shù)內部的this值可綁定到 call() & apply() 方法指定的第一個對象上, 如果第一個參數(shù)不是對象,JavaScript內部會嘗試將其轉換成對象然后指向它。(見后續(xù)代碼)
通過bind方法綁定后, 函數(shù)將被永遠綁定在其第一個參數(shù)對象上, 而無論其在什么情況下被調用。(見后續(xù)代碼)
當函數(shù)被當做監(jiān)聽事件處理函數(shù)時, 其 this 指向觸發(fā)該事件的元素(針對于addEventListener事件)
- <button id="testId">按鈕</button>
 - const btn = document.getElementById('testId');
 - btn.addEventListener('click', function() {
 - console.log(this); // <button id="testId">按鈕</button>
 - });
 
內聯(lián)事件中的this指向分兩種情況:
(1)當代碼被內聯(lián)處理函數(shù)調用時,它的this指向監(jiān)聽器所在的DOM元素
- <button onclick="console.log(this)">按鈕</button> // 輸出該DOM節(jié)點
 
(2)當代碼被包括在函數(shù)內部執(zhí)行時,其this指向等同于 函數(shù)直接調用的情況,即在非嚴格模式指向全局對象window, 在嚴格模式指向undefined
- <button onclick="clickFun()">按鈕</button>
 - function clickFun() {
 - console.log(this); // window
 - }
 
對于延時函數(shù)內部的回調函數(shù)的this指向全局對象window(當然可以通過bind方法改變其內部函數(shù)的this指向)
- function Fun() {
 - this.a = 10;
 - this.method = function() {
 - setTimeout(function() {
 - console.log(this); // window
 - }, 1000);
 - }
 - }
 - const fun = new Fun();
 - fun.method();
 
由于箭頭函數(shù)不綁定this, 它會捕獲其所在(即定義的位置)上下文的this值, 作為自己的this值,所以 call() / apply() / bind() 方法對于箭頭函數(shù)來說只是傳入?yún)?shù),對它的 this 毫無影響。
- function Fun() {
 - this.a = 10;
 - this.method = function() {
 - setTimeout(() => {
 - console.log(this); // Fun {a: 10, method: ƒ}
 - }, 1000);
 - }
 - }
 - const fun = new Fun();
 - fun.method();
 
14.3 改變this指向
除了隱式綁定this的方式,還能夠通過顯示綁定的方式,通過call、apply、bind方式改變this指向,對于這三者的區(qū)別后續(xù)將有專門的百題斬去闡述,本節(jié)主要進行一波簡單使用。
call()
call() 方法使用一個指定的 this 值和單獨給出的一個或多個參數(shù)來調用一個函數(shù)。
- function method(val1, val2) {
 - return this.a + this.b + val1 + val2;
 - }
 - const obj = {
 - a: 1,
 - b: 2
 - };
 - console.log(method.call(obj, 3, 4)); // 10
 
apply()
apply() 方法調用一個具有給定this值的函數(shù),以及以一個數(shù)組(或類數(shù)組對象)的形式提供的參數(shù)。
- function method(val1, val2) {
 - return this.a + this.b + val1 + val2;
 - }
 - const obj = {
 - a: 1,
 - b: 2
 - };
 - console.log(method.apply(obj, [3, 4])); // 10
 
bind()
bind() 方法創(chuàng)建一個新的函數(shù),在 bind() 被調用時,這個新函數(shù)的 this 被指定為 bind() 的第一個參數(shù),而其余參數(shù)將作為新函數(shù)的參數(shù),供調用時使用。
- function method(val1, val2) {
 - return this.a + this.b + val1 + val2;
 - }
 - const obj = {
 - a: 1,
 - b: 2
 - };
 - const bindMethod = method.bind(obj, 3, 4);
 - console.log(bindMethod); // [Function: bound method]
 - console.log(bindMethod()); // 10
 
擴展
- call() 和 apply()的區(qū)別是call()方法接受的是參數(shù)列表,而apply()方法接受的是一個參數(shù)數(shù)組;
 - bind返回的是一個綁定函數(shù),而call和apply返回的是運行結果;
 - 多次 bind() 是無效的,只會綁定到第一次調用的對象上;
 - call() / apply() / bind() 方法對于箭頭函數(shù)來說只是傳入?yún)?shù),對它的 this 毫無影響。
 
本文轉載自微信公眾號「執(zhí)鳶者」,可以通過以下二維碼關注。轉載本文請聯(lián)系執(zhí)鳶者公眾號。

















 
 
 


 
 
 
 