JavaScript中this指向有什么用-創(chuàng)新互聯(lián)

這篇文章給大家分享的是有關(guān)JavaScript中this指向有什么用的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。

創(chuàng)新互聯(lián)建站憑借專業(yè)的設(shè)計(jì)團(tuán)隊(duì)扎實(shí)的技術(shù)支持、優(yōu)質(zhì)高效的服務(wù)意識(shí)和豐厚的資源優(yōu)勢(shì),提供專業(yè)的網(wǎng)站策劃、網(wǎng)站設(shè)計(jì)制作、成都做網(wǎng)站、網(wǎng)站優(yōu)化、軟件開發(fā)、網(wǎng)站改版等服務(wù),在成都十余年的網(wǎng)站建設(shè)設(shè)計(jì)經(jīng)驗(yàn),為成都上千余家中小型企業(yè)策劃設(shè)計(jì)了網(wǎng)站。

JavaScript 中的 this 指向問(wèn)題有很多文章在解釋,仍然有很多人問(wèn)。上周我們的開發(fā)團(tuán)隊(duì)連續(xù)兩個(gè)人遇到相關(guān)問(wèn)題,所以我不得不將關(guān)于前端構(gòu)建技術(shù)的交流會(huì)延長(zhǎng)了半個(gè)時(shí)候討論 this 的問(wèn)題。

與我們常見的很多語(yǔ)言不同,JavaScript 函數(shù)中的 this 指向并不是在函數(shù)定義的時(shí)候確定的,而是在調(diào)用的時(shí)候確定的。換句話說(shuō), 函數(shù)的調(diào)用方式?jīng)Q定了 this 指向 。

JavaScript 中,普通的函數(shù)調(diào)用方式有三種:直接調(diào)用、方法調(diào)用和 new 調(diào)用。除此之外,還有一些特殊的調(diào)用方式,比如通過(guò) bind() 將函數(shù)綁定到對(duì)象之后再進(jìn)行調(diào)用、通過(guò) call() 、 apply() 進(jìn)行調(diào)用等。而 es6 引入了箭頭函數(shù)之后,箭頭函數(shù)調(diào)用時(shí),其 this 指向又有所不同。下面就來(lái)分析這些情況下的 this 指向。

直接調(diào)用

直接調(diào)用,就是通過(guò) 函數(shù)名(...) 這種方式調(diào)用。這時(shí)候,函數(shù)內(nèi)部的 this 指向全局對(duì)象,在瀏覽器中全局對(duì)象是 window ,在 NodeJs 中全局對(duì)象是 global 。

來(lái)看一個(gè)例子:

// 簡(jiǎn)單兼容瀏覽器和 NodeJs 的全局對(duì)象
const _global = typeof window === "undefined" ? global : window;
function test() {
  console.log(this === _global);  // true
}
test();  // 直接調(diào)用

這里需要注意的一點(diǎn)是,直接調(diào)用并不是指在全局作用域下進(jìn)行調(diào)用,在任何作用域下,直接通過(guò) 函數(shù)名(...) 來(lái)對(duì)函數(shù)進(jìn)行調(diào)用的方式,都稱為直接調(diào)用。比如下面這個(gè)例子也是直接調(diào)用

(function(_global) {
  // 通過(guò) IIFE 限定作用域
  function test() {
    console.log(this === _global); // true
  }
  test();   // 非全局作用域下的直接調(diào)用
})(typeof window === "undefined" ? global : window);

bind() 對(duì)直接調(diào)用的影響

還有一點(diǎn)需要注意的是 bind() 的影響。 Function.prototype.bind() 的作用是將當(dāng)前函數(shù)與指定的對(duì)象綁定,并返回一個(gè)新函數(shù),這個(gè)新函數(shù)無(wú)論以什么樣的方式調(diào)用,其 this 始終指向綁定的對(duì)象。還是來(lái)看例子:

const obj = {};
function test() {
  console.log(this === obj);
}
const testObj = test.bind(obj);
test();   // false
testObj(); // true

那么 bind() 干了啥?不妨模擬一個(gè) bind() 來(lái)了解它是如何做到對(duì) this 產(chǎn)生影響的。

const obj = {};
function test() {
  console.log(this === obj);
}
// 自定義的函數(shù),模擬 bind() 對(duì) this 的影響
function myBind(func, target) {
  return function() {
    return func.apply(target, arguments);
  };
}
const testObj = myBind(test, obj);
test();   // false
testObj(); // true

從上面的示例可以看到,首先,通過(guò)閉包,保持了 target ,即綁定的對(duì)象;然后在調(diào)用函數(shù)的時(shí)候,對(duì)原函數(shù)使用了 apply 方法來(lái)指定函數(shù)的 this 。當(dāng)然原生的 bind() 實(shí)現(xiàn)可能會(huì)不同,而且更高效。但這個(gè)示例說(shuō)明了 bind() 的可行性。

call 和 apply 對(duì) this 的影響

上面的示例中用到了 Function.prototype.apply() ,與之類似的還有 Function.prototype.call() 。這兩方法的用法請(qǐng)大家自己通過(guò)鏈接去看文檔。不過(guò),它們的第一個(gè)參數(shù)都是指定函數(shù)運(yùn)行時(shí)其中的 this 指向。

不過(guò)使用 apply 和 call 的時(shí)候仍然需要注意,如果目錄函數(shù)本身是一個(gè)綁定了 this 對(duì)象的函數(shù),那 apply 和 call 不會(huì)像預(yù)期那樣執(zhí)行,比如

const obj = {};
function test() {
  console.log(this === obj);
}
// 綁定到一個(gè)新對(duì)象,而不是 obj
const testObj = test.bind({});
test.apply(obj);  // true
// 期望 this 是 obj,即輸出 true
// 但是因?yàn)?nbsp;testObj 綁定了不是 obj 的對(duì)象,所以會(huì)輸出 false
testObj.apply(obj); // false

由此可見, bind() 對(duì)函數(shù)的影響是深遠(yuǎn)的,慎用!

方法調(diào)用

方法調(diào)用是指通過(guò)對(duì)象來(lái)調(diào)用其方法函數(shù),它是 對(duì)象.方法函數(shù)(...) 這樣的調(diào)用形式。這種情況下,函數(shù)中的 this 指向調(diào)用該方法的對(duì)象。但是,同樣需要注意 bind() 的影響。

const obj = {
  // 第一種方式,定義對(duì)象的時(shí)候定義其方法
  test() {
    console.log(this === obj);
  }
};
// 第二種方式,對(duì)象定義好之后為其附加一個(gè)方法(函數(shù)表達(dá)式)
obj.test2 = function() {
  console.log(this === obj);
};
// 第三種方式和第二種方式原理相同
// 是對(duì)象定義好之后為其附加一個(gè)方法(函數(shù)定義)
function t() {
  console.log(this === obj);
}
obj.test3 = t;
// 這也是為對(duì)象附加一個(gè)方法函數(shù)
// 但是這個(gè)函數(shù)綁定了一個(gè)不是 obj 的其它對(duì)象
obj.test4 = (function() {
  console.log(this === obj);
}).bind({});
obj.test();   // true
obj.test2();  // true
obj.test3();  // true
// 受 bind() 影響,test4 中的 this 指向不是 obj
obj.test4();  // false

這里需要注意的是,后三種方式都是預(yù)定定義函數(shù),再將其附加給 obj 對(duì)象作為其方法。再次強(qiáng)調(diào),函數(shù)內(nèi)部的 this 指向與定義無(wú)關(guān),受調(diào)用方式的影響。

方法中 this 指向全局對(duì)象的情況

注意這里說(shuō)的是 方法 中而不是 方法調(diào)用 中。方法中的 this 指向全局對(duì)象,如果不是因?yàn)?bind() ,那就一定是因?yàn)椴皇怯玫姆椒ㄕ{(diào)用方式,比如

const obj = {
  test() {
    console.log(this === obj);
  }
};
const t = obj.test;
t();  // false

t 就是 obj 的 test 方法,但是 t() 調(diào)用時(shí),其中的 this 指向了全局。

之所以要特別提出這種情況,主要是因?yàn)槌3⒁粋€(gè)對(duì)象方法作為回調(diào)傳遞給某個(gè)函數(shù)之后,卻發(fā)現(xiàn)運(yùn)行結(jié)果與預(yù)期不符——因?yàn)楹雎粤苏{(diào)用方式對(duì) this 的影響。比如下面的例子是在頁(yè)面中對(duì)某些事情進(jìn)行封裝之后特別容易遇到的問(wèn)題:

class Handlers {
  // 這里 $button 假設(shè)是一個(gè)指向某個(gè)按鈕的 jQuery 對(duì)象
  constructor(data, $button) {
    this.data = data;
    $button.on("click", this.onButtonClick);
  }
  onButtonClick(e) {
    console.log(this.data);
  }
}
const handlers = new Handlers("string data", $("#someButton"));
// 對(duì) #someButton 進(jìn)行點(diǎn)擊操作之后
// 輸出 undefined
// 但預(yù)期是輸出 string data
很顯然 this.onButtonClick 作為一個(gè)參數(shù)傳入 on() 之后,事件觸發(fā)時(shí),是對(duì)這個(gè)函數(shù)進(jìn)行的直接調(diào)用,而不是方法調(diào)用,所以其中的 this 會(huì)指向全局對(duì)象。要解決這個(gè)問(wèn)題有很多種方法
// 這是在 es5 中的解決辦法之一
var _this = this;
$button.on("click", function() {
  _this.onButtonClick();
});
// 也可以通過(guò) bind() 來(lái)解決
$button.on("click", this.onButtonClick.bind(this));
// es6 中可以通過(guò)箭頭函數(shù)來(lái)處理,在 jQuery 中慎用
$button.on("click", e => this.onButtonClick(e));

不過(guò)請(qǐng)注意,將箭頭函數(shù)用作 jQuery 的回調(diào)時(shí)造成要小心函數(shù)內(nèi)對(duì) this 的使用。jQuery 大多數(shù)回調(diào)函數(shù)(非箭頭函數(shù))中的 this 都是表示調(diào)用目標(biāo),所以可以寫 $(this).text() 這樣的語(yǔ)句,但 jQuery 無(wú)法改變箭頭函數(shù)的 this 指向,同樣的語(yǔ)句語(yǔ)義完全不同。

new 調(diào)用

在 es6 之前,每一個(gè)函數(shù)都可以當(dāng)作是構(gòu)造函數(shù),通過(guò) new 調(diào)用來(lái)產(chǎn)生新的對(duì)象(函數(shù)內(nèi)無(wú)特定返回值的情況下)。而 es6 改變了這種狀態(tài),雖然 class 定義的類用 typeof 運(yùn)算符得到的仍然是 "function" ,但它不能像普通函數(shù)一樣直接調(diào)用;同時(shí), class 中定義的方法函數(shù),也不能當(dāng)作構(gòu)造函數(shù)用 new 來(lái)調(diào)用。

而在 es5 中,用 new 調(diào)用一個(gè)構(gòu)造函數(shù),會(huì)創(chuàng)建一個(gè)新對(duì)象,而其中的 this 就指向這個(gè)新對(duì)象。這沒有什么懸念,因?yàn)?new 本身就是設(shè)計(jì)來(lái)創(chuàng)建新對(duì)象的。

var data = "Hi";  // 全局變量
function AClass(data) {
  this.data = data;
}
var a = new AClass("Hello World");
console.log(a.data);  // Hello World
console.log(data);   // Hi
var b = new AClass("Hello World");
console.log(a === b);  // false

箭頭函數(shù)中的 this

先來(lái)看看 MDN 上對(duì)箭頭函數(shù)的說(shuō)明

An arrow function expression has a shorter syntax than a function expression and does not bind its own this , arguments , super , or new.target . Arrow functions are always anonymous. These function expressions are best suited for non-method functions, and they cannot be used as constructors.

這里已經(jīng)清楚了說(shuō)明了,箭頭函數(shù)沒有自己的 this 綁定。箭頭函數(shù)中使用的 this ,其實(shí)是直接包含它的那個(gè)函數(shù)或函數(shù)表達(dá)式中的 this 。比如

const obj = {
  test() {
    const arrow = () => {
      // 這里的 this 是 test() 中的 this,
      // 由 test() 的調(diào)用方式?jīng)Q定
      console.log(this === obj);
    };
    arrow();
  },
  getArrow() {
    return () => {
      // 這里的 this 是 getArrow() 中的 this,
      // 由 getArrow() 的調(diào)用方式?jīng)Q定
      console.log(this === obj);
    };
  }
};
obj.test();   // true
const arrow = obj.getArrow();
arrow();    // true

示例中的兩個(gè) this 都是由箭頭函數(shù)的直接外層函數(shù)(方法)決定的,而方法函數(shù)中的 this 是由其調(diào)用方式?jīng)Q定的。上例的調(diào)用方式都是方法調(diào)用,所以 this 都指向方法調(diào)用的對(duì)象,即 obj 。

箭頭函數(shù)讓大家在使用閉包的時(shí)候不需要太糾結(jié) this ,不需要通過(guò)像 _this 這樣的局部變量來(lái)臨時(shí)引用 this 給閉包函數(shù)使用。來(lái)看一段 Babel 對(duì)箭頭函數(shù)的轉(zhuǎn)譯可能能加深理解:

// ES6
const obj = {
  getArrow() {
    return () => {
      console.log(this === obj);
    };
  }
}
// ES5,由 Babel 轉(zhuǎn)譯
var obj = {
  getArrow: function getArrow() {
    var _this = this;
    return function () {
      console.log(_this === obj);
    };
  }
};

另外需要注意的是,箭頭函數(shù)不能用 new 調(diào)用,不能 bind() 到某個(gè)對(duì)象(雖然 bind() 方法調(diào)用沒問(wèn)題,但是不會(huì)產(chǎn)生預(yù)期效果)。不管在什么情況下使用箭頭函數(shù),它本身是沒有綁定 this 的,它用的是直接外層函數(shù)(即包含它的最近的一層函數(shù)或函數(shù)表達(dá)式)綁定的 this 。

感謝各位的閱讀!關(guān)于“JavaScript中this指向有什么用”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)建站www.bm7419.com,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。

網(wǎng)頁(yè)題目:JavaScript中this指向有什么用-創(chuàng)新互聯(lián)
網(wǎng)站地址:http://www.bm7419.com/article48/dpcghp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、虛擬主機(jī)企業(yè)網(wǎng)站制作、網(wǎng)站制作網(wǎng)站改版、網(wǎng)站導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營(yíng)