最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解JS中的this、apply、call、bind(經(jīng)典面試題)

 更新時(shí)間:2017年09月19日 10:28:47   投稿:mrr  
JS中的this、apply、call、bind是一道經(jīng)典面試題,最好還是了解一下 this 的指向和 call、apply、bind 三者的區(qū)別。下面就跟隨腳本之家小編一起學(xué)習(xí)this、apply、call、bind的知識(shí)吧

這又是一個(gè)面試經(jīng)典問題~/(ㄒoㄒ)/~~也是 ES5中眾多坑中的一個(gè),在 ES6 中可能會(huì)極大避免 this 產(chǎn)生的錯(cuò)誤,但是為了一些老代碼的維護(hù),最好還是了解一下 this 的指向和 call、apply、bind 三者的區(qū)別。

this 的指向

在 ES5 中,其實(shí) this 的指向,始終堅(jiān)持一個(gè)原理:this 永遠(yuǎn)指向最后調(diào)用它的那個(gè)對(duì)象,來(lái),跟著我朗讀三遍:this 永遠(yuǎn)指向最后調(diào)用它的那個(gè)對(duì)象,this 永遠(yuǎn)指向最后調(diào)用它的那個(gè)對(duì)象,this 永遠(yuǎn)指向最后調(diào)用它的那個(gè)對(duì)象。記住這句話,this 你已經(jīng)了解一半了。

下面我們來(lái)看一個(gè)最簡(jiǎn)單的例子:

例 1:

 var name = "windowsName";
 function a() {
  var name = "Cherry";
  console.log(this.name);   // windowsName
  console.log("inner:" + this); // inner: Window
 }
 a();
 console.log("outer:" + this)   // outer: Window

這個(gè)相信大家都知道為什么 log 的是 windowsName,因?yàn)楦鶕?jù)剛剛的那句話“this 永遠(yuǎn)指向最后調(diào)用它的那個(gè)對(duì)象”,我們看最后調(diào)用 a 的地方 a();,前面沒有調(diào)用的對(duì)象那么就是全局對(duì)象 window,這就相當(dāng)于是 window.a();注意,這里我們沒有使用嚴(yán)格模式,如果使用嚴(yán)格模式的話,全局對(duì)象就是 undefined,那么就會(huì)報(bào)錯(cuò) Uncaught TypeError: Cannot read property 'name' of undefined。

再看下這個(gè)例子:

例 2:

var name = "windowsName";
 var a = {
  name: "Cherry",
  fn : function () {
   console.log(this.name);  // Cherry
  }
 }
 a.fn();

在這個(gè)例子中,函數(shù) fn 是對(duì)象 a 調(diào)用的,所以打印的值就是 a 中的 name 的值。是不是有一點(diǎn)清晰了呢~

我們做一個(gè)小小的改動(dòng):

例 3:

var name = "windowsName";
 var a = {
  name: "Cherry",
  fn : function () {
   console.log(this.name);  // Cherry
  }
 }
 window.a.fn();

這里打印 Cherry 的原因也是因?yàn)閯倓偰蔷湓挕皌his 永遠(yuǎn)指向最后調(diào)用它的那個(gè)對(duì)象”,最后調(diào)用它的對(duì)象仍然是對(duì)象 a。

我們?cè)賮?lái)看一下這個(gè)例子:

例 4:

 var name = "windowsName";
 var a = {
  // name: "Cherry",
  fn : function () {
   console.log(this.name);  // undefined
  }
 }
 window.a.fn();

這里為什么會(huì)打印 undefined 呢?這是因?yàn)檎鐒倓偹枋龅哪菢?,調(diào)用 fn 的是 a 對(duì)象,也就是說(shuō) fn 的內(nèi)部的 this 是對(duì)象 a,而對(duì)象 a 中并沒有對(duì) name 進(jìn)行定義,所以 log 的 this.name 的值是 undefined。

這個(gè)例子還是說(shuō)明了:this 永遠(yuǎn)指向最后調(diào)用它的那個(gè)對(duì)象,因?yàn)樽詈笳{(diào)用 fn 的對(duì)象是 a,所以就算 a 中沒有 name 這個(gè)屬性,也不會(huì)繼續(xù)向上一個(gè)對(duì)象尋找 this.name,而是直接輸出 undefined。

再來(lái)看一個(gè)比較坑的例子:

例 5:

 var name = "windowsName";
 var a = {
  name : null,
  // name: "Cherry",
  fn : function () {
   console.log(this.name);  // windowsName
  }
 }
 var f = a.fn;
 f();

這里你可能會(huì)有疑問,為什么不是 Cherry,這是因?yàn)殡m然將 a 對(duì)象的 fn 方法賦值給變量 f 了,但是沒有調(diào)用,再接著跟我念這一句話:“this 永遠(yuǎn)指向最后調(diào)用它的那個(gè)對(duì)象”,由于剛剛的 f 并沒有調(diào)用,所以 fn() 最后仍然是被 window 調(diào)用的。所以 this 指向的也就是 window。

由以上五個(gè)例子我們可以看出,this 的指向并不是在創(chuàng)建的時(shí)候就可以確定的,在 es5 中,永遠(yuǎn)是this 永遠(yuǎn)指向最后調(diào)用它的那個(gè)對(duì)象。

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

例 6:

 var name = "windowsName";
 function fn() {
  var name = 'Cherry';
  innerFunction();
  function innerFunction() {
   console.log(this.name);  // windowsName
  }
 }
 fn()

讀到現(xiàn)在了應(yīng)該能夠理解這是為什么了吧(o゚▽゚)o。

怎么改變 this 的指向

改變 this 的指向我總結(jié)有以下幾種方法:

使用 ES6 的箭頭函數(shù)

在函數(shù)內(nèi)部使用 _this = this

使用 apply、call、bind

new 實(shí)例化一個(gè)對(duì)象

例 7:

var name = "windowsName";
 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)  
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   },100);
  }
 };
 a.func2()  // this.func1 is not a function

在不使用箭頭函數(shù)的情況下,是會(huì)報(bào)錯(cuò)的,因?yàn)樽詈笳{(diào)用 setTimeout 的對(duì)象是 window,但是在 window 中并沒有 func1 函數(shù)。

我們?cè)诟淖?this 指向這一節(jié)將把這個(gè)例子作為 demo 進(jìn)行改造。

箭頭函數(shù)

眾所周知,ES6 的箭頭函數(shù)是可以避免 ES5 中使用 this 的坑的。箭頭函數(shù)的 this 始終指向函數(shù)定義時(shí)的 this,而非執(zhí)行時(shí)。,箭頭函數(shù)需要記著這句話:“箭頭函數(shù)中沒有 this 綁定,必須通過(guò)查找作用域鏈來(lái)決定其值,如果箭頭函數(shù)被非箭頭函數(shù)包含,則 this 綁定的是最近一層非箭頭函數(shù)的 this,否則,this 為 undefined”。

例 8 :

 var name = "windowsName";
 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)  
  },
  func2: function () {
   setTimeout( () => {
    this.func1()
   },100);
  }
 };
 a.func2()  // Cherry

在函數(shù)內(nèi)部使用 _this = this

如果不使用 ES6,那么這種方式應(yīng)該是最簡(jiǎn)單的不會(huì)出錯(cuò)的方式了,我們是先將調(diào)用這個(gè)函數(shù)的對(duì)象保存在變量 _this 中,然后在函數(shù)中都使用這個(gè) _this,這樣 _this 就不會(huì)改變了。

例 9:

 var name = "windowsName";
 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)  
  },
  func2: function () {
   var _this = this;
   setTimeout( function() {
    _this.func1()
   },100);
  }
 };
 a.func2()  // Cherry

這個(gè)例子中,在 func2 中,首先設(shè)置 var _this = this;,這里的 this 是調(diào)用 func2 的對(duì)象 a,為了防止在 func2 中的 setTimeout 被 window 調(diào)用而導(dǎo)致的在 setTimeout 中的 this 為 window。我們將 this(指向變量 a) 賦值給一個(gè)變量 _this,這樣,在 func2 中我們使用 _this 就是指向?qū)ο?a 了。

使用 apply、call、bind

使用 apply、call、bind 函數(shù)也是可以改變 this 的指向的,原理稍后再講,我們先來(lái)看一下是怎么實(shí)現(xiàn)的:

使用 apply

例 10:

 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   }.apply(a),100);
  }
 };
 a.func2()   // Cherry

使用 call

例 11:

 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   }.call(a),100);
  }
 };
 a.func2()   // Cherry

使用 bind

例 12:

var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   }.bind(a)(),100);
  }
 };
 a.func2()   // Cherry

apply、call、bind 區(qū)別

剛剛我們已經(jīng)介紹了 apply、call、bind 都是可以改變 this 的指向的,但是這三個(gè)函數(shù)稍有不同。

在 MDN 中定義 apply 如下;

apply() 方法調(diào)用一個(gè)函數(shù), 其具有一個(gè)指定的this值,以及作為一個(gè)數(shù)組(或類似數(shù)組的對(duì)象)提供的參數(shù)

語(yǔ)法:

fun.apply(thisArg, [argsArray])

thisArg:在 fun 函數(shù)運(yùn)行時(shí)指定的 this 值。需要注意的是,指定的 this 值并不一定是該函數(shù)執(zhí)行時(shí)真正的 this 值,如果這個(gè)函數(shù)處于非嚴(yán)格模式下,則指定為 null 或 undefined 時(shí)會(huì)自動(dòng)指向全局對(duì)象(瀏覽器中就是window對(duì)象),同時(shí)值為原始值(數(shù)字,字符串,布爾值)的 this 會(huì)指向該原始值的自動(dòng)包裝對(duì)象。

argsArray:一個(gè)數(shù)組或者類數(shù)組對(duì)象,其中的數(shù)組元素將作為單獨(dú)的參數(shù)傳給 fun 函數(shù)。如果該參數(shù)的值為null 或 undefined,則表示不需要傳入任何參數(shù)。從ECMAScript 5 開始可以使用類數(shù)組對(duì)象。瀏覽器兼容性請(qǐng)參閱本文底部?jī)?nèi)容。

apply 和 call 的區(qū)別

其實(shí) apply 和 call 基本類似,他們的區(qū)別只是傳入的參數(shù)不同。

call 的語(yǔ)法為:

fun.call(thisArg[, arg1[, arg2[, ...]]])

所以 apply 和 call 的區(qū)別是 call 方法接受的是若干個(gè)參數(shù)列表,而 apply 接收的是一個(gè)包含多個(gè)參數(shù)的數(shù)組。

例 13:

var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.apply(a,[1,2])  // 3

例 14:

var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.call(a,1,2)  // 3

bind 和 apply、call 區(qū)別

我們先來(lái)將剛剛的例子使用 bind 試一下

 var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.bind(a,1,2)

我們會(huì)發(fā)現(xiàn)并沒有輸出,這是為什么呢,我們來(lái)看一下 MDN 上的文檔說(shuō)明:

bind()方法創(chuàng)建一個(gè)新的函數(shù), 當(dāng)被調(diào)用時(shí),將其this關(guān)鍵字設(shè)置為提供的值,在調(diào)用新函數(shù)時(shí),在任何提供之前提供一個(gè)給定的參數(shù)序列。

所以我們可以看出,bind 是創(chuàng)建一個(gè)新的函數(shù),我們必須要手動(dòng)去調(diào)用:

var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.bind(a,1,2)()   // 3

總結(jié)

以上所述是小編給大家介紹的JS中的this、apply、call、bind,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • axios基本入門用法教程

    axios基本入門用法教程

    之前當(dāng)vue更新到2.0之后,作者就宣告不再對(duì)vue-resource更新,而是推薦的axios,前一段時(shí)間用了一下,現(xiàn)在說(shuō)一下它的基本用法。文中介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-03-03
  • nodejs分離html文件里面的js和css的方法

    nodejs分離html文件里面的js和css的方法

    這篇文章主要介紹了nodejs分離html文件里面的js和css的方法,本文需要分離出一個(gè)html 文件里面的script 和style 里面的內(nèi)容,然后單獨(dú)生成js文件和css 文件,感興趣的可以了解一下
    2019-04-04
  • XMLHTTP 亂碼的解決方法(UTF8,GB2312 編碼 解碼)

    XMLHTTP 亂碼的解決方法(UTF8,GB2312 編碼 解碼)

    XMLHTTP 亂碼的解決方法(UTF8,GB2312 編碼 解碼)(附帶解決DHTMLX不能用中文的問題)
    2011-01-01
  • js實(shí)現(xiàn)隨機(jī)點(diǎn)名功能

    js實(shí)現(xiàn)隨機(jī)點(diǎn)名功能

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)隨機(jī)點(diǎn)名功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • 小程序中手機(jī)號(hào)識(shí)別的示例

    小程序中手機(jī)號(hào)識(shí)別的示例

    這篇文章主要介紹了小程序中手機(jī)號(hào)識(shí)別的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • JS觸發(fā)事件event.target VS event.currentTarget實(shí)例

    JS觸發(fā)事件event.target VS event.currentTarget實(shí)例

    這篇文章主要介紹了JS觸發(fā)事件event.target VS event.currentTarget實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • 150行代碼帶你實(shí)現(xiàn)微信小程序中的數(shù)據(jù)偵聽

    150行代碼帶你實(shí)現(xiàn)微信小程序中的數(shù)據(jù)偵聽

    在這篇文章中, 我將用150行代碼, 手把手帶你打造一個(gè)小程序也可以使用的偵聽器,感興趣的朋友跟隨小編一起看看吧
    2019-05-05
  • 小程序?qū)崿F(xiàn)頁(yè)面多級(jí)來(lái)回切換的示例代碼

    小程序?qū)崿F(xiàn)頁(yè)面多級(jí)來(lái)回切換的示例代碼

    這篇文章主要為大家詳細(xì)介紹了小程序如何頁(yè)面多級(jí)來(lái)回切換支持滑動(dòng)和點(diǎn)擊操作,文中的實(shí)現(xiàn)步驟講解詳細(xì),快跟隨小編一起動(dòng)手嘗試一下吧
    2022-07-07
  • javascript在事件監(jiān)聽方面的兼容性小結(jié)

    javascript在事件監(jiān)聽方面的兼容性小結(jié)

    javascript 在事件監(jiān)聽方面的兼容性總結(jié),注意是由于多個(gè)瀏覽器的不一致,導(dǎo)致大家在js書寫時(shí)需要考慮多個(gè)瀏覽器的兼容性。
    2010-04-04
  • JS實(shí)現(xiàn)自定義彈窗功能

    JS實(shí)現(xiàn)自定義彈窗功能

    瀏覽器自帶的原生彈窗很不美觀,而且功能比較單一,絕大部分時(shí)候我們都會(huì)按照設(shè)計(jì)圖自定義彈窗或者直接使用注入layer的彈窗等等。下面小編給大家?guī)?lái)了JS實(shí)現(xiàn)自定義彈窗,感興趣的朋友一起看看吧
    2018-08-08

最新評(píng)論

潞城市| 乐亭县| 平遥县| 扎赉特旗| 江门市| 巴彦县| 东莞市| 清原| 建阳市| 夏邑县| 襄樊市| 丘北县| 靖州| 晋城| 河津市| 伊宁市| 杂多县| 黄大仙区| 汕尾市| 平江县| 社旗县| 福州市| 岳阳市| 建瓯市| 宁蒗| 喜德县| 曲阜市| 五台县| 特克斯县| 右玉县| 张家港市| 栾城县| 丘北县| 大荔县| 芜湖市| 曲沃县| 浙江省| 民权县| 公主岭市| 兴安盟| 临武县|