摘要:系統,扎實的語言基礎是一個優秀的前端工程師必須具備的。第一個參數為調用函數時的指向,隨后的參數則作為函數的參數并調用,也就是。和的區別只有一個,就是它只有兩個參數,而且第二個參數為調用函數時的參數構成的數組。
系統,扎實的 javascript 語言基礎是一個優秀的前端工程師必須具備的。在看了一些關于 call,apply,bind 的文章后,我還是打算寫下這篇總結,原因其實有好幾個。首先,在如今 ES6 大行其道的今天,很多文章中講述的它們的應用場景其實用 ES6 可以更優雅的解決。再則,講它們的實現原理的文章不多,本文將把它們通過代碼一一模擬實現,讓它們不再神秘。不謙虛的說,關于 call,apply,bind 的知識,看這一篇文章就夠了。
改變函數中 this 指向的三兄弟我們知道在 javascript 的 function 中有 this,arguments 等關鍵字。本文不討論 this 指向問題,那個都可以多帶帶整一篇文章了。一個常見的使用場景是當你使用 . 來調用一個函數的時候,此時函數中 this 指向 . 前面的調用者:
const person = { name: "YuTengjing", age: 22, introduce() { console.log(`Hello everyone! My name is ${this.name}. I"m ${this.age} years old.`); } }; // this 此時指向 person console.log(person.introduce()); // => Hello everyone! My name is YuTengjing. I"m 22 years old.?
通過 call,apply,bind 這三兄弟可以改變 introduce 中 this 的指向。
callconst myFriend = { name: "dongdong", age: 21, }; console.log(person.introduce.call(myFriend)); // => Hello everyone! My name is dongdong. I"m 21 years old.?
通過上面代碼我們可以看出 introduce 這個函數中的 this 指向被改成了 myFriend。Function.prototype.call 的函數簽名是 fun.call(thisArg, arg1, arg2, ...)。第一個參數為調用函數時 this 的指向,隨后的參數則作為函數的參數并調用,也就是 fn(arg1, arg2, ...)。
applyapply 和 call 的區別只有一個,就是它只有兩個參數,而且第二個參數為調用函數時的參數構成的數組。函數簽名:func.apply(thisArg, [argsArray])。如果不用給函數傳參數,那么他倆就其實是完全一樣的,需要傳參數的時候注意它的應該將參數轉換成數組形式。
一個簡單的例子:
function displayHobbies(...hobbies) { console.log(`${this.name} likes ${hobbies.join(", ")}.`); } // 下面兩個等價 displayHobbies.call({ name: "Bob" }, "swimming", "basketball", "anime"); // => // => Bob likes swimming, basketball, anime.? displayHobbies.apply({ name: "Bob" }, ["swimming", "basketball", "anime"]); // => Bob likes swimming, basketball, anime.?
有些 API 比如 Math.max 它的參數為多參數,當我們有多參數構成的數組使或者說參數很多時該怎么辦呢?
// Math.max 參數為多參數 console.log(Math.max(1, 2, 3)); // => 3 // 現在已知一個很大的元素為隨機大小的整數數組 const bigRandomArray = [...Array(10000).keys()].map(num => Math.trunc(num * Math.random())); // 怎樣使用 Math.max 獲取 bigRandomArray 中的最大值呢?Math.max 接受的是多參數而不是數組參數啊! // 思考下面的寫法 console.log(Math.max.apply(null, bigRandomArray)); // => 9936
可以上 ES6 的話就簡單了,使用擴展運算符即可,優雅簡潔。
console.log(Math.max(...bigRandomArray));bind
bind 和上面兩個用途差別還是比較大,如同字面意思(綁定),是用來綁定 this 指向的,返回一個原函數被綁定 this 后的新函數。一個簡單的例子:
const person = { name: "YuTengjing", age: 22, }; function introduce() { console.log(`Hello everyone! My name is ${this.name}. I"m ${this.age} years old.`); } const myFriend = { name: "dongdong", age: 21 }; person.introduce = introduce.bind(myFriend); // person.introduce 的 this 已經被綁定到 myFriend 上了 console.log(person.introduce()); // => Hello everyone! My name is dongdong. I"m 21 years old. console.log(person.introduce.call(person)); // => Hello everyone! My name is dongdong. I"m 21 years old.?
bind 的函數簽名是 func.bind(thisArg, arg1, arg2, ...)。春招的時候被問過 bind 的第二個參數是干嘛用的,因為我之前寫代碼本身不怎么用這幾個 API,用的時候我也只用第一個參數,所以當時面試的時候被問這個問題的時候我還是愣了一下。不過其實如果可以傳多個參數的話,猜也能猜得出來是干嘛用的,我當時就猜對了φ(* ̄0 ̄)。
學以致用我們學習知識的時候不能只是停留在理解層面,需要去思考它們有什么用,應用場景有哪些。這樣的話,當你處在這種場景中,你就能很自然的想出解決方案。
多參函數轉換為單個數組參數調用javascript 中有很多 API 是接受多個參數的比如之前提過的 Math.max,還有很多例如 Math.min,Array.prototype.push 等它們都是接受多個參數的 API,但是有時候我們只有多個參數構成的數組,而且可能還特別大,這個時候就可以利用 apply 巧妙的來轉換。
下面是利用 apply 來巧妙的合并數組:
let arr1 = [1, 2, 3]; let arr2 = [4, 5, 6]; Array.prototype.push.apply(arr1, arr2); console.log(arr1); // [1, 2, 3, 4, 5, 6]
但是,其實用 ES6 可以非常的簡潔:
arr1.push(...arr2);
所以,忘了這種用法吧( ̄︶ ̄)↗ 。
將類數組轉換為數組JavaScript類型化數組是一種類似數組的對象,它們有數組的一些屬性,但是如果你用 Array.isArray() 去測試會返回 false,常見的像 arguments,NodeList 等。
function testArrayLike() { // 有 length 屬性沒有 slice 屬性 console.log(arguments.length); // => 3 console.log(arguments.slice); // => undefined // 類數組不是數組 console.log(Array.isArray(arguments)); // => false console.log(arguments); // => { [Iterator] 0: "a", 1: "b", 2: "c", [Symbol(Symbol.iterator)]: [λ: values] }? const array = Array.prototype.slice.call(arguments); console.log(Array.isArray(array)); // => true console.log(array); // => [ "a", "b", "c" ] } testArrayLike("a", "b", "c");
其實 把 slice 換成 concat,splice 等其它 API 也是可以的。思考:為什么通過 Array.prototype.slice.call(arrayLike) 可以轉換類數組為數組?
我沒有研究過 slice 的具體實現,猜測是下面這樣的:
Array.prototype.mySlice = function(start=0, end) { const array = this; const end = end === undefined ? array.length : end; const resultArray = []; if (array.length === 0) return resultArray; for (let index = start; index < end; index++) { resultArray.push(array[index]); } return resultArray; }
我想 slice 內部實現可能就是會像我上面的代碼一樣只需要一個 length 屬性,遍歷元素返回新數組,所以調用 slice 時將其 this 指向類數組能正常工作。
其實,這個用法也可以忘了,用 ES6 來轉換不造多簡單,ES6 大法好
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105146.html
摘要:出現箭頭函數的時候,指向為定義時的上下文對象而非指向時,并且不能被改變首先我們先看一個例子由上面的例子我們可以看出來此時指針在用改變了之后指向的依然是全局對象非嚴格瀏覽器環境中是而非。 javascript基礎之this指針 越往后面學越發現基礎的重要性,所以打算重新過一遍基礎,之后出幾個vue和react的實戰教程。ok,嚴歸正傳。 首先什么是this this是執行上下文創建時確定...
摘要:參考鏈接在中,和是對象自帶的三個方法,都是為了改變函數體內部的指向。返回值是函數方法不會立即執行,而是返回一個改變了上下文后的函數。而原函數中的并沒有被改變,依舊指向全局對象。原因是,在中,多次是無效的。 參考鏈接:https://juejin.im/post/59bfe8... 在JavaScript中,call、apply和bind是Function對象自帶的三個方法,都是為了改變...
摘要:文章盡量使用大量實例進行講解,它們的使用場景。在嚴格模式下,函數被調用后,里面的默認是后面通過調用函數上的和方法,該變指向,函數里面的指向。利用,可以傳入外層的上下文。同樣適用的還有,里面的對象,它也是一種類數組對象。 call,apply and bind in JavaScript 在ECMAScript中,每個函數都包含兩個繼承而來的方法:apply() 和 call(),這兩個...
摘要:也就是說當返回的函數作為構造函數的時候,時指定的值會失效,但傳入的參數依然生效。構造函數效果的優化實現但是在這個寫法中,我們直接將,我們直接修改的時候,也會直接修改函數的。 JavaScript深入系列第十一篇,通過bind函數的模擬實現,帶大家真正了解bind的特性 bind 一句話介紹 bind: bind() 方法會創建一個新函數。當這個新函數被調用時,bind() 的第一個參數...
摘要:模擬和模擬一樣,現摘抄下面的代碼添加一個返回值對象然后我們定義一個函數,如果執行下面的代碼能夠返回和函數一樣的值,就達到我們的目的。 原文:https://zhehuaxuan.github.io/... 作者:zhehuaxuan 目的 本文主要用于理解和掌握call,apply和bind的使用和原理,本文適用于對它們的用法不是很熟悉,或者想搞清楚它們原理的童鞋。 好,那我們開始...
閱讀 2100·2021-11-11 16:55
閱讀 3171·2021-10-11 10:58
閱讀 3038·2021-09-13 10:28
閱讀 3967·2021-07-26 23:57
閱讀 1005·2019-08-30 15:56
閱讀 1331·2019-08-29 13:15
閱讀 1258·2019-08-26 18:18
閱讀 1266·2019-08-26 13:44