this是什麼?作什麼?指向是什麼?javascript
函數中this調用:this-----》windowcss
方法中this調用:this-----》當前對象(嗲用方法的對象)html
構造函數中this調用:this------》該構造函數的實例對象java
借用方法調用:改變this的指向node
分析this的問題,須要明白兩點:(只看函數是怎麼被調用的,無論函數是怎麼來的)css3
1.分析this是屬於哪一個函數程序員
2.分析該函數是以什麼模式被調用的es6
要說 JavaScript 這門語言最容易讓人困惑的知識點,this
關鍵詞確定算一個。JavaScript 語言面世多年,一直在進化完善,如今在服務器上還能夠經過 node.js 來跑 JavaScript。顯然,這門語言還會活好久。web
因此說,我一直相信,若是你是一個 JavaScript 開發者或者說 web 開發者,學好 JavaScript 的運做原理以及語言特色確定對你之後大有好處。編程
在開始正文以前,我強烈推薦你先掌握好下面的知識:
若是沒有對這些基礎知識掌握踏實,直接討論 JavaScript 的 this
關鍵詞只會讓你感到更加地困惑和挫敗。
this
?若是上面的簡單介紹沒有說服你來深刻探索 this
關鍵詞,那我用這節來說講爲何要學。
考慮這樣一個重要問題,假設開發者,好比 Douglas Crockford (譯者注:JavaScript 領域必知牛人),再也不使用 new
和 this
,轉而使用完徹底全的函數式寫法來作代碼複用,會怎樣?
事實上,基於 JavaScript 內置的現成的原型繼承功能,咱們已經使用而且將繼續普遍使用 new
和 this
關鍵詞來實現代碼複用。
理由一,若是隻能使用本身寫過的代碼,你是無法工做的。現有的代碼以及你讀到這句話時別人正在寫的代碼都頗有可能包含 this
關鍵詞。那麼學習怎麼用好它是否是頗有用呢?
所以,即便你不打算在你的代碼庫中使用它,深刻掌握 this
的原理也能讓你在接手別人的代碼理解其邏輯時事半功倍。
理由二,拓展你的編碼視野和技能。使用不一樣的設計模式會加深你對代碼的理解,怎麼去看、怎麼去讀、怎麼去寫、怎麼去理解。咱們寫代碼不只是給機器去解析,仍是寫給咱們本身看的。這不只適用於 JavaScript,對其餘編程語言亦是如此。
隨着對編程理念的逐步深刻理解,它會逐漸塑造你的編碼風格,無論你用的是什麼語言什麼框架。
就像畢加索會爲了得到靈感而涉足那些他並非很贊同很感興趣的領域,學習 this 會拓展你的知識,加深對代碼的理解。
this
?在我開始講解前,若是你學過一門基於類的面向對象編程語言(好比 C#,Java,C++),那請將你對 this
這個關鍵詞應該是作什麼用的先入爲主的概念扔到垃圾桶裏。JavaScript 的 this
關鍵詞是很不同,由於 JavaScript 原本就不是一門基於類的面向對象編程語言。
雖然說 ES6 裏面 JavaScript 提供了類這個特性給咱們用,但它只是一個語法糖,一個基於原型繼承的語法糖。
this
就是一個指針,指向咱們調用函數的對象。
我難以強調上一句話有多重要。請記住,在 Class 添加到 ES6 以前,JavaScript 中沒有 Class 這種東西。Class 只不過是一個將對象串在一塊兒表現得像類繼承同樣的語法糖,以一種咱們已經習慣的寫法。全部的魔法背後都是用原型鏈編織起來的。
若是上面的話很差理解,那你能夠這樣想,this 的上下文跟英語句子的表達很類似。好比下面的例子
Bob.callPerson(John);
就能夠用英語寫成 「Bob called a person named John」。因爲 callPerson()
是 Bob 發起的,那 this
就指向 Bob。咱們將在下面的章節深刻更多的細節。到了這篇文章結束時,你會對 this
關鍵詞有更好的理解(和信心)。
執行上下文 是語言規範中的一個概念,用通俗的話講,大體等同於函數的執行「環境」。具體的有:變量做用域(和 做用域鏈條,閉包裏面來自外部做用域的變量),函數參數,以及
this
對象的值。引自: Stackoverflow.com
記住,如今起,咱們專一於查明 this
關鍵詞到底指向哪。所以,咱們如今要思考的就一個問題:
爲了理解這個關鍵概念,咱們來測一下下面的代碼。
var person = { name: "Jay", greet: function() { console.log("hello, " + this.name); } }; person.greet();
誰調用了 greet 函數?是 person
這個對象對吧?在 greet()
調用的左邊是一個 person 對象,那麼 this 關鍵詞就指向 person
,this.name
就等於 "Jay"
。如今,仍是用上面的例子,我加點料:
var greet = person.greet; // 將函數引用存起來; greet(); // 調用函數
你以爲在這種狀況下控制檯會輸出什麼?「Jay」?undefined
?仍是別的?
正確答案是 undefined
。若是你對這個結果感到驚訝,沒必要慚愧。你即將學習的東西將幫助你在 JavaScript 旅程中打開關鍵的大門。
this
的值並非由函數定義放在哪一個對象裏面決定,而是函數執行時由誰來喚起決定。
對於這個意外的結果咱們暫且壓下,繼續看下去。(感受先後銜接得不夠流暢)
帶着這個困惑,咱們接着測試下 this
三種不一樣的定義方式。
this
的指向上一節咱們已經對 this
作了測試。可是這塊知識實在重要,咱們須要再好好琢磨一下。在此以前,我想用下面的代碼給你出個題:
var name = "Jay Global"; var person = { name: 'Jay Person', details: { name: 'Jay Details', print: function() { return this.name; } }, print: function() { return this.name; } }; console.log(person.details.print()); // ? console.log(person.print()); // ? var name1 = person.print; var name2 = person.details; console.log(name1()); // ? console.log(name2.print()) // ?
console.log()
將會輸出什麼,把你的答案寫下來。若是你還想不清楚,複習下上一節。
準備好了嗎?放鬆心情,咱們來看下面的答案。
首先,誰調用了 print 函數?在 JavaScript 中咱們都是從左讀到右。因而 this 指向 details
而不是 person
。這是一個很重要的區別,若是你對這個感到陌生,那趕忙把它記下。
print
做爲 details
對象的一個 key,指向一個返回 this.name
的函數。既然咱們已經找出 this 指向 details ,那函數的輸出就應該是 'Jay Details'
。
再來一次,找出 this
的指向。print()
是被 person
對象調用的,沒錯吧?
在這種狀況,person
裏的 print
函數返回 this.name
。this
如今指向 person
了,那 'Jay Person'
就是返回值。
這一題就有點狡猾了。在上一行有這樣一句代碼:
var name1 = person.print;
若是你是經過這句來思考的,我不會怪你。很遺憾,這樣去想是錯的。要記住,this
關鍵詞是在函數調用時才作綁定的。name1()
前面是什麼?什麼都沒有。所以 this
關鍵詞就將指向全局的 window
對象去。
所以,答案是 'Jay Global'
。
看一下 name2
指向哪一個對象,是 details
對象沒錯吧?
因此下面這句會打印出什麼呢?若是到目前爲止的全部小點你都理解了,那這裏稍微思考下你就天然有答案了。
console.log(name2.print()) // ??
答案是 'Jay Details'
,由於 print
是 name2
調起的,而 name2
指向 details
。
你可能會問:「什麼是詞法做用域?」
逗我呢,咱們不是在探討 this
關鍵詞嗎,這個又是哪裏冒出來的?好吧,當咱們用起 ES6 的箭頭函數,這個就要考慮了。若是你已經寫了不止一年的 JavaScript,那你極可能已經碰到箭頭函數。隨着 ES6 逐漸成爲現實標準,箭頭函數也變得愈來愈經常使用。
JavaScript 的詞法做用域 並很差懂。若是你 理解閉包,那要理解這個概念就容易多了。來看下下面的小段代碼。
// outerFn 的詞法做用域 var outerFn = function() { var n = 5; console.log(innerItem); // innerFn 的詞法做用域 var innerFn = function() { var innerItem = "inner"; // 錯了。只能坐着電梯向上,不能向下。 console.log(n); }; return innerFn; }; outerFn()();
想象一下一棟樓裏面有一架只能向上走的詭異電梯。
建築的頂層就是全局 windows 對象。若是你如今在一樓,你就能夠看到並訪問那些放在樓上的東西,好比放在二樓的 outerFn
和放在三樓的 window
對象。
這就是爲何咱們執行代碼 outerFn()()
,它在控制檯打出了 5 而不是 undefined
。
然而,當咱們試着在 outerFn
詞法做用域下打出日誌 innerItem
,咱們遇到了下面的報錯。請記住,JavaScript 的詞法做用域就好像建築裏面那個只能向上走的詭異電梯。因爲 outerFn 的詞法做用域在 innerFn 上面,因此它不能向下走到 innerFn 的詞法做用域裏面並拿到裏面的值。這就是觸發下面報錯的緣由:
test.html:304 Uncaught ReferenceError: innerItem is not defined at outerFn (test.html:304) at test.html:313
this
和箭頭函數在 ES6 裏面,無論你喜歡與否,箭頭函數被引入了進來。對於那些還沒用慣箭頭函數或者新學 JavaScript 的人來講,當箭頭函數和 this
關鍵詞混合使用時會發生什麼,這個點可能會給你帶來小小的困惑和淡淡的憂傷。那這個小節就是爲大家準備的!
當涉及到
this
關鍵詞,箭頭函數 和 普通函數 主要的不一樣是什麼?
答案:
箭頭函數按詞法做用域來綁定它的上下文,因此
this
實際上會引用到原來的上下文。引自:hackernoon.com
我實在無法給出比這個更好的總結。
箭頭函數保持它當前執行上下文的詞法做用域不變,而普通函數則不會。換句話說,箭頭函數從包含它的詞法做用域中繼承到了 this
的值。
咱們不妨來測試一些代碼片斷,確保你真的理解了。想清楚這塊知識點將來會讓你少點頭痛,由於你會發現 this
關鍵詞和箭頭函數太常常一塊兒用了。
仔細閱讀下面的代碼片斷。
var object = { data: [1,2,3], dataDouble: [1,2,3], double: function() { console.log("this inside of outerFn double()"); console.log(this); return this.data.map(function(item) { console.log(this); // 這裏的 this 是什麼?? return item * 2; }); }, doubleArrow: function() { console.log("this inside of outerFn doubleArrow()"); console.log(this); return this.dataDouble.map(item => { console.log(this); // 這裏的 this 是什麼?? return item * 2; }); } }; object.double(); object.doubleArrow();
若是咱們看執行上下文,那這兩個函數都是被 object
調用的。因此,就此判定這兩個函數裏面的 this 都指向 object
不爲過吧?是的,但我建議你拷貝這段代碼而後本身測一下。
這裏有個大問題:
arrow()
和doubleArrow()
裏面的map
函數裏面的this
又指向哪裏呢?
上一張圖已經給了一個大大的提示。若是你還不肯定,那請花5分鐘將咱們上一節討論的內容再好好想一想。而後,根據你的理解,在實際執行代碼前把你認爲的 this 應該指向哪裏寫下來。在下一節咱們將會回答這個問題。
這個標題已經把答案泄露出來了。在你看不到的地方,map 函數對調用它的數組進行遍歷,將數組的每一項傳到回調函數裏面並把執行結果返回。若是你對 JavaScript 的 map 函數不太瞭解或有所好奇,能夠讀讀這個瞭解更多。
總之,因爲 map()
是被 this.data
調起的,因而 this 將指向那個存儲在 data
這個 key 裏面的數組,即 [1,2,3]
。一樣的邏輯,this.dataDouble
應該指向另外一個數組,值爲 [1,2,3]
。
如今,若是函數是 object
調用的,咱們已經肯定 this 指向 object
對吧?好,那來看看下面的代碼片斷。
double: function() { return this.data.map(function(item) { console.log(this); // 這裏的 this 是什麼?? return item * 2; }); }
這裏有個頗有迷惑性的問題:傳給 map()
的那個匿名函數是誰調用的?答案是:這裏沒有一個對象是。爲了看得更明白,這裏給出一個 map
函數的基本實現。
// Array.map polyfill if (Array.prototype.map === undefined) { Array.prototype.map = function(fn) { var rv = []; for(var i=0, l=this.length; i<l; i++) rv.push(fn(this[i])); return rv; }; }
fn(this[i]));
前面有什麼對象嗎?沒。所以,this
關鍵詞指向全局的 windows 對象。那,爲何 this.dataDouble.map
使用了箭頭函數會使得 this 指向 object
呢?
我想再說一遍這句話,由於它實在很重要:
箭頭函數按詞法做用域將它的上下文綁定到 原來的上下文
如今,你可能會問:原來的上下文是什麼?問得好!
誰是 doubleArrow()
的初始調用者?就是 object
對吧?那它就是原來的上下文
use strict
爲了讓 JavaScript 更加健壯及儘可能減小人爲出錯,ES5 引進了嚴格模式。一個典型的例子就是 this 在嚴格模式下的表現。你若是想按照嚴格模式來寫代碼,你只須要在你正在寫的代碼的做用域最頂端加上這麼一行 "use strict;"
。
記住,傳統的 JavaScript 只有函數做用域,沒有塊做用域。舉個例子:
function strict() { // 函數級嚴格模式寫法 'use strict'; function nested() { return 'And so am I!'; } return "Hi! I'm a strict mode function! " + nested(); } function notStrict() { return "I'm not strict."; }
代碼片斷來自 Mozilla Developer Network。
不過呢,ES6 裏面經過 let 關鍵詞提供了塊做用域的特性。
如今,來看一段簡單代碼,看下 this 在嚴格模式和非嚴格模式下會怎麼表現。在繼續以前,請將下面的代碼運行一下。
(function() { "use strict"; console.log(this); })(); (function() { // 不使用嚴格模式 console.log(this); })();
正如你看到的,this
在嚴格模式下指向 undefined
。相對的,非嚴格模式下 this
指向全局變量 window
。大部分狀況下,開發者使用 this ,並不但願它指向全局 window 對象。嚴格模式幫咱們在使用 this
關鍵詞時,儘可能少作搬起石頭砸本身腳的蠢事。
舉個例子,若是全局的 window 對象恰好有一個 key 的名字和你但願訪問到的對象的 key 相同,會怎樣?上代碼吧:
(function() { // "use strict"; var item = { document: "My document", getDoc: function() { return this.document; } } var getDoc = item.getDoc; console.log(getDoc()); })();
這段代碼有兩個問題。
this
將不會指向 item
。window
對象也有一個名爲 document
的屬性。在這個簡單示例中,由於代碼較短也就不會造成大問題。
若是你是在生產環境像上面那樣寫,當用到 getDoc
返回的數據時,你將收穫一堆難以定位的報錯。若是你代碼庫比較大,對象間互動比較多,那問題就更嚴重了。
值得慶幸的是,若是咱們是在嚴格模式下跑這段代碼,因爲 this 是 undefined
,因而馬上就有一個報錯拋給咱們:
test.html:312 Uncaught TypeError: Cannot read property 'document' of undefined
at getDoc (test.html:312)
at test.html:316
at test.html:317
先前假定你們都對執行上下文不熟,因而咱們聊了不少關於執行上下文和 this 的知識。
讓人歡喜讓人憂的是,在 JavaScript 中經過使用內置的特性開發者就能夠直接操做執行上下文了。這些特性包括:
this
的值準確設置到你選擇的一個對象上。還能夠經過逗號隔開傳遞多個參數,如 func.bind(this, param1, param2, ...)
。this
的值準確設置到你選擇的一個對象上。第二個參數是一個數組,數組的每一項是你但願傳遞給函數的參數。最後,執行函數。this
的值準確設置到你選擇的一個對象上,而後想 bind
同樣經過逗號分隔傳遞多個參數給函數。如:print.call(this, param1, param2, ...)
。最後,執行函數。上面提到的全部內置函數都有一個共同點,就是它們都是用來將 this
關鍵詞指向到其餘地方。這些特性可讓咱們玩一些騷操做。只是呢,這個話題太廣了都夠寫好幾篇文章了,因此簡潔起見,這篇文章我不打算展開它的實際應用。
重點:上面那三個函數,只有 bind()
在設置好 this
關鍵詞後不馬上執行函數。
你可能在想:如今已經很亂了,學習全部這些的目的是什麼?
首先,你會看到 bind、call 和 apply 這幾個函數處處都會用到,特別是在一些大型的庫和框架。若是你沒理解它作了些什麼,那可憐的你就只用上了 JavaScript 提供的強大能力的一小部分而已。
若是你不想了解一些可能的用法而想馬上讀下去,固然了,你能夠直接跳過這節,不要緊。
下面列出來的應用場景都是一些具備深度和廣度的話題(一篇文章基本上是講不完的),因此我放了一些連接供你深度閱讀用。將來我可能會在這篇終極指南里面繼續添加新的小節,這樣你們就能夠一次看過癮。
若是我漏掉了其餘實踐案例,請留言告知。我會常常來優化這篇指南,這樣你做爲讀者就能夠讀到最豐富的內容。
閱讀高質量的開源代碼能夠升級你的知識和技能。
講真,你會在一些開源代碼上看到 this 關鍵詞、call、apply 和 bind 的實際應用。我會將這塊結合着其餘能幫你成爲更好的程序員的方法一塊兒講。
在我看來,開始閱讀最好的開源代碼是 underscore。它並不像其餘開源項目,如 d3,那樣鐵板一塊,而是內部代碼相互比較獨立,於是它是教學用的最佳選擇。另外,它代碼簡潔,文檔詳細,編碼風格也是至關容易學習。
this
和 bind前面提到了,bind
容許你明確設定 this 的指向而不用實際去執行函數。這裏是一個簡單示例:
var bobObj = { name: "Bob" }; function print() { return this.name; } // 將 this 明確指向 "bobObj" var printNameBob = print.bind(bobObj); console.log(printNameBob()); // this 會指向 bob,因而輸出結果是 "Bob"
在上面的示例中,若是你把 bind 那行去掉,那 this 將會指向全局 window
對象。
這好像很蠢,但在你想將 this
綁定到具體對象前你就必須用 bind
來綁定。在某些場景下,咱們可能想從另外一個對象中借用一些方法。舉個例子,
var obj1 = { data: [1,2,3], printFirstData: function() { if (this.data.length) return this.data[0]; } }; var obj2 = { data: [4,5,6], printSecondData: function() { if (this.data.length > 1) return this.data[1]; } }; // 在 obj1 中借用 obj2 的方法 var getSecondData = obj2.printSecondData.bind(obj1); console.log(getSecondData()); // 輸出 2
在這個代碼片斷裏,obj2
有一個名爲 printSecondData
的方法,而咱們想將這個方法借給 obj1
。在下一行
var getSecondData = obj2.printSecondData.bind(obj1);
經過使用 bind ,咱們讓 obj1
能夠訪問 obj2
的 printSecondData
方法。
在下面的代碼中
var object = { data: [1,2,3], double: function() { this.data.forEach(function() { // Get this to point to object. console.log(this); }); } }; object.double();
怎麼讓 this 關鍵詞指向 object
。提示:你並不須要重寫 this.data.forEach
。
在上一節中,咱們瞭解了執行上下文。若是你對匿名函數調用那部分看得夠細心,你就知道它並不會做爲某個對象的方法被調用。所以,this
關鍵詞指向了全局 window
對象。
因而咱們須要將 object 做爲上下文綁定到匿名函數上,使得裏面的 this 指向 object
。如今,double
函數跑起來時,是 object
調用了它,那麼 double
裏面的 this
指向 object
。
var object = { data: [1,2,3], double: function() { return this.data.forEach(function() { // Get this to point to object. console.log(this); }.bind(this)); } }; object.double();
那,若是咱們像下面這樣作呢?
var double = object.double; double(); // ??
double()
的調用上下文是什麼?是全局上下文。因而,咱們就會看到下面的報錯。
Uncaught TypeError: Cannot read property 'forEach' of undefined
at double (test.html:282)
at test.html:289
因此,當咱們用到 this
關鍵詞時,就要當心在乎咱們調用函數的方式。咱們能夠在提供 API 給用戶時固定 this 關鍵詞,以此減小這種類型的錯誤。但請記住,這麼作的代價是犧牲了靈活性,因此作決定前要考慮清楚。
var double = object.double.bind(object); double(); // 再也不報錯
this
和 callcall 方法和 bind 很類似,但就如它名字所暗示的,call
會馬上呼起(執行)函數,這是兩個函數的最大區別。
var item = { name: "I am" }; function print() { return this.name; } // 馬上執行 var printNameBob = console.log(print.call(item));
call
、apply
、bind
大部分使用場景是重疊的。做爲一個程序員最重要的仍是先了解清楚這三個方法之間的差別,從而能根據它們的設計和目的的不一樣來選用。只要你瞭解清楚了,你就能夠用一種更有創意的方式來使用它們,寫出更獨到精彩的代碼。
在參數數量固定的場景,call
或 bind
是不錯的選擇。好比說,一個叫 doLogin
的函數常常是接受兩個參數:username
和 password
。在這個場景下,若是你須要將 this 綁定到一個特定的對象上,call
或 bind
會挺好用的。
之前一個最經常使用的場景是把一個類數組對象,好比 arguments
對象,轉化成數組。舉個例子:
function convertArgs() { var convertedArgs = Array.prototype.slice.call(arguments); console.log(arguments); console.log(Array.isArray(arguments)); // false console.log(convertedArgs); console.log(Array.isArray(convertedArgs)); // true } convertArgs(1,2,3,4);
在上面的例子中,咱們使用 call 將 argument
對象轉化成一個數組。在下一個例子中,咱們將會調用一個 Array
對象的方法,並將 argument 對象設置爲方法的 this,以此來將傳進來參數加在一塊兒。
function add (a, b) { return a + b; } function sum() { return Array.prototype.reduce.call(arguments, add); } console.log(sum(1,2,3,4)); // 10
咱們在一個類數組對象上調用了 reduce 函數。要知道 arguments 不是一個數組,但咱們給了它調用 reduce 方法的能力。若是你對 reduce 感興趣,能夠在這裏瞭解更多。
如今是時候鞏固下你新學到的知識。
NodeList
。請寫一個函數,它接收一個 CSS 選擇器,而後返回一個選擇到的 DOM 節點數組。null
或 undefined
,那就新建一個 object
。示例:set.call( {name: "jay"}, {age: 10, email: '[[email protected]](/cdn-cgi/l/email-protection)'}); // return {name: "jay", age: 10, email: '[[email protected]](/cdn-cgi/l/email-protection)'}
。apply 就是接受數組版本的 call。因而當使用 apply
時,多聯想下數組。
將一個方法應用(apply)到一個數組上。
我用這句話來記住它,並且還挺管用。apply 爲你的現有堆積的軍火庫又添加了同樣利器,增長了不少新的可能,你很快就能體會到這一點。
當你要處理參數數量動態變化的場景,用 apply 吧。將一系列數據轉化爲數組並用上 apply 能讓你寫出更好用和更具彈性的代碼,會讓你的工做更輕鬆。
Math.min 和 max
都是能夠接受多個參數並返回最小值和最大值的函數。除了直接傳 n 個參數,你也能夠將這 n 個參數放到一個數組裏而後藉助 apply
將它傳到 min 函數裏。
Math.min(1,2,3,4); // 返回 1 Math.min([1,2,3,4]); // 返回 NaN。只接受數字 Math.min.apply(null, [1,2,3,4]); // 返回 1
看暈了嗎?若是真暈了,那我來解釋下。使用 apply 時咱們要傳一個數組由於它須要數組做爲第二個參數。而下面
Math.min.apply(null, [1,2,3,4]); // 返回 1
作的事情基本等同於
Math.min(1,2,3,4); // 返回 1
這就是我想指出來的 apply 的神奇之處。它和 call
工做原理,不過咱們只要傳給它一個數組而不是 n 個參數。很好玩對吧?橋豆麻袋,這是否意味着 Math.min.call(null, 1,2,3,4);
執行起來和 Math.min.apply(null, [1,2,3,4]);
同樣?
啊,你說對了!看來你已經開始掌握它了
讓咱們來看下另外一種用法。
function logArgs() { console.log.apply(console, arguments); } logArgs(1,3,'I am a string', {name: "jay", age: "1337"}, [4,5,6,7]);
沒錯,你甚至能夠傳一個類數組對象做爲 apply
的第二個參數。很酷對吧?
null
或 undefined
,那就新建一個 object
。示例:set.apply( {name: "jay"}, [{age: 10}]); // 返回 {name: "jay", age: 10}
Math.max
和 min
的函數,不過接收的不是數字而是運算。前兩個參數必須是數字
,然後面的參數你要將其轉化爲一個函數數組。下面提供一個方便你上手理解的示例:function operate() { if (arguments.length < 3) { throw new Error("至少要三個參數"); } if (typeof arguments[0] !== 'number' || typeof arguments[1] !== 'number') { throw new Error("前兩個參數必須是數字"); } // 寫代碼 // 這是一個由函數組成的數組。你能夠用 call、apply 或者 bind。但不要直接遍歷參數而後直接塞到一個數組裏 var args; var result = 0; // 好了,開始吧,祝好運 } function sum(a, b) { return a + b; } function multiply(a,b) { return a * b; } console.log(operate(10, 2, sum, multiply)); // 必須返回 32 -> (10 + 2) + (10 * 2) = 32
假如我上面的解釋沒能讓你釋疑,那下面這些額外的資料能夠幫你更好地理解 bind 在 JavaScript 裏面是怎麼運做的。
我還強烈推薦你去學習 JavaScript 原型鏈,不單是由於裏面用到大量的 this
關鍵詞,並且它仍是 JavaScript 實現繼承的標準方式。
下面列出一些幫你瞭解 this
如何使用的書籍:
考慮到 this
關鍵詞已經用到了難以計量的代碼中,它是 JavaScript 中咱們不得不聊的話題。
一個優秀的藝術家確定精於工具的使用。做爲一個 JavaScript 開發者,怎麼用好它的特性是最最重要的。
若是你想看到一些從特定角度對 this
關鍵詞深刻剖析的文章或者更多的代碼,請別忘了告訴我。這些可能的角度能夠是(但不限於)下面這些:
this
和 new
關鍵詞。this
和 JavaScript 的類。做者:老教授連接:https://juejin.im/post/5aefe76e6fb9a07abc29d4a1來源:掘金著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。