<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一篇通俗易懂的關于“原型” & “this”的解釋

          共 13270字,需瀏覽 27分鐘

           ·

          2021-10-22 03:25

          轉自:掘金?- i.m.t? https://juejin.cn/post/6921686794987634695

          主題

          今天想跟大家分享一個比較 "別扭" 的概念:“原型 & this”?。

          想把這玩意兒給說清楚,大多都會感到頭大。用的時候也會遇到些尷尬的場景。就很難去整明白,這到底是個啥。

          這一期,就試著將這 說個清楚,講個明白。開始~

          原型

          什么是?原型??帶著這個問題往下看。

          原型-構造器 (constructor)

          首先說到原型,那就跟對象密不可分。如果我們需要創(chuàng)建一個對象,就需要區(qū)定義一個object。那我們在開發(fā)中如何去創(chuàng)建一個對象?肯定有人會說,就是var 一個對象唄。很好你說的很對~ 確實是var 一個對象,那我如果需要兩個呢?這個時候又會說了,那就var兩個唄。很好,你又說對了~

          以下是創(chuàng)建對象的方法。

          code 創(chuàng)建對象

          var?zhangsan?=?{
          ?name:'張三'
          ????age:20
          }

          var?lisi?=?{
          ?name:'李四'
          ????age:22
          }


          那如果我們需要創(chuàng)建100個對象呢?程序員這么懶,不會去實打實的真的給你去 var 100個對象。當然如果真去這樣做了,里面的變量也是未知的。何況如果是一個動態(tài)創(chuàng)建的,也不能去給代碼寫死不是。

          好了,那這個時候,聰明的同學就已經想到了,搞一個 function 函數唄。專門生成對象,不就完事拉!

          code 創(chuàng)建對象

          function?User(name,?age)?{
          ????var?person?=?{}?//?定義一個person?對象
          ????person.name?=?name;?//?往對象中綁定傳參
          ????person.age?=?age;
          ????return?person?//?返回生成的新對象
          }

          var?zhangsan?=?User('張三',?20);
          var?lisi?=?User('李四',?22);


          以上的函數,就會生成你想要的任何對象,也稱之為:工廠函數?!一個專門造對象的工廠函數。

          好了,那么這樣做就可以了嗎?是不是發(fā)現了什么?

          對拉,js中,本身就有一種生產對象的方式啊,并且更簡單,不需要再函數中定義一個對象。只需要綁定 this 就可以了。

          code 創(chuàng)建對象

          function?User(name,?age)?{
          ??this.name?=?name;?//?這里面的this,就代表了即將生成的那個對象?,并且綁定傳參
          ??this.age?=?age;
          }

          var?zhangsan?=?new?User('張三',?20);
          var?lisi?=?new?User('李四',?22);


          這個時候,細心的同學已經發(fā)現了不同之處。兩個都是生成對象的函數,但是叫法就有些不同了。如果是用第二種 js 本身的函數,我們就需要用 new 關鍵字來生成對象。

          code 差異

          var?zhangsan?=??User('張三',?20);?//??第一種
          var?zhangsan?=?new?User('張三',?20);?//??第二種


          而這種需要用 new 關鍵字來叫的函數,稱之為:“構造器 constructor or 構造函數”

          而生成對象的這個過程,稱之為:實例化“zhangsan”?可以稱之為一個對象,也可以稱之為一個?實例

          原型-proto?& prototype

          好了,上一段說了構造器,那么構造器是干嘛的?就是造對象的一個函數呀。

          那這一段,來說說原型中的重頭戲。先看一段代碼:

          code 創(chuàng)建對象 在對象中添加一個功能屬性,可以引用自己的屬性 "greet"

          function?User(name,?age)?{
          ??this.name?=?name;?//?這里面的this,就代表了即將生成的那個對象?,并且綁定傳參
          ??this.age?=?age;
          ??this.greet?=?function?()?{
          ????console.log('你好,?我是'?+?this.name?+?',我'?+?this.age?+?'歲');
          ??}
          }

          var?zhangsan?=?new?User('張三',?20);
          var?lisi?=?new?User('李四',?22);

          zhangsan.greet()?//?你好我是張三,我20歲
          lisi.greet()?//?你好我是李四,我22歲

          這個時候,用生成的對象來叫一下?greet?這個方法,一點毛病沒有。但是有沒有同學發(fā)現什么問題?細心的同學已經發(fā)現了,這兩個都分別實例了greet !

          是不是有的同學有點沒理解這句話的意思?沒關系,接著看:

          code 實例化后引用 greet 差異對比

          zhangsan.greet?===?lisi.greet??//?false

          同學們,看到了什么?what? 這兩個不一樣?

          這意味著什么呢?也就是說 張三 和 李四,實例化之后,都在自己的內部,創(chuàng)造了 greet 這樣的屬性。

          這個時候,greet 的功能都是一模一樣的呀。如果實例100個對象,豈不是要拷100份?完全沒必要呀。有沒有什么方法將這些通用的屬性,放到一個地方呢?

          有的。接下來就要說到本段的重頭戲之一:prototype?了。在講之前,先看下面一段代碼:

          code 創(chuàng)建對象 自帶 prototype

          function?test1?()?{}
          console.log(?test1.prototype?)?//?{?constructor?:?f?}

          function?test2?()?{}
          console.log(?test2.prototype?)?//?{?constructor?:?f?}


          發(fā)現了什么?是不是每創(chuàng)建一個function,都會自帶一個?prototype?這樣的對象啊。這就是js 的原生機制。那為什么 js 的原生機制 要這么做呢?劃重點:prototype 就是給他即將生成的對象,繼承下去的屬性?看到了什么?prototype?他是一個屬性,是一個可供實例對象繼承下去的屬性。這不簡單了嗎。走一個。

          code 創(chuàng)建對象 在對象中添加一個功能屬性,可以引用自己的屬性 "greet"

          function?User(name,?age)?{
          ??this.name?=?name;?//?這里面的this,就代表了即將生成的那個對象?,并且綁定傳參
          ??this.age?=?age;
          }
          User.prototype.greet?=?function?()?{
          ??console.log('你好,?我是'?+?this.name?+?',我'?+?this.age?+?'歲');
          }

          var?zhangsan?=?new?User('張三',?20);
          var?lisi?=?new?User('李四',?22);

          zhangsan.greet()?===?lisi.greet() //?true


          既然知道了在構造函數中,使用?prototype?這樣的繼承對象,可以將?通用?的屬性給 實例化的對象繼承下去。

          那么說到這,是不是會有幾個問題?這個greet 并不是定義在實例化的對象里面的啊,來看一段代碼:

          code prototype

          function?User(name,?age)?{
          ??this.name?=?name;?//?這里面的this,就代表了即將生成的那個對象?,并且綁定傳參
          ??this.age?=?age;
          }
          User.prototype.greet?=?function?()?{
          ??console.log('你好,?我是'?+?this.name?+?',我'?+?this.age?+?'歲');
          }
          var?lisi?=?new?User('李四',?22);
          console.log(lisi);
          ??/*
          ??User?{}
          ??name:'李四'
          ??age?=?22
          ??__proto__
          ??greet:f()
          ??constructor?:?f?User?(name,?age)
          ??__proto__:Object
          ??...
          ??*/??????????

          看到了什么?是不是通過?prototype?定義的_greet = function ()_ 屬性跑到了?proto?下面去了。并且,這個greet屬性雖然沒有在自己本身的對象下面,但是一樣可以使用啊!我們上面說到過:prototype?是繼承屬性對象。那么看到這里的小伙伴,是不是會困惑,為什么繼承屬性會定義在?proto?下面?先別急。接著看!

          這個時候已經看到了重頭戲之二:proto。再來看一段代碼:

          code __proto__

          function?Test?()?{}
          Test.prototype.name?=?'test'
          var?test01?=?new?Test()
          var?test02?=?new?Test()
          test01.__proto__?===?test02.__proto__????//?true
          //?-----------------------?實例之后的對象調用__proto__指針指向的?等于被實例的構造函數的prototype!
          //?test01.__proto__?=?Test.prototype??//?true


          這時候,是不是已經恍然大悟了!原來通過prototype?定義的屬性,再被多個實例化之后,引用的地址是同一個!并且?proto?就是我們上面使用的prototype?屬性的馬甲啊!就是說,我們在構造函數中使用prototype?定義的屬性,都會被?proto?指針引用!

          好了,這個時候,可以整一段比較晦澀的總結了:每個對象都有一個?proto?的屬性,指向該對象的原型。實例后通過對?proto?屬性的訪問 去對 prototype對象進行訪問;原型鏈是由原型對象組成的,每個對象都有__proto__屬性,指向創(chuàng)建該對象的構造函數的原型 ,然后通過__proto__屬性將對象鏈接起來,組成一個原型鏈,用來實現繼承和共享屬性!

          理清楚以上關系后,可以想一下 通過prototype?定義的屬性作用就僅僅如此么?接著看一段代碼:

          code prototype

          function?Test?()?{}
          Test.prototype.name?=?'test'
          var?test01?=?new?Test()
          console.log(?test01.name?)?//?"test"
          Test.prototype.name?=?'no?test?'
          console.log(?test01.name?)?//?"no?test"


          看到了什么?原來?prototype?可以在實例之后,再進行更改呀!

          就是說,通過構造函數去改變name 的值,實例化之后的對象,引用的屬性值也會跟著變。太強大了!

          再來看看?constructor?:

          code constructor

          function?User(name,?age)?{
          ??this.name?=?name;?//?這里面的this,就代表了即將生成的那個對象?,并且綁定傳參
          ??this.age?=?age;
          }
          User.prototype.greet?=?function?()?{
          ??console.log('你好,?我是'?+?this.name?+?',我'?+?this.age?+?'歲');
          }
          var?lisi?=?new?User('李四',?22);

          //?再次構造
          var?zhangsan?=?new?lisi.constructor('張三', 20)?//?使用constructor來實例化!!!
          new?lisi.constructor()?===?new?User()??//?true
          console.log(zhangsan)
          /*
          ??User?{}
          ??name:'張三'
          ??age?=?20
          ??__proto__
          ??greet:f()
          ??constructor?:?f?User?(name,?age)
          ??__proto__:Object
          ??...
          ??*/??


          發(fā)現了嗎?就算我只能知道實例后的對象,但是我可以通過?proto?去找到這個實例對象的構造函數?constructor?,我再通過這個構造函數再去實例對象。(var zhangsan = new lisi.constructor('張三', 20))與我直接var zhangsan = new User('張三', 20)。完全一樣。真的很強大!

          好了,講到這,proto?& prototype?也就說完了,接下來再說說?原生對象的原型

          原型-原生對象的原型

          前面,知道了原型的概念,那就趁熱打鐵,接著看看原生對象的原型。

          先看一段代碼:

          code 原生對象

          ??var?a?={}
          ??console.log(a)
          ??/*
          ????{}
          ????__proto__
          ????greet:f()
          ????constructor?:?f?Object()
          ????...
          ????*/??


          可以看到,我們var 了一個新對象之后,沒有定義任何屬性,但是也能看到他的構造函數:Object()。也就是說:var a ={} === var a = new Object(),兩者沒有任何區(qū)別。舉個例子:

          code 原生對象

          ??var?a?={}
          ??var?b?=?new?Object()
          ??console.log(a.constructor?===?b.constructor?)?//?true


          可以看到,構造函數完全一樣。

          那么這個時候,可能會有同學想問,怎么去創(chuàng)造一個干凈的對象呢?里面沒有任何集成的屬性等。

          當然也是可以的。接著看:

          code 原生對象

          ? var a = new Object.create(null)?//?創(chuàng)建函數必須傳參,一個對象或者是 null ,否則會報錯!
          ??console.log(?a?)
          ??/*
          ????no?prototies?
          ????*/??


          可以看到,通過?Object.create()?創(chuàng)建的對象,屬性為空。這個時候,肯定會有同學有疑問,你這傳的參數是 null,那當然什么都沒有了,你傳個對象試試。哈哈哈,確實,如果傳對象的話,那就是定義自己所自帶的原型了。舉個例子:

          code 原生對象

          ??var?a?=?new?Object.create({name:juejin,des:"666"})?//?創(chuàng)建函數必須傳參,一個對象或者是 null ,否則會報錯!
          ??console.log(?a?)
          ??/*
          ????{}
          ????__proto__
          ????name:juejin
          ????des:"666"
          ??????__proto__
          ??????constructor?:?f?Object()
          ??????...
          ????*/???


          可以看到,再Object.create()?中傳入對象的屬性,是放在第一層的?proto?下面的,也就是中,這是你創(chuàng)建的這個原型對象的繼承屬性,意味著,可以根據自身的業(yè)務需求,來定義自己的原型對象!

          多級繼承鏈

          好了,上面已經詳細的講解了原型鏈,構造函數,那么就試著來實現一個繼承鏈。看下面代碼:

          code 繼承鏈 從祖父 到爺爺 到爸爸 到自己

          //?Animal?-->?Mammal?-->?Person?-->?me
          //?Animal?
          function?Animal(color,?weight)?{
          ??this.color?=?color;
          ??this.weight?=?weight;
          }
          Animal.prototype.eat?=?function?()?{
          ??console.log('吃飯');
          }

          Animal.prototype.sleep?=?function?()?{
          ??console.log('睡覺');
          }
          ?//??Mammal
          function?Mammal(color,?weight)?{
          ??Animal.call(this,?color,?weight);?//綁定?this?這個下面講
          }

          Mammal.prototype?=?Object.create(Animal.prototype);
          Mammal.prototype.constructor?=?Mammal;
          Mammal.prototype.suckle?=?function?()?{
          ??console.log('喝牛奶');
          }
          //??Person
          function?Person(color,?weight)?{
          ??Mammal.call(this,?color,?weight);
          }

          Person.prototype?=?Object.create(Mammal.prototype);
          Person.prototype.constructor?=?Person;
          Person.prototype.lie?=?function?()?{
          ??console.log('你是個騙子');
          }
          //?實例
          var?zhangsan?=?new?Person('brown',?100);
          var?lisi?=?new?Person('brown',?80);
          console.log('zhangsan:',?zhangsan);
          console.log('lisi:',?lisi);??
          ????


          上面的代碼中,實現了三級繼承。其中,使用了我們上面講到的?prototype?以及?Object.create()?。

          code

          function?Animal(color,?weight)?{
          ??this.color?=?color;
          ??this.weight?=?weight;
          }
          Animal.prototype.eat?=?function?()?{
          ??console.log('吃飯');
          }


          往祖父類中寫入繼承屬性,eat 供爺爺輩來繼承這個吃的屬性。

          code

          //??Mammal
          ??function?Mammal(color,?weight)?{
          ????Animal.call(this,?color,?weight);?//綁定?this?這個下面講
          ??}
          Mammal.prototype?=?Object.create(Animal.prototype);
          Mammal.prototype.constructor?=?Mammal;
          Mammal.prototype.suckle?=?function?()?{
          ??console.log('喝牛奶');
          }


          同時,爺爺輩的屬性,需要繼承祖父輩的其他屬性,因為上面有講到:prototype?是繼承屬性,也可以稱之為隱性屬性。那么?color, weight?這些顯性屬性怎么給他繼承過來呢?

          這個時候就用上了上面的?Mammal.prototype = Object.create(Animal.prototype);?這就是利用?Object.create()?來將祖父的其他顯性屬性,全部繼承到爺爺輩。并且再寫進爺爺輩的?prototype?中,方便再往下給爸爸繼承。

          這樣一級一級的綁定,構建,就實現了所謂的?多級繼承?了。

          當然細心的同學又發(fā)現了一個點:

          code

          ?//??Mammal
          function?Mammal(color,?weight)?{
          ??Animal.call(this,?color,?weight);?//綁定?this?
          }


          為什么這邊的爺爺輩的構造器里面為什么要?call this 呢??,這邊就先賣個關子,下面this那段會講到!嘿嘿~

          原型總結

          好了,講了這么多,終于說完了原型鏈。其實一圖勝千言。

          引用上面的一句話:每個對象都有一個?proto?的屬性,指向該對象的原型。實例后通過對?proto?屬性的訪問 去對 prototype對象進行訪問;原型鏈是由原型對象組成的,每個對象都有__proto__屬性,指向創(chuàng)建該對象的構造函數的原型 ,然后通過__proto__屬性將對象鏈接起來,組成一個原型鏈,用來實現繼承和共享屬性!

          說到這,原型鏈也就說完了,接下來再啃一塊硬骨頭:this

          this

          其實說到?this,大家都有這樣的一個感覺,就是一看就會,一用就亂。那么這個this?到底是個啥?能不能給它整明白?別急,

          先來看一段代碼:

          code

          var?User?=?{
          ?fname:'三'
          ?????lname:'張'
          ?????fullname:function(){
          ??????return?User.lname?+?User.fname
          ?????}
          ??}
          ?console.log(User.fullname)?//?"張三"


          這段代碼是去獲取?User?對象下的全名,可以看到是沒什么問題。那么這個時候,需要給這個對象換成person對象,會發(fā)生什么呢?

          code

          var?Person?=?{
          ?fname:'三'
          ?????lname:'張'
          ?????fullname:function(){
          ??????return?User.lname?+?User.fname
          ?????}
          ??}
          ?console.log(Person.fullname)?//?User?is?not?defined


          看到了什么,找不到這個?User,這是為什么呢?很明顯,是因為我們再return?中,返回的還是?User?這個對象,但是這個時候,我已經將原來的?User?改成?Person?了。所以,如果這段代碼想生效,必須也要將?return?中的?User?對象 改成?Person?對象。

          麻不麻煩?可重用性也太低了。那么這個時候,this 就派上用場了。接著看:

          code

          var?Person?=?{
          ?fname:'三'
          ?????lname:'張'
          ?????fullname:function(){
          ??????return?this.lname?+?this.fname
          ?????}
          ??}
          ?console.log(Person.fullname)?//?"張三"


          這時候,就能看到,我對象名改成了Person,是一樣可以拿到這個對象下的?fullname

          是不是有同學會問了,這是為什么?其實這個時候,這里面的this,就指向了這個fullname的?fnc?外的Person對象了。是不是覺得說的有點干,那我們就來看看:

          code

          var?Person?=?{
          ?fname:'三'
          ?????lname:'張'
          ?????fullname:function(){
          ???????? console.log(this)?//?在哪邊引用this,就在哪邊看!
          ??????return?this.lname?+?this.fname
          ?????}
          ??}
          /*
          fname:'三'
          lname:'張'
          fullname:f()
          __proto__
          ??????constructor?:?f?Object()
          ??????...
          */


          這樣看,是不是十分清晰明了。其實也就是說,我在?fullname?這個方法中使用的?this?就是指向了,我當前這個?function?代碼塊的上一級。

          看到這,是不是感覺明白了?再來:

          code

          var?Person?=?{
          ?fname:'三'
          ?????lname:'張'
          ?????fullname:function(){
          ??????return?this.lname?+?this.fname
          ?????}
          ??}
          var??getfullname?=?Person.fullname?//?將Person對象中的fullname?方法,給到新定義的參數使用
          console.log(getfullname())?//?NAN


          這是什么?沒拿到?張三??這是為啥?

          到這里是不是一下子又懵了?這個?this?到底有多少幺蛾子。打印出來看看,這個時候的?this到底是什么:

          code

          var?Person?=?{
          ?fname:'三'
          ?????lname:'張'
          ?????fullname:function(){
          ?????????console.log(this)?
          ??????return?this.lname?+?this.fname
          ?????}
          ??}
          var??getfullname?=?Person.fullname?//?將Person對象中的fullname?方法,給到新定義的參數使用
          console.log(getfullname())?//?window:{},NAN


          看到什么了?這個?this?竟然指向了window,全局變量。這是咋回事?這就是?this?坑的地方,我上面說到:this?就是指向了,我當前這個?function?代碼塊的上一級。其實這句話,在這邊就直接錯了。因為this引用沒變。只是我的調用方式變了。

          所以這個時候,這句話要重新描述,謹記:this 并不取決于它所在的位置,而是取決于它所在的function是怎么被調用的!!!

          而上面?console.log(Person.fullname) // "張三"?可以打印出結果,就是fullname的這個方法,直接被它的父級調用了,也就是說這個時候的?this?是指向的?Person

          而如果指定調用這個?this?的,并不是直接父級,那么再非嚴格模式下,指向的就是全局?window,而在嚴格模式下則是?undefined

          再來 如果?this?再構造函數中被調用,會是怎么樣?看下面一段代碼 (嚴格模式下):

          code

          "use strict";function User (){ console.log(this)}User()?//?undefined?new?User?()?//?User?{}

          這個時候,可以看到,如果?this?是放在構造函數中,被直接調用?User (),那么這個時候的?this?就是?undefined?。因為?this?所在的?function?并沒有作為一個方法被調用。

          而 如果是通過?new?的方式被調用的,那么這個時候,?this?所在的?function?就被調用了,并且指向的就是被調用的?User {}?。還記得我們上面說的,js 本身的構造函數機制嗎?再來復習一下:

          code 創(chuàng)建對象 "

          function?User(name,?age)?{
          ??this.name?=?name;?//?這里面的this,就代表了即將生成的那個對象?,并且綁定傳參
          ??this.age?=?age;
          }


          就是說:構造函數中的 this ,就是指向即將實例化的那個對象。謹記!

          所以 總結一下?this?的三種場景:

          1.?如果this?是?在一個函數中,并且被用作方法來叫,那么這個時候的?this?就指向了父級對象;
          2. 如果this 是在匿名函數,或者全局環(huán)境的函數中,那么這個時候的 this 就是;undefined;
          3.?如果this?是在構造函數中,那么這個時候的?this?就指向了即將生成的那個對象


          好了,既然區(qū)分了?this?的使用場景之后,那么它的強大之處是什么呢?舉個例子:

          code 動態(tài)綁定 this

          function?introduction()?{
          ??console.log('你好,?我是'?+?this.name);
          }

          var?zhangsan?=?{
          ??name:?'張三',
          }

          var?lisi?=?{
          ??name:?'李四',
          }

          zhangsan.introduction?=?introduction;
          lisi.introduction?=?introduction;

          zhangsan.introduction();?//??你好,我是張三
          lisi.introduction();??//??你好,我是李四


          上面可以看到,定義了一個方法,這個方法中使用了?this.name?,但是這個時候,并不知道,這個方法中的?this?到底指向的是誰,而是等待著誰來調用它。回憶一下上面說的那句話:this 并不取決于它所在的位置,而是取決于它所在的function是怎么被調用的!!!

          而這個時候,定義了 張三 和 李四 兩個對象,這兩個對象,分別將定義的?introduction?賦值到本身的對象下面,也就是說,這個時候, 張三 和 李四 兩個對象,都擁有了?introduction這個方法,并且調用了。所以,這個時候的?function introduction()?已經擁有了被調用的對象,所以其中的?this.name?也就分別指向了這兩個對象的中name。

          好,以上就是將?this?的默認指向講完了。但是是不是有個問題,還沒解決?

          那就是我們之前在說?多級繼承?的時候,有個?call this?。這個賣的關子 還沒說呢?那接下來就講講。關于?this?改變它的默認指向,綁定一個我想要綁定的環(huán)境,行不行?

          bind & apply & call

          好了,這一段,就接著上面的講,這里會講到關于?this?的三種綁定方法。先來看代碼:

          code 動態(tài)綁定 this

          function?introduction()?{
          ??console.log('你好,?我是'?+?this.name);
          }
          introduction()?//?你好,?我是?undefined


          這個結果相信大家不會陌生,因為就是上面講的第二種情況:2. 如果this 是在匿名函數,或者全局環(huán)境的函數中,那么這個時候的 this 就是;undefined

          這里普及一個知識:introduction() === introduction.call() 只是前者是后者的簡寫!并且call()中的第一個傳參可以指定這個函數中的 this 指向誰!

          好了,知道這個知識點,再看下面的代碼:

          code 動態(tài)綁定 this

          function?introduction()?{
          ??console.log('你好,?我是'?+?this.name);
          }
          var?zhangsan?=?{
          ?name:'張三'
          }
          introduction.call(zhangsan)?//?你好,?我是?張三


          看完是不是一目了然,這個call()里面?zhèn)鞯膮担赶蛄?zhangsan?這個對象。那這不就是給這個?introduction?方法指定了調用的父級了嗎?this?也就指向給調用這個方法的?zhangsan了呀!

          說到這是不是就能清楚的知道,這個跟上面 在對象中,來綁定這個方法,來關聯父級調用關系,是一樣的。一個是對象引用方法,這個就是方法綁定對象呀!

          好,再來:

          code 動態(tài)綁定 this

          function?introduction(name)?{
          ??console.log('你好,'+?name?+'?我是'?+?this.name);
          }
          var?zhangsan?=?{
          ?name:'張三'
          }
          introduction.call(zhangsan,"李四")?//?你好?李四,?我是?張三


          可以看到call() 除了可以指定this指向的對象,還可以傳一些其他的參數。

          好了,說到這,是不是已經能猜到:bind & apply?怎么用拉!

          大同小異:

          code 動態(tài)綁定 this

          function?introduction(name)?{
          ??console.log('你好,'+?name?+'?我是'?+?this.name);
          }
          var?zhangsan?=?{
          ?name:'張三'
          }??
          introduction.call(zhangsan,"李四")???//?你好?李四,?我是?張三???call
          introduction.apply(zhangsan,["李四"])???//?你好?李四,?我是?張三???apply
          intro?=?introduction.bind(zhangsan)
          intro("李四")//?你好?李四,?我是?張三???bind


          可以看到,call() 和 apply() 區(qū)別就在于,后面的傳參的格式是:數組的形式;

          而 bind() 則是返回一個綁定新環(huán)境的 function,等著被調用。

          結語

          好啦,這期關于?“原型” & “this”?的內容就全部說完了,看到這,就兩個字:“透徹”

          瀏覽 58
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲中文字幕网站 | 日韩一级片在线播放 | 一卡二卡无码 | 亚洲综合国产 | 亚洲视频在线a |