整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢(xún)熱線:

          React組件之巔- JavaScript界的寵兒

          React組件之巔: JavaScript界的寵兒

          今天的JavaScript世界中,有一股風(fēng)頭如熱鋒在飛,那就是React,尤其是它強(qiáng)大的Component機(jī)制,它在前端開(kāi)發(fā)界以靈活、高效和愉悅的體驗(yàn)吸引了前端開(kāi)發(fā)者出現(xiàn)一頓風(fēng)results。今天,讓我們一起看看React中的巔峰之lassmac——組件,并探討一下為何這個(gè)功能擁有這么高的相信空間。


          一、初識(shí)React組件

          React是一個(gè)開(kāi)源的JavaScript庫(kù),由Facebook開(kāi)發(fā),旨在構(gòu)建用戶(hù)界面。React的核心是基于組件的開(kāi)發(fā)模型,組件是獨(dú)立且可復(fù)用的HTML片段,它們可以傳遞狀態(tài)和事件回調(diào),能夠讓?xiě)?yīng)用程序的UI和數(shù)據(jù)保持同步。

          二、React組件的特點(diǎn)

          1. 可復(fù)用性和組織能力:組件在React中是可復(fù)用的,可以讓開(kāi)發(fā)者將復(fù)雜的應(yīng)用拆分為簡(jiǎn)單的組件,然后再將這些組件組合在一起。此外,組件的開(kāi)發(fā)過(guò)程也可以獨(dú)立,避免了項(xiàng)目中的Component-related代碼混亂。
          2. 擁有唯一的狀態(tài)管理機(jī)制:組件內(nèi)的狀態(tài)(state)是私有的,開(kāi)發(fā)者可以通過(guò)props(屬性)來(lái)傳遞。狀態(tài)的變更觸發(fā)情況會(huì)使得Jsx運(yùn)行(Xanthus)再一次渲染。這內(nèi)支持了狀態(tài)的局部性。
          3. 簡(jiǎn)潔高效的語(yǔ)法和接口:React的組件基于JavaScript原生功能實(shí)現(xiàn),因此同時(shí)實(shí)現(xiàn)簡(jiǎn)潔和高效。開(kāi)發(fā)者可以用es6的箭頭函數(shù)、arrow functions,編寫(xiě)輕松的、易讀的代碼。

          三、React組件的制作方法

          1. 聲明式組件:這是React中最常見(jiàn)的組件類(lèi)型,可以簡(jiǎn)要地定義一個(gè)通過(guò)ibling狀態(tài)(state)和屬性(props)管理的個(gè)體組件。
          2. 類(lèi)式組件:可以使用JavaScript的class關(guān)鍵字來(lái)定義組件,利用類(lèi)中的方法來(lái)實(shí)現(xiàn)組件的生命周期函數(shù)。
          3. 函數(shù)式組件:利用React Hooks API,開(kāi)發(fā)者可以通過(guò)以函數(shù)而非類(lèi)來(lái)編寫(xiě)組件,使代碼更簡(jiǎn)潔。
          4. 高階組件:高階組件是一種函數(shù)組件,它接收一個(gè)組件作為參數(shù),然后返回一個(gè)新組件,該組件把需要的 props 傳遞進(jìn)參數(shù)組件,并獲取 rendered 結(jié)果。

          讀前建議先了解以下知識(shí)點(diǎn):

          • 理解 JavaScript 中的 this 關(guān)鍵字
          • JavaScript 對(duì)象概念
          • JavaScript 閉包概念


          如果你對(duì)前面提到的先備知識(shí)有所了解, 你應(yīng)該知道 JavaScript 中的函數(shù)其實(shí)是一種對(duì)象。 而作為對(duì)象, 函數(shù)是可以有方法的, 包括非常強(qiáng)大的 `Apply`, `Call`以及 `Bind` 方法。一方面, Apply 方法和 Call 方法的用途幾乎相同, 在 JavaScript 中被頻繁使用于方法借用和明確 this 關(guān)鍵字指向等場(chǎng)景. 我們也將 Apply 用于參數(shù)可變的函數(shù); 在后文中你將會(huì)對(duì)此有更多的了解。 另一方面, 我們會(huì)使用 Bind 來(lái)給方法指定 this 指向值或者函數(shù)柯里化 (currying functions)。

          我們會(huì)討論在 JavaScript 中使用這三種方法的每一個(gè)場(chǎng)景。 Apply 和 Call 方法是在 ECMAScript 3 標(biāo)準(zhǔn)中出現(xiàn)的(可以在IE 6, 7, 8 以及現(xiàn)代瀏覽器中使用), ECAMScript 5 標(biāo)準(zhǔn)添加了 Bind 這個(gè)方法。由于三種方法都非常強(qiáng)大, 開(kāi)發(fā)時(shí)你一定會(huì)用到其中一個(gè)。讓我們先從 Bind 方法說(shuō)起。

          Bind 方法

          我們用 Bind() 來(lái)實(shí)現(xiàn)在指明函數(shù)內(nèi)部 this 指向的情況下去調(diào)用該函數(shù), 換句話說(shuō), bind() 允許我們非常簡(jiǎn)單的在函數(shù)或者方法被調(diào)用時(shí)綁定 this 到指定對(duì)象上。

          當(dāng)我們?cè)谝粋€(gè)方法中用到了 this, 而這個(gè)方法調(diào)用于一個(gè)接收器對(duì)象, 我們會(huì)需要使用到 bind() 方法; 在這種情況下, 由于 this 不一定完全如我們所期待的綁定在目標(biāo)對(duì)象上, 程序有時(shí)便會(huì)出錯(cuò)。

          Bind 允許我們明確指定方法中的 this 指向

          當(dāng)以下按鈕被點(diǎn)擊的時(shí)候, 文本輸入框會(huì)被隨機(jī)填入一個(gè)名字。

          ```

          // <button>Get Random Person</button>

          // <input type="text">

          var user={

          data :[

          {name:"T. Woods", age:37},

          {name:"P. Mickelson", age:43}

          ],

          clickHandler:function(event) {

          var randomNum=((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1

          // 從 data 數(shù)組中隨機(jī)選取一個(gè)名字填入 input 框內(nèi)

          $("input").val(this.data[randomNum].name + " " + this.data[randomNum].age);

          }

          }

          // 給點(diǎn)擊事件添加一個(gè)事件處理器

          $("button").click(user.clickHandler);

          ```



          當(dāng)你點(diǎn)擊按鈕時(shí), 會(huì)發(fā)現(xiàn)一個(gè)報(bào)錯(cuò)信息: 因?yàn)?clickHandler() 方法中的 this 綁定的是按鈕 HTML 內(nèi)容的上下文, 因?yàn)檫@才是 clickHandler 方法的執(zhí)行時(shí)的調(diào)用對(duì)象。

          在 JavaScript 中這種問(wèn)題比較常見(jiàn), JavaScript 框架中例如 Backbone.js, jQuery 都自動(dòng)為我們做好了綁定的工作, 所以在使用時(shí) this 總是可以綁定到我們所期望的那個(gè)對(duì)象上。

          為了解決之前例子中存在的問(wèn)題, 我們利用 bind() 方法將 `$("button").click(user.clickHandler);` 換成以下形式:

          ```

          $("button").click(user.clickHandler.bind(user));

          ```

          Tips: 再考慮另一個(gè)方法來(lái)修復(fù) this 的值: 你可以給 click() 方法傳遞一個(gè)匿名回調(diào)函數(shù), jQuery 會(huì)將匿名函數(shù)的 this 綁定到按鈕對(duì)象上.bind() 函數(shù)在 ECMA-262 第五版才被加入;它可能無(wú)法在所有瀏覽器上運(yùn)行。你可以部份地在腳本開(kāi)頭加入以下代碼,就能使它運(yùn)作,讓不支持的瀏覽器也能使用 bind() 功能。

          ```

          if (!Function.prototype.bind) {

          Function.prototype.bind=function(oThis) {

          if (typeof this !=="function") {

          // closest thing possible to the ECMAScript 5

          // internal IsCallable function

          throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");

          }

          var aArgs=Array.prototype.slice.call(arguments, 1),

          fToBind=this, // 此處的 this 指向目標(biāo)函數(shù)

          fNOP=function() {},

          fBound=function() {

          return fToBind.apply(this instanceof fNOP

          ? this // 此處 this 為 調(diào)用 new obj() 時(shí)所生成的 obj 本身

          : oThis || this, // 若 oThis 無(wú)效則將 fBound 綁定到 this

          // 將通過(guò) bind 傳遞的參數(shù)和調(diào)用時(shí)傳遞的參數(shù)進(jìn)行合并, 并作為最終的參數(shù)傳遞

          aArgs.concat(Array.prototype.slice.call(arguments)));

          };

          // 將目標(biāo)函數(shù)的原型對(duì)象拷貝到新函數(shù)中,因?yàn)槟繕?biāo)函數(shù)有可能被當(dāng)作構(gòu)造函數(shù)使用

          fNOP.prototype=this.prototype;

          fBound.prototype=new fNOP();

          return fBound;

          };

          }

          ```

          繼續(xù)之前的例子, 如果我們將包含 this 的方法賦值給一個(gè)變量, 那么 this 的指向也會(huì)綁定到另一個(gè)對(duì)象上, 如下所示:

          ```

          // 全局變量 data

          var data=[

          {name:"Samantha", age:12},

          {name:"Alexis", age:14}

          ]

          var user={

          // 局部變量 data

          data :[

          {name:"T. Woods", age:37},

          {name:"P. Mickelson", age:43}

          ],

          showData:function(event) {

          var randomNum=((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1

          console.log(this.data[randomNum].name + " " + this.data[randomNum].age);

          }

          }

          // 將 user 對(duì)象的 showData 方法賦值給一個(gè)變量

          var showDataVar=user.showData;

          showDataVar(); // Samantha 12 (來(lái)自全局變量數(shù)組而非局部變量數(shù)組)

          ```

          當(dāng)我們執(zhí)行 showDataVar() 函數(shù)時(shí), 輸出到 console 的數(shù)值來(lái)自全局 data 數(shù)組, 而不是 user 對(duì)象. 這是因?yàn)?showDataVar() 函數(shù)是被當(dāng)做一個(gè)全局函數(shù)執(zhí)行的, 所以在函數(shù)內(nèi)部 this 被綁定位全局對(duì)象, 即瀏覽器中的 window 對(duì)象。

          來(lái), 我們用 bind 方法來(lái)修復(fù)這個(gè) bug。

          ```

          // Bind the showData method to the user object

          var showDataVar=user.showData.bind(user);

          ```

          Bind 方法允許我們實(shí)現(xiàn)函數(shù)借用

          在 JavaScript 中, 我們可以傳遞函數(shù), 返回函數(shù), 借用他們等等, 而 bind() 方法使函數(shù)借用變得極其簡(jiǎn)單. 以下為一個(gè)函數(shù)借用的例子:

          ```

          // cars 對(duì)象

          var cars={

          data:[

          {name:"Honda Accord", age:14},

          {name:"Tesla Model S", age:2}

          ]

          }

          // 我們從之前定義的 user 對(duì)象借用 showData 方法

          // 這里我們將 user.showData 方法綁定到剛剛新建的 cars 對(duì)象上

          cars.showData=user.showData.bind(cars);

          cars.showData(); // Honda Accord 14

          ```

          這里存在一個(gè)問(wèn)題, 當(dāng)我們?cè)?cars 對(duì)象上添加一個(gè)新方法(showData)時(shí)我們可能不想只是簡(jiǎn)單的借用一個(gè)函數(shù)那樣, 因?yàn)?cars 本身可能已經(jīng)有一個(gè)方法或者屬性叫做 showData 了, 我們不想意外的將這個(gè)方法覆蓋了. 正如在之后的 *Apply 和 Call 方法* 章節(jié)我們會(huì)介紹, 借用函數(shù)的最佳實(shí)踐應(yīng)該是使用 Apply 或者 Call 方法。

          Bind 方法允許我們柯里化一個(gè)函數(shù)

          柯里化的概念很簡(jiǎn)單, 只傳遞給函數(shù)一部分參數(shù)來(lái)調(diào)用它, 讓它返回一個(gè)函數(shù)去處理剩下的參數(shù). 你可以一次性地調(diào)用 curry 函數(shù), 也可以每次只傳一個(gè)參數(shù)分多次調(diào)用, 以下為一個(gè)簡(jiǎn)單的示例. - [JS 函數(shù)是編程指南 第 4 章: 柯里化(curry)](https://llh911001.gitbooks.io/mostly-adequate-guide-chinese/content/ch4.html)

          ```

          var add=function(x) {

          return function(y) {

          return x + y;

          };

          };

          var increment=add(1);

          var addTen=add(10);

          increment(2);

          // 3

          addTen(2);

          // 12

          ```

          現(xiàn)在, 我們使用 bind() 方法來(lái)實(shí)現(xiàn)函數(shù)的柯里化. 我們首先定義一個(gè)接收三個(gè)參數(shù)的 greet() 函數(shù):

          ```

          function greet(gender, age, name) {

          // if a male, use Mr., else use Ms.

          var salutation=gender==="male" ? "Mr. " : "Ms. ";

          if (age > 25) {

          return "Hello, " + salutation + name + ".";

          }

          else {

          return "Hey, " + name + ".";

          }

          }

          ```

          接著我們使用 bind() 方法柯里化 greet() 方法. bind() 接收的第一個(gè)參數(shù)指定了 this 的值:

          ```

          // 在 greet 函數(shù)中我們可以傳遞 null, 因?yàn)楹瘮?shù)中并未使用到 this 關(guān)鍵字

          var greetAnAdultMale=greet.bind (null, "male", 45);

          greetAnAdultMale("John Hartlove"); // "Hello, Mr. John Hartlove."

          var greetAYoungster=greet.bind(null, "", 16);

          greetAYoungster("Alex"); // "Hey, Alex."

          greetAYoungster("Emma Waterloo"); // "Hey, Emma Waterloo."

          ```

          當(dāng)我們用 bind() 實(shí)現(xiàn)柯里化時(shí), greet() 函數(shù)參數(shù)中除了最后一個(gè)參數(shù)都被預(yù)定義好了, 所以當(dāng)我們調(diào)用柯里化后的新函數(shù)時(shí)只需要指定最后一位參數(shù)。

          所以小結(jié)一下, bind() 方法允許我們明確指定對(duì)象方法中的 this 指向, 我們可以借用, 復(fù)制一個(gè)方法或者將方法賦值為一個(gè)可作為函數(shù)執(zhí)行的變量. 我們以可以借用 bind 實(shí)現(xiàn)函數(shù)柯里化。

          JavaScript 中的 Apply 和 Call 方法

          作為 JavaScript 中最常用的兩個(gè)函數(shù)方法, apply 和 call 允許我們借用函數(shù)以及在函數(shù)調(diào)用中指定 this 指向. 除此外, apply 函數(shù)允許我們?cè)趫?zhí)行函數(shù)時(shí)傳入一個(gè)參數(shù)數(shù)組, 以此使函數(shù)在執(zhí)行可變參數(shù)的函數(shù)時(shí)可以將每個(gè)參數(shù)單獨(dú)的傳入函數(shù)并得到處理。

          使用 apply 或者 call 設(shè)置 this

          當(dāng)我們使用 apply 或者 call 時(shí), 傳入的第一個(gè)參數(shù)為目標(biāo)函數(shù)中 this 指向的對(duì)象, 以下為一個(gè)簡(jiǎn)單的例子:

          ```

          // 全局變量

          var avgScore="global avgScore";

          // 全局函數(shù)

          function avg(arrayOfScores) {

          // 分?jǐn)?shù)相加并返回結(jié)果

          var sumOfScores=arrayOfScores.reduce(function(prev, cur, index, array) {

          return prev + cur;

          });

          // 這里的 "this" 會(huì)被綁定到全局對(duì)象上, 除非使用 Call 或者 Apply 明確指定 this 的指向

          this.avgScore=sumOfScores / arrayOfScores.length;

          }

          var gameController={

          scores :[20, 34, 55, 46, 77],

          avgScore:null

          }

          // 調(diào)用 avg 函數(shù), this 指向 window 對(duì)象

          avg(gameController.scores);

          // 證明 avgScore 已經(jīng)被設(shè)置為 window 對(duì)象的屬性

          console.log(window.avgScore); // 46.4

          console.log(gameController.avgScore); // null

          // 重置全局變量

          avgScore="global avgScore";

          // 使用 call() 方法明確將 "this" 綁定到 gameController 對(duì)象

          avg.call(gameController, gameController.scores);

          console.log(window.avgScore); // 全局變量 avgScore 的值

          console.log(gameController.avgScore); // 46.4

          ```

          以上例子中 call() 中的第一個(gè)參數(shù)明確了 this 的指向, 第二參數(shù)被傳遞給了 avg() 函數(shù).

          apply 和 call 的用法幾乎相同, 唯一的差別在于當(dāng)函數(shù)需要傳遞多個(gè)變量時(shí), apply 可以接受一個(gè)數(shù)組作為參數(shù)輸入, call 則是接受一系列的單獨(dú)變量.。

          在回掉函數(shù)中用 call 或者 apply 設(shè)置 this

          以下為一個(gè)例子, 這種做法允許我們?cè)趫?zhí)行 callback 函數(shù)時(shí)能夠明確 其內(nèi)部的 this 指向

          ```

          // 定義一個(gè)方法

          var clientData={

          id: 094545,

          fullName: "Not Set",

          // clientData 對(duì)象中的一個(gè)方法

          setUserName: function (firstName, lastName) {

          this.fullName=firstName + " " + lastName;

          }

          }

          function getUserInput(firstName, lastName, callback, callbackObj) {

          // 使用 apply 方法將 "this" 綁定到 callbackObj 對(duì)象

          callback.apply(callbackObj, [firstName, lastName]);

          }

          ```

          如下樣例中傳遞給 callback 函數(shù) 中的參數(shù)將會(huì)在 clientData 對(duì)象中被設(shè)置/更新。

          ```

          getUserInput("Barack", "Obama", clientData.setUserName, clientData);

          console.log(clientData.fullName); // Barack Obama

          ```

          使用 Apply 或者 Call 借用函數(shù)(必備知識(shí))

          相比 bind 方法, 我們使用 apply 或者 call 方法實(shí)現(xiàn)函數(shù)借用能夠有很大的施展空間. 接下來(lái)我們考慮從 Array 中借用方法的問(wèn)題, 讓我們定義一個(gè)**類(lèi)數(shù)組對(duì)象(array-like object)**然后從數(shù)組中借用方法來(lái)處理我們定義的這個(gè)對(duì)象, 不過(guò)在這之前請(qǐng)記住我們要操作的是一個(gè)對(duì)象, 而不是數(shù)組;

          ```

          // An array-like object: note the non-negative integers used as keys

          var anArrayLikeObj={0:"Martin", 1:78, 2:67, 3:["Letta", "Marieta", "Pauline"], length:4 };

          ```

          接下來(lái)我們可以這樣使用數(shù)組的原生方法:

          ```

          // Make a quick copy and save the results in a real array:

          // First parameter sets the "this" value

          var newArray=Array.prototype.slice.call(anArrayLikeObj, 0);

          console.log(newArray); // ["Martin", 78, 67, Array[3]]

          // Search for "Martin" in the array-like object

          console.log(Array.prototype.indexOf.call(anArrayLikeObj, "Martin")===-1 ? false : true); // true

          // Try using an Array method without the call () or apply ()

          console.log(anArrayLikeObj.indexOf("Martin")===-1 ? false : true); // Error: Object has no method 'indexOf'

          // Reverse the object:

          console.log(Array.prototype.reverse.call(anArrayLikeObj));

          // {0: Array[3], 1: 67, 2: 78, 3: "Martin", length: 4}

          // Sweet. We can pop too:

          console.log(Array.prototype.pop.call(anArrayLikeObj));

          console.log(anArrayLikeObj); // {0: Array[3], 1: 67, 2: 78, length: 3}

          // What about push?

          console.log(Array.prototype.push.call(anArrayLikeObj, "Jackie"));

          console.log(anArrayLikeObj); // {0: Array[3], 1: 67, 2: 78, 3: "Jackie", length: 4}

          ```

          這樣的操作使得我們定義的對(duì)象既保留有所有對(duì)象的屬性, 同時(shí)也能夠在對(duì)象上使用數(shù)組方法.。

          **arguments** 對(duì)象是所有 JavaScript 函數(shù)中的一個(gè)類(lèi)數(shù)組對(duì)象, 因此 call() 和 apply() 的一個(gè)最常用的用法是從 arguments 中提取參數(shù)并將其傳遞給一個(gè)函數(shù)。

          以下為 Ember.js 源碼中的一部分, 加上了我的一些注釋:

          ```

          function transitionTo(name) {

          // 因?yàn)?arguments 是一個(gè)類(lèi)數(shù)組對(duì)象, 所以我們可以使用 slice()來(lái)處理它

          // 參數(shù) "1" 表示我們返回一個(gè)從下標(biāo)為1到結(jié)尾元素的數(shù)組

          var args=Array.prototype.slice.call(arguments, 1);

          // 添加該行代碼用于查看 args 的值

          console.log(args);

          // 注釋本例不需要使用到的代碼

          //doTransition(this, name, this.updateURL, args);

          }

          // 使用案例

          transitionTo("contact", "Today", "20"); // ["Today", "20"]

          ```

          以上例子中, args 變量是一個(gè)真正的數(shù)組. 從以上案例中我們可以寫(xiě)一個(gè)得到快速得到傳遞給函數(shù)的所有參數(shù)(以數(shù)組形式)的函數(shù):

          ```

          function doSomething() {

          var args=Array.prototype.slice.call(arguments);

          console.log(args);

          }

          doSomething("Water", "Salt", "Glue"); // ["Water", "Salt", "Glue"]

          ```

          考慮到字符串是不可變的, 如果使用 apply 或者 call 方法借用字符串的方法, 不可變的數(shù)組操作對(duì)他們來(lái)說(shuō)才是有效的, 所以你不能使用類(lèi)似 reverse 或者 pop 等等這類(lèi)的方法. 除此外, 我們也可以用他們借用我們自定義的方法。

          ```

          var gameController={

          scores :[20, 34, 55, 46, 77],

          avgScore:null,

          players :[

          {name:"Tommy", playerID:987, age:23},

          {name:"Pau", playerID:87, age:33}

          ]

          }

          var appController={

          scores :[900, 845, 809, 950],

          avgScore:null,

          avg :function() {

          var sumOfScores=this.scores.reduce(function(prev, cur, index, array) {

          return prev + cur;

          });

          this.avgScore=sumOfScores / this.scores.length;

          }

          }

          // Note that we are using the apply() method, so the 2nd argument has to be an array

          appController.avg.apply(gameController);

          console.log(gameController.avgScore); // 46.4

          // appController.avgScore is still null; it was not updated, only gameController.avgScore was updated

          console.log(appController.avgScore); // null

          ```

          這個(gè)例子非常簡(jiǎn)單, 我們定義的 gameController 對(duì)象借用了 appController 對(duì)象的 avg() 方法. 你也許會(huì)想, 如果我們借用的函數(shù)定義發(fā)生了變化, 那么我們的代碼會(huì)發(fā)生什么變化. 借用(復(fù)制后)的函數(shù)也會(huì)變化么, 還是說(shuō)他在完整復(fù)制后已經(jīng)和原始的方法切斷了聯(lián)系? 讓我們用下面這個(gè)小例子來(lái)說(shuō)明這個(gè)問(wèn)題:

          ```

          appController.maxNum=function() {

          this.avgScore=Math.max.apply(null, this.scores);

          }

          appController.maxNum.apply(gameController, gameController.scores);

          console.log(gameController.avgScore); // 77

          ```

          正如我們所期望的那樣, 如果我們修改原始的方法, 這樣的變化會(huì)在借用實(shí)例的方法上體現(xiàn)出來(lái). 我們總是希望如此, 因?yàn)槲覀儚膩?lái)不希望完整的復(fù)制一個(gè)方法, 我們只是想簡(jiǎn)單的借用一下.。

          使用 apply() 執(zhí)行參數(shù)可變的函數(shù)

          關(guān)于 Apply, Call 和 Bind 方法的多功能性和實(shí)用性, 我們將討論一下Apply方法的一個(gè)很簡(jiǎn)單的功能: 使用參數(shù)數(shù)組執(zhí)行函數(shù)。

          Math.max() 方法是 JavaScript 中一個(gè)常見(jiàn)的參數(shù)可變函數(shù):

          ```

          console.log(Math.max(23, 11, 34, 56)); // 56

          ```

          但如果我們有一個(gè)數(shù)組要傳遞給 Math.max(), 是不能這樣做的:

          ```

          var allNumbers=[23, 11, 34, 56];

          console.log(Math.max(allNumbers)); // NaN

          ```

          使用 apply 我們可以像下面這樣傳遞數(shù)組:

          ```

          var allNumbers=[23, 11, 34, 56];

          console.log(Math.max.apply(null, allNumbers)); // 56

          ```

          正如之前討論, apply() 的第一個(gè)參數(shù)用于設(shè)置 this 的指向, 但是 Math.max() 并未使用到 this, 所以我們傳遞 null 給他。

          為了更進(jìn)一步解釋 apply() 在 參數(shù)可變函數(shù)上的能力, 我們自定義了一個(gè)參數(shù)可變函數(shù):

          ```

          var students=["Peter Alexander", "Michael Woodruff", "Judy Archer", "Malcolm Khan"];

          // 不定義參數(shù), 因?yàn)槲覀兛梢詡鬟f任意多個(gè)參數(shù)進(jìn)入該函數(shù)

          function welcomeStudents() {

          var args=Array.prototype.slice.call(arguments);

          var lastItem=args.pop();

          console.log("Welcome " + args.join (", ") + ", and " + lastItem + ".");

          }

          welcomeStudents.apply(null, students);

          // Welcome Peter Alexander, Michael Woodruff, Judy Archer, and Malcolm Khan.

          ```

          區(qū)別與注意事項(xiàng)

          三個(gè)函數(shù)存在的區(qū)別, 用一句話來(lái)說(shuō)的話就是: bind是返回對(duì)應(yīng)函數(shù), 便于稍后調(diào)用; apply, call則是立即調(diào)用. 除此外, 在 ES6 的箭頭函數(shù)下, call 和 apply 的失效, 對(duì)于箭頭函數(shù)來(lái)說(shuō):

          • 函數(shù)體內(nèi)的 this 對(duì)象, 就是定義時(shí)所在的對(duì)象, 而不是使用時(shí)所在的對(duì)象;
          • 不可以當(dāng)作構(gòu)造函數(shù), 也就是說(shuō)不可以使用 new 命令, 否則會(huì)拋出一個(gè)錯(cuò)誤;
          • 不可以使用 arguments 對(duì)象, 該對(duì)象在函數(shù)體內(nèi)不存在. 如果要用, 可以用 Rest 參數(shù)代替;
          • 不可以使用 yield 命令, 因此箭頭函數(shù)不能用作 Generator 函數(shù);


          更多關(guān)于箭頭函數(shù)的介紹在這里就不做過(guò)多介紹了, 詳情可以查看 [Arrow functions](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions).

          總結(jié)

          Call, Apply 和 Bind 在設(shè)置 this 指向, 聲稱(chēng)與執(zhí)行參數(shù)可變函數(shù)以及函數(shù)借用方面的強(qiáng)大之處已經(jīng)非常明顯. 作為一名 JavaScript 開(kāi)發(fā)者, 你一定會(huì)經(jīng)常見(jiàn)到這種用法, 或者在開(kāi)發(fā)中嘗試使用他. 請(qǐng)確保你已經(jīng)很好的了解了如上所述的概念與用法.

          原文鏈接:

          http://javascriptissexy.com/javascript-apply-call-and-bind-methods-are-essential-for-javascript-professionals

          們知道在 HTML 打開(kāi)鏈接的方法就是定義 href

          如下面的代碼:

          <div>
             <a href="javascript: void(0);" @click="openBlogDetail(item.id)" class="text-primary">Read
             more <i class="mdi mdi-arrow-right"></i></a>
          </div>
          

          但是,有時(shí)候我們是希望通過(guò)單擊鏈接的方法調(diào)用一個(gè) JS 函數(shù)。

          上面就是定義了一個(gè)調(diào)用函數(shù),并且傳遞 ID 到函數(shù)中。

          在函數(shù)中打開(kāi)鏈接

          在函數(shù)中打開(kāi)鏈接的方法是:

          window.open("/blog/detail/" + id, "_self")

          需要注意的是,上面的打開(kāi)方法我們添加了一個(gè)參數(shù) _self。

          這個(gè)參數(shù)的意思是在當(dāng)前的標(biāo)簽頁(yè)中打開(kāi)。

          按照現(xiàn)代瀏覽器的配置,如果不添加這個(gè)參數(shù),將會(huì)把需要打開(kāi)的鏈接在一個(gè)新的標(biāo)簽頁(yè)中打開(kāi)。

          使用上面的方法,直接調(diào)用就可以了。


          主站蜘蛛池模板: 中文字幕在线观看一区二区| 亚洲一区在线免费观看| 日韩成人一区ftp在线播放| 成人精品一区二区三区不卡免费看 | 色窝窝无码一区二区三区成人网站 | 手机看片福利一区二区三区| 亚洲丶国产丶欧美一区二区三区| 久久99热狠狠色精品一区| 亚洲午夜福利AV一区二区无码| 国产一区二区三区亚洲综合| 亚洲一区二区三区高清| 精品久久一区二区三区| 一区二区三区视频观看| 精品一区二区三区四区在线| 国模丽丽啪啪一区二区| 无码视频免费一区二三区| 国产丝袜一区二区三区在线观看 | 亚洲国产欧美一区二区三区 | 熟妇人妻系列av无码一区二区| 一区二区三区波多野结衣| 日本成人一区二区| 欧美日韩国产免费一区二区三区 | 精品国产一区二区三区www| 亚洲国产精品一区二区三区久久| 无码日韩精品一区二区三区免费| 日本一区二区三区不卡在线视频| 2018高清国产一区二区三区| 无码人妻精品一区二区蜜桃AV| 高清一区二区三区视频| 国产精品熟女一区二区| 一本一道波多野结衣AV一区| 国产伦精品一区二区三区免费迷| 日韩毛片一区视频免费| 中文字幕精品无码一区二区三区| 色噜噜狠狠一区二区三区果冻| 国产乱码精品一区三上| 文中字幕一区二区三区视频播放| 国产成人无码精品一区不卡| 国产一区二区精品尤物| 色多多免费视频观看区一区| 爆乳无码AV一区二区三区|