成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript之例題中徹底理解this

Hwg / 833人閱讀

摘要:最后重點(diǎn)理解結(jié)論箭頭函數(shù)的,總是指向定義時(shí)所在的對(duì)象,而不是運(yùn)行時(shí)所在的對(duì)象。輸出,箭頭函數(shù)不會(huì)綁定所以傳入指向無效。原因是,要徹底理解應(yīng)該是建立在已經(jīng)大致理解了中的執(zhí)行上下文,作用域作用域鏈,閉包,變量對(duì)象,函數(shù)執(zhí)行過程的基礎(chǔ)上。

本文共 2025 字,看完只需 8 分鐘
概述

前面的文章講解了 JavaScript 中的執(zhí)行上下文,作用域,變量對(duì)象,this 的相關(guān)原理,但是我后來在網(wǎng)上看到一些例題的時(shí)候,依然沒能全做對(duì),說明自己有些細(xì)節(jié)還沒能掌握,本文就結(jié)合例題進(jìn)行深入實(shí)踐,討論函數(shù)在不同的調(diào)用方式 this 的指向問題。

老規(guī)矩,先給結(jié)論 1 和 結(jié)論2:

this 始終指向最后調(diào)用它的對(duì)象

“箭頭函數(shù)”的this,總是指向定義時(shí)所在的對(duì)象,而不是運(yùn)行時(shí)所在的對(duì)象。

特別提示:
本文的例子,最好自己在瀏覽器控制臺(tái)中去試一遍,看完過兩天就會(huì)忘的,一定要實(shí)踐。

一、隱式綁定
// 例 1
var name = "window";

function foo() {
    var name = "inner";

    console.log(this.name);
}

foo();  // ?

輸出:

window

例 1 中,非嚴(yán)格模式,由于 foo 函數(shù)是在全局環(huán)境中被調(diào)用,this 會(huì)被默認(rèn)指向全局對(duì)象 window;

所以符合了我們的結(jié)論一:

this 始終指向最后調(diào)用它的對(duì)象
二、一般函數(shù)和箭頭函數(shù)的對(duì)象調(diào)用
// 例 2
var name = "window";

var person = {
    name: "inner",
    show1: function () {
        console.log(this.name);
    },
    show2: () => {
        console.log(this.name);
    }
}

person.show1();  // ?
person.show2();  // ?

輸出:

inner  
window

person.show1() 輸出 inner 沒毛病,person.show2() 箭頭函數(shù)為什么會(huì)輸出 window 呢。MDN 中對(duì) this 的定義是:

箭頭函數(shù)不綁定 this, 箭頭函數(shù)不會(huì)創(chuàng)建自己的this,它只會(huì)從自己的作用域鏈的上一層繼承this。

再看本文前面給的結(jié)論:

“箭頭函數(shù)”的this,總是指向定義時(shí)所在的對(duì)象,而不是運(yùn)行時(shí)所在的對(duì)象。

由于 JS 中只有全局作用域和函數(shù)作用域,箭頭函數(shù)在定義時(shí)的上一層作用域是全局環(huán)境,全局環(huán)境中的 this 指向全局對(duì)象本身,即 window。

三、call
// 例 3
var name = "window"

var person1 = {
  name: "person1",
  show1: function () {
    console.log(this.name)
  },
  show2: () => console.log(this.name),
  show3: function () {
    return function () {
      console.log(this.name)
    }
  },
  show4: function () {
    return () => console.log(this.name)
  }
}
var person2 = { name: "person2" }

person1.show1()  // ?
person1.show1.call(person2)  // ?

person1.show2()  // ?
person1.show2.call(person2)  // ?

person1.show3()()  // ?
person1.show3().call(person2)  // ?
person1.show3.call(person2)()  // ?

person1.show4()()  // ?
person1.show4().call(person2)  // ?
person1.show4.call(person2)()  // ?

輸出:

person1  
person2

window
window

window
person2
window

person1
person1
person2

上面 10 行打印,你對(duì)了幾個(gè)呢?

首先:
person1.show1()person1.show1.call(person2) 輸出結(jié)果應(yīng)該沒問題,call 的作用就是改變了調(diào)用的對(duì)象 為 person2。

其次:
person1.show2(),person1.show2.call(person2),由于調(diào)用的是箭頭函數(shù),和本文例 2 中是一樣的,箭頭函數(shù)定義時(shí) this 指向的是上一層,也就是全局對(duì)象, 并且 箭頭函數(shù)不綁定自己的 this, 所以通過 call()apply() 方法調(diào)用箭頭函數(shù)時(shí),只能傳遞參數(shù),不能傳遞新的對(duì)象進(jìn)行綁定。故打印的值都是 window。

進(jìn)而:

function foo () {
    return function () {
      console.log(this.name)
    }
  }

foo()();

博客前面的文章有講過閉包,上面這段代碼也是典型的閉包運(yùn)用,可以看作:

function foo () {
    return function () {
      console.log(this.name)
    }
  }

var bar = foo();
bar();

所以,很明顯,被返回的內(nèi)部函數(shù)其實(shí)是在全局環(huán)境下被調(diào)用的。回到前面看我們的結(jié)論 1,this 始終指向最后調(diào)用函數(shù)的對(duì)象,這句話的關(guān)鍵詞應(yīng)該是什么?我覺得應(yīng)該是 調(diào)用,什么時(shí)候調(diào)用,誰調(diào)用。

再回過頭來看:
person1.show3()() 輸出 window,因?yàn)閮?nèi)部函數(shù)在全局環(huán)境中被調(diào)用。

person1.show3().call(person2) 輸出 person2, 因?yàn)閮?nèi)部函數(shù)被 person2 對(duì)象調(diào)用了。

person1.show3.call(person2)() 輸出 window,也是因?yàn)閮?nèi)部函數(shù)在全局環(huán)境中被調(diào)用。

最后:
重點(diǎn)理解結(jié)論 2:

“箭頭函數(shù)”的this,總是指向定義時(shí)所在的對(duì)象,而不是運(yùn)行時(shí)所在的對(duì)象。
show4: function () {
    return () => console.log(this.name)
  }

這段代碼中,箭頭函數(shù)是在 外層函數(shù) show4 執(zhí)行后才被定義的。為什么?可以翻看我前面關(guān)于作用域鏈,執(zhí)行上下文,變量對(duì)象的文章,函數(shù)在進(jìn)入執(zhí)行階段時(shí),會(huì)先查找內(nèi)部的變量和函數(shù)聲明,將他們作為變量對(duì)象的屬性,關(guān)聯(lián)作用域鏈,并綁定 this 指向。

所以:
person1.show4()() 輸出 person1,因?yàn)橥獠亢瘮?shù)在執(zhí)行時(shí)的 this 為 person1, 此時(shí)定義了內(nèi)部函數(shù),而內(nèi)部函數(shù)為外部函數(shù)的 this。

person1.show4().call(person2) 輸出 person1,箭頭函數(shù)不會(huì)綁定 this, 所以 call 傳入 this 指向無效。

person1.show4.call(person2)() 輸出 person2,因?yàn)橥獠亢瘮?shù)在執(zhí)行時(shí)的 this 為 person2,此時(shí)定義了內(nèi)部函數(shù),而內(nèi)部函數(shù)為外部函數(shù)的 this。

四、構(gòu)造函數(shù)中的 this
// 例 4
var name = "window"

function Person (name) {
  this.name = name;
  this.show1 = function () {
    console.log(this.name)
  }
  this.show2 = () => console.log(this.name)
  this.show3 = function () {
    return function () {
      console.log(this.name)
    }
  }
  this.show4 = function () {
    return () => console.log(this.name)
  }
}

var personA = new Person("personA")
var personB = new Person("personB")

personA.show1()  // 
personA.show1.call(personB)  // 

personA.show2()  // 
personA.show2.call(personB)  // 

personA.show3()()  // 
personA.show3().call(personB)  // 
personA.show3.call(personB)()  // 

personA.show4()()  // 
personA.show4().call(personB)  // 
personA.show4.call(personB)()  //

輸出:

personA  
personB

personA
personA

window
personB
window

personA
personA
personB

例 4 和 例 3 大致一樣,唯一的區(qū)別在于兩點(diǎn):

構(gòu)造函數(shù)中 this 指向被創(chuàng)建的實(shí)例

構(gòu)造函數(shù),也是函數(shù),所以存在作用域,所以里面的箭頭函數(shù),它們的 this 指向,來自于上一層,就不再是全局環(huán)境 window, 而是構(gòu)造函數(shù) 的 this。

五、setTimeout 函數(shù)
// 例 5
function foo(){
  setTimeout(() =>{
    console.log("id:", this.id)
      setTimeout(() =>{
        console.log("id:", this.id)
      }, 100);
  }, 100);
}

foo.call({id: 111});  // 

輸出:

111   
111

注意一點(diǎn):
setTimeout 函數(shù)是在全局環(huán)境被 window 對(duì)象執(zhí)行的,但是 foo 函數(shù)在執(zhí)行時(shí),setTimtout 委托的匿名箭頭函數(shù)被定義,箭頭函數(shù)的 this 來自于上層函數(shù) foo 的調(diào)用對(duì)象, 所以打印結(jié)果才為 111;

六、setTimeout 函數(shù) 2
// 例 6
function foo1(){
  setTimeout(() =>{
    console.log("id:", this.id)
      setTimeout(function (){
        console.log("id:", this.id)
      }, 100);
  }, 100);
}


function foo2(){
  setTimeout(function() {
    console.log("id:", this.id)
      setTimeout(() => {
        console.log("id:", this.id)
      }, 100);
  }, 100);
}

foo1.call({ id: 111 });  // ?
foo2.call({ id: 222 });  // ?

輸出:

111  
undefined

undefined
undefined

例 5 中已經(jīng)提到,setTimeout函數(shù)被 window 對(duì)象調(diào)用,如果
是普通函數(shù),內(nèi)部的 this 自然指向了全局對(duì)象下的 id, 所以為 undefined,如果是箭頭函數(shù),this 指向的就是外部函數(shù)的 this。

七、嵌套箭頭函數(shù)
// 例 7
function foo() {
  return () => {
    return () => {
      return () => {
        console.log("id:", this.id);
      };
    };
  };
}

var f = foo.call({id: 1});

var t1 = f.call({id: 2})()();  // 
var t2 = f().call({id: 3})();  // 
var t3 = f()().call({id: 4});  // 

輸出:

1  
1
1

這段代碼是為了鞏固我們的結(jié)論2:

“箭頭函數(shù)”的this,總是指向定義時(shí)所在的對(duì)象,而不是運(yùn)行時(shí)所在的對(duì)象。

foo.call({}) 在執(zhí)行時(shí),內(nèi)部的第一層箭頭函數(shù)才被定義

箭頭函數(shù)無法綁定 this, 所以 call 函數(shù)指定 this 無效

箭頭函數(shù)的 this 來自于上一層作用域(非箭頭函數(shù)作用域)的 this

總結(jié)

有本書中有提到,當(dāng)理解 JavaScript 中的 this 之后,JavaScript 才算入門,我深以為然。

原因是,要徹底理解 this, 應(yīng)該是建立在已經(jīng)大致理解了 JS 中的執(zhí)行上下文,作用域、作用域鏈,閉包,變量對(duì)象,函數(shù)執(zhí)行過程的基礎(chǔ)上。

有興趣深入了解上下文,作用域,閉包相關(guān)內(nèi)容的同學(xué)可以翻看我之前的文章。

參考鏈接:

1:this、apply、call、bind
2: 從這兩套題,重新認(rèn)識(shí)JS的this、作用域、閉包、對(duì)象
3: 關(guān)于箭頭函數(shù)this的理解幾乎完全是錯(cuò)誤的
4: 深入JS系列

歡迎關(guān)注我的個(gè)人公眾號(hào)“謝南波”,專注分享原創(chuàng)文章。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/98761.html

相關(guān)文章

  • JS專題數(shù)組去重

    摘要:將元素作為對(duì)象的鍵,默認(rèn)鍵對(duì)應(yīng)的值為如果對(duì)象中沒有這個(gè)鍵,則將這個(gè)元素放入結(jié)果數(shù)組中去。 前言 數(shù)組去重在日常開發(fā)中的使用頻率還是較高的,也是網(wǎng)上隨便一抓一大把的話題,所以,我寫這篇文章目的在于歸納和總結(jié),既然很多人都在提的數(shù)組去重,自己到底了解多少呢。又或者是如果自己在開發(fā)中遇到了去重的需求,自己能想到更好的解決方案嗎。 這次我們來理一理怎么做數(shù)組去重才能做得最合適,既要考慮兼容性,...

    only_do 評(píng)論0 收藏0
  • JavaScript函數(shù)調(diào)用的經(jīng)典例題

    摘要:第二問直接調(diào)用函數(shù),相當(dāng)于調(diào)用,那么與函數(shù)無關(guān)。第三問先執(zhí)行了函數(shù),然后調(diào)用函數(shù)的返回值對(duì)象的屬性函數(shù)。第四問再次調(diào)用函數(shù)時(shí),此時(shí)函數(shù)已經(jīng)被第三問執(zhí)行時(shí)修改,所以結(jié)果為。 JavaScript函數(shù)調(diào)用的經(jīng)典例題 很多初學(xué)JavaScript的人對(duì)函數(shù)的調(diào)用理解有些模糊的,話不多說,直接上題: function Foo() { getName = function...

    cyqian 評(píng)論0 收藏0
  • 面向?qū)ο蟮?JavaScript

    摘要:是完全的面向?qū)ο笳Z言,它們通過類的形式組織函數(shù)和變量,使之不能脫離對(duì)象存在。而在基于原型的面向?qū)ο蠓绞街?,?duì)象則是依靠構(gòu)造器利用原型構(gòu)造出來的。 JavaScript 函數(shù)式腳本語言特性以及其看似隨意的編寫風(fēng)格,導(dǎo)致長期以來人們對(duì)這一門語言的誤解,即認(rèn)為 JavaScript 不是一門面向?qū)ο蟮恼Z言,或者只是部分具備一些面向?qū)ο蟮奶卣?。本文將回歸面向?qū)ο蟊疽猓瑥膶?duì)語言感悟的角度闡述為什...

    novo 評(píng)論0 收藏0
  • javascript對(duì)象不完全探索記錄01:this! which?

    溫馨提示:作者的爬坑記錄,對(duì)你等大神完全沒有價(jià)值,別在我這浪費(fèi)生命 這一切,源于阮大神博文學(xué)習(xí)Javascript閉包(Closure)- 阮一峰中的一道思考題 //問題1: var name = The Window; var object = {   name : My Object,   getNameFunc : function(){     return function(){    ...

    rubyshen 評(píng)論0 收藏0
  • JavaScript深入淺出

    摘要:理解的函數(shù)基礎(chǔ)要搞好深入淺出原型使用原型模型,雖然這經(jīng)常被當(dāng)作缺點(diǎn)提及,但是只要善于運(yùn)用,其實(shí)基于原型的繼承模型比傳統(tǒng)的類繼承還要強(qiáng)大。中文指南基本操作指南二繼續(xù)熟悉的幾對(duì)方法,包括,,。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。 怎樣使用 this 因?yàn)楸救藢儆趥吻岸?,因此文中只看懂?8 成左右,希望能夠給大家?guī)韼椭?...(據(jù)說是阿里的前端妹子寫的) this 的值到底...

    blair 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<