自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Know this, use this! (總結(jié) this 的常見(jiàn)用法)

開(kāi)發(fā) 開(kāi)發(fā)工具
在了解this之前,相信大家都應(yīng)該會(huì)知道作用域這個(gè)知識(shí)點(diǎn)的存在,函數(shù)在創(chuàng)建之后,會(huì)構(gòu)建自己的執(zhí)行環(huán)境以及作用域,這是一開(kāi)始就確定了。但是實(shí)際的上下文(context)環(huán)境,也可以理解為就是this,它是動(dòng)態(tài)確定的,即在函數(shù)運(yùn)行時(shí)才確定this所指向的對(duì)象,而非聲明時(shí)所指向的對(duì)象。

[[170676]]

this應(yīng)該是一個(gè)討論了很久的話(huà)題了。其中,關(guān)于this的文章,在很多的博客當(dāng)中也有很多介紹,但是,以前我都是一知半解的去了解它,就是看博客當(dāng)中,只介紹了一些情況下的 this 的使用方式,但是也并沒(méi)有自己去做過(guò)總結(jié)。剛好是在掘金當(dāng)中有看到一篇關(guān)于this的一些詳細(xì)文章,文末會(huì)附上鏈接以及英文原文,這里純粹是自己進(jìn)行一個(gè)總結(jié),以后方便自己進(jìn)行回顧以及加深印象。希望這篇文章對(duì)于你了解this有一定的幫助,文末還有一些練習(xí)題噢~希望真的對(duì)你們有幫助。(因?yàn)閷?xiě)項(xiàng)目過(guò)程中,一直被 this 坑過(guò),卻找了很久的 bug ,我真是 樂(lè)了狗)

在了解this之前,相信大家都應(yīng)該會(huì)知道作用域這個(gè)知識(shí)點(diǎn)的存在,函數(shù)在創(chuàng)建之后,會(huì)構(gòu)建自己的執(zhí)行環(huán)境以及作用域,這是一開(kāi)始就確定了。但是實(shí)際的上下文(context)環(huán)境,也可以理解為就是this,它是動(dòng)態(tài)確定的,即在函數(shù)運(yùn)行時(shí)才確定this所指向的對(duì)象,而非聲明時(shí)所指向的對(duì)象。

關(guān)于this,總結(jié)起來(lái),主要有以下幾個(gè)途徑能夠被運(yùn)用到。

1 對(duì)象方法中調(diào)用this

如果函數(shù)被當(dāng)中對(duì)象的一個(gè)方法進(jìn)行調(diào)用,則this值指向該對(duì)象。

  1. var person = { 
  2.     name'Alice'
  3.     sayName: function() { 
  4.         alert('welcome ' + this.name); 
  5.     } 
  6.  
  7. person.sayName();    // this == person, alert: 'welcome Alice' 

 在這里,函數(shù)的this指向該對(duì)象(即 person);但是有一點(diǎn)需要注意,就是當(dāng)對(duì)象的方法被賦予給一個(gè)變量時(shí),其則變?yōu)榱撕瘮?shù)觸發(fā),此時(shí)的this為 window 或者 undefined(嚴(yán)格模式下),如下:

  1. var name = 'Bob'
  2. var person;    // 即上面的定義,此不拓展詳細(xì),直接使用 
  3.  
  4. var say = person.sayName;    // this == window || undefined 
  5. say();    // 'welcome Bob' || throw an error: Cannot read property 'name' of undefined(...) 

 2 函數(shù)內(nèi)部使用

在函數(shù)內(nèi)部當(dāng)中使用了 this,即函數(shù)被當(dāng)做方法使用,不同于 1 當(dāng)中作為對(duì)象的方法使用,此時(shí)調(diào)用,是在全局作用域下進(jìn)行調(diào)用,即在window下進(jìn)行調(diào)用,由定義可以知道,在全局作用域下聲明一個(gè)函數(shù),其自動(dòng)加為window的一個(gè)屬性。this此時(shí)名正言順的會(huì)指向window,嚴(yán)格模式下為 undefined

  1. function sayThis() { 
  2.     alert(this == window);    // true 

 結(jié)合第一點(diǎn),函數(shù)作為對(duì)象的一個(gè)方法使用,這里存在一個(gè)小坑,即閉包,啥是閉包,這個(gè)在這里就不扯開(kāi)了,最簡(jiǎn)單的理解就是Function that returns function,如果不理解什么是閉包的話(huà),可以去翻翻 《JavaScript 高級(jí)程序設(shè)計(jì)》第七章關(guān)于閉包的相關(guān)內(nèi)容。第一點(diǎn)當(dāng)中存在一個(gè)小坑,就是將對(duì)象的方法賦予給一個(gè)變量的時(shí)候,其變?yōu)楹瘮?shù)觸發(fā),此時(shí)的 this 實(shí)際上是指向 window(非嚴(yán)格模式)。

那么,當(dāng)函數(shù)中返回一個(gè)函數(shù),此時(shí)在對(duì)象當(dāng)中調(diào)用該方法,其就相當(dāng)于是函數(shù)觸發(fā),此時(shí)的 this,在不做任何上下文綁定的前提之下,其指向 window(非嚴(yán)格模式)。

  1. var name = 'Bob'
  2.     person = { 
  3.         name'Alice'
  4.         sayName: function() { 
  5.             console.log(this === person);    // true 
  6.             return function() { 
  7.                 console.log(this === person);    // false 
  8.                 console.log(this === window);    // true 
  9.                 console.log(this.name);          // Bob 
  10.             }; 
  11.         } 
  12.     }; 
  13.  
  14. person.sayName()(); 

 當(dāng)然,要解決這個(gè)問(wèn)題的方法,很簡(jiǎn)單,就是給他綁定一個(gè)上下文。

  1. var name = 'Bob'
  2.     person = { 
  3.         name'Alice'
  4.         sayName: function() { 
  5.             console.log(this === person);    // true 
  6.             return function() { 
  7.                 console.log(this === person);    // true 
  8.                 console.log(this === window);    // false 
  9.                 console.log(this.name);          // Alice 
  10.             }.bind(this); 
  11.         } 
  12.     }; 
  13.  
  14. person.sayName()(); 

 3 new 當(dāng)中進(jìn)行使用

我們知道在使用 new 方法創(chuàng)建對(duì)象的時(shí)候,會(huì)經(jīng)過(guò)如下這些個(gè)過(guò)程:

  • 創(chuàng)建對(duì)象,將 this 值賦予新的對(duì)象
  • 調(diào)用構(gòu)造函數(shù),為 this 添加屬性和方法
  • 返回 this 給當(dāng)前的對(duì)象
  1. function Person(name, age) { 
  2.     this.name = name
  3.     this.age = age; 
  4.  
  5. var person1 = new Person('Alice', 29); 
  6. console.log(person1.name);    // Alice 

 這里要記得使用 new 運(yùn)算符,否則,其只能算是普通的調(diào)用,而不是創(chuàng)建一個(gè)新的實(shí)例對(duì)象。而當(dāng)做普通函數(shù)調(diào)用的話(huà),實(shí)際上即 第 2 種情況下,對(duì)函數(shù)普通調(diào)用,此時(shí)的 this 指向 window

  1. function Person(name, age) { 
  2.     this.name = name
  3.     this.age = age; 
  4.     return this; 
  5.  
  6. var person1 = Person('Alice', 29); 
  7. console.log(person1.name);    // Alice 
  8. console.log(window.name);     // Alice 
  9. console.log(person1 === window);    // true 

 這是正常情況下,this 會(huì)正確返回并且指向該對(duì)象,但是在構(gòu)造函數(shù)當(dāng)中,如果返回了一個(gè)對(duì)象,那么 this 會(huì)指向返回的那個(gè)對(duì)象。

  1. function Person(name, age) { 
  2.     this.name = name
  3.     this.age = age; 
  4.     return { 
  5.         name'Bob' 
  6.     }; 
  7.  
  8. var person1 = new Person('Alice'); 
  9. console.log(person1.name);    // Bob 
  10. console.log(person1.age);     // undefined 

 題外話(huà),類(lèi)似的,聯(lián)想到 var a = new Person(),則 a instanceof Person一定返回 true嗎?留給你們想一想咯。

4 使用 call、apply 或 bind 改變 this

在引用類(lèi)型 Function當(dāng)中,函數(shù)存在兩個(gè)方法屬性,call 和 apply,在 ECMAScript5當(dāng)中,加入了 bind 方法。題外話(huà),他們?nèi)邊^(qū)別,應(yīng)該都知道了吧,不知道的加緊補(bǔ)習(xí)呀。

  1. var name = 'Bob'
  2. var person = { 
  3.     name'Alice'
  4.     age: 29 
  5.  
  6. function sayName() { 
  7.     console.log(this.name); 
  8.  
  9. sayName.call(person);    // Alice 

 這里是使用了 call 方法來(lái)改變了 this的執(zhí)行環(huán)境,至于使用 apply,效果一樣,只是二者差別在于傳入?yún)?shù)的不同。

  1. func.call(context, arg1, arg2, ...) 
  2. func.apply(context, [arg1, arg2, ...]) 

 使用 bind 方法進(jìn)行上下文的改變,bind 方法與 call 和 apply有著本質(zhì)的不同,其不同點(diǎn)是,bind()函數(shù)返回的是一個(gè)新的函數(shù),即方法,而后兩者則都是立即執(zhí)行函數(shù),使用的時(shí)候即調(diào)用了該函數(shù),返回方法操作的結(jié)果。

并且,使用 bind()方法創(chuàng)建的 上下文,其為永久的上下文環(huán)境,不可修改,即使是使用 call 或者 apply方法,也無(wú)法修改 this所指向的值。

  1. var name = 'Bob'
  2. var person = { 
  3.     name'Alice'
  4.     age: 29 
  5.  
  6. function sayName() { 
  7.     console.log(this.name); 
  8.  
  9. var say = sayName.bind(person); 
  10. say();        // Alice 
  11. sayName();    // Bob 

 5 箭頭函數(shù)

箭頭函數(shù)并不創(chuàng)建其自身的上下文,其上下文 this,取決于其在定義時(shí)的外部函數(shù)。

并且,箭頭函數(shù)擁有靜態(tài)的上下文,即一次綁定之后,便不可再修改,即使是用了 第 4 種用途當(dāng)中的改變上下文的方法,也不為之動(dòng)容。

  1. var num = [1, 2, 3]; 
  2.  
  3. (function() { 
  4.     var showNumber = () => { 
  5.         console.log(this === num);    // true 
  6.         console.log(this);            // [1, 2, 3] 
  7.     } 
  8.     console.log(this === num);        // true 
  9.     showNumber();                     // true && [1, 2, 3] 
  10.     showNumber.call([1, 2]);          // true && [1, 2, 3] 
  11.     showNumber.apply([1, 2]);         // true && [1, 2, 3] 
  12.     showNumber.bind([1, 2])();        // true && [1, 2, 3] 
  13. }).call(num); 

 由于箭頭函數(shù)的外部決定上下文以及靜態(tài)上下文等的特性,不太建議使用箭頭函數(shù)在全局環(huán)境下來(lái)定義方法,因?yàn)椴荒芡ㄟ^(guò)其他方法改變其上下文。這很蛋疼。 

  1. function Period (hours, minutes) {   
  2.     this.hours = hours; 
  3.     this.minutes = minutes; 
  4. Period.prototype.format = () => {   
  5.     console.log(this === window);    // => true 
  6.     return this.hours + ' hours and ' + this.minutes + ' minutes'
  7. }; 
  8. var walkPeriod = new Period(2, 30);   
  9. console.log(walkPeriod.hours); 
  10. walkPeriod.format();    // => 'undefined hours and undefined minutes'  

此時(shí)的 this 實(shí)際上是指向了 window,所以 this.hours 和 this.minutes實(shí)際上沒(méi)有聲明的,故為 undefined。

在全局環(huán)境下,還是選用 函數(shù)表達(dá)式 來(lái)進(jìn)行函數(shù)的定義,可以保證正確的上下文環(huán)境

  1. function Period (hours, minutes) {   
  2.     this.hours = hours; 
  3.     this.minutes = minutes; 
  4. Period.prototype.format = function() {   
  5.     console.log(this === walkPeriod);    // => true 
  6.     return this.hours + ' hours and ' + this.minutes + ' minutes'
  7. }; 
  8. var walkPeriod = new Period(2, 30);   
  9. walkPeriod.format(); // '2 hours and 30 minutes'  

練習(xí)

  1. // 練習(xí)1 
  2. var func = (function(a) { 
  3.     this.a = a; 
  4.     return function(a) { 
  5.         a += this.a; 
  6.         return a; 
  7.     } 
  8. })(function(a, b) { 
  9.     return a; 
  10. }(1, 2)) 
  11.  
  12. func(4) // ? 
  13.  
  14. // 練習(xí)2 
  15. var x = 10, 
  16.     foo = { 
  17.         x: 20, 
  18.         bar: function() { 
  19.             var x = 30; 
  20.             return this.x; 
  21.         } 
  22.     } 
  23.  
  24. console.log(foo.bar()); 
  25. console.log((foo.bar)()); 
  26. console.log((foo.bar = foo.bar)()); 
  27. console.log((foo.bar, foo.bar)());  

希望看完這篇文章,這兩個(gè)練習(xí)題,你是能夠做出來(lái)的呀~ 好好分析一下唄。如果不確定的話(huà),可以在留言板上,咱們相互討論一下呀

責(zé)任編輯:龐桂玉 來(lái)源: segmentfault
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)