你有遇見過給bind返回的函數做new操作的場景,本篇主要講述的就是實現一下兼容new操作的bind寫法,順便學習一下new操作符,為大家提供下參考。
大家可以去看下關于 JS 中 bind 方法的實現的文章,并給出了實現:
Function.prototype.myBind = function(thisArg, ...prefixArgs) { const fn = this; return function(...args) { return fn.call(thisArg, ...prefixArgs, ...args); } }
但沒有處理通過 new 創建實例的情況。
我們沒考慮過給 bind 返回的函數做 new 操作的場景,主要就是這種情況極少遇見。
但有時還是會出現,在實現一下兼容 new 操作的 bind 寫法,順便學習一下 new 操作符。
這里我推薦先看下前一篇文章:《前端面試題:手寫 bind》。
new
我們先學習一下 new 操作符。
new 用于通過函數來創建一個對象實例,在很多語言中都能看到。
JS 的函數,除了可以是普通函數,比如:
function sum(a, b) { return a + b; }
還可以是構造函數,只需要在構造時在它前面加一個 new:
function Person(name, age) { this.name = name; this.age = age; } const person = new Person('前端西瓜哥', 100) // Person {name: '前端西瓜哥', age: 100}
new 創建一個新對象,做了下面幾件事:
創建一個空對象{};
空對象的原型屬性__proto__指向構造函數的原型對象Person.prototype;
函數中的 this 設置為這個空對象;
如果該函數不返回一個對象,就返回這個 this,否則返回這個對象。
判斷函數是否通過 new 被調用
怎么判斷一個函數正在被 new 操作符調用?
答案是使用 instanceof 判斷 this 是否為當前函數的實例,即this instanceof Fn為 true,表示在通過 new 構建實例。
先看下實例:
function Person() { if (this instanceof Person) { console.log('通過 new 構建實例'); } else { console.log('普通調用') } } Person() // 輸出:普通調用 new Person() // 輸出:通過 new 構建實例
在 Vuejs 的源碼,你會看到下面代碼,這里也用到了這個技巧。
function Vue(options) { if (__DEV__ && !(this instanceof Vue)) { warn('Vue is a constructor and should be called with the `new` keyword') } this._init(options) }
你在開發環境如果不通過 new 來使用 Vue 對象,會在控制臺提示你要通過 new 來調用 Vue。
new 和 bind
如果我們 new 的是 Function.prototype.bind 返回的新函數,會發生什么事情?
function Person(name, age) { this.name = name; this.age = age; } const BoundPerson = Person.bind(null, '前端西瓜哥'); const boundPerson = new BoundPerson(100); // Person {name: '前端西瓜哥', age: 100} boundPerson.__proto__ === Person.prototype // true
結果等價于直接去 new 原始函數。
不同的是,仍舊可以進行參數的預置。可以看到,構造函數的第一個參數,在調用 bind 的時候就提前設置為 '前端西瓜哥'。
實現完整的 bind
完整實現如下:
Function.prototype.myBind = function(thisArg, ...prefixArgs) { const fn = this; const boundFn = function(...args) { // 通過 new 使用當前函數 if (this instanceof boundFn) { return new fn(...prefixArgs, ...args); } // 普通的方法調用當前函數 return fn.call(thisArg, ...prefixArgs, ...args); } boundFn.prototype = fn.prototype; return boundFn; }
這里我通過this instanceof boundFn來判斷是否用了 new,如果是,就直接 new 原始函數然后返回,記得帶上 bind 預置好的參數。
和原本一樣(參照《前端面試題:手寫 bind》)。
boundFn.prototype = fn.prototype;這個可寫可不寫,只是讓 bind 返回的新函數的 prototype 指向原函數的 prototype。
如果是原生 bind 返回的函數,它是沒有 protoype 屬性的,可以認為它是一種特別的函數,而我們實現的 bind 返回的卻是一個普通函數,所以并不能完全模擬的。
如果你追求完美的實現,可以研讀一下Function.prototype.bind的標準:
然后再看看知名的core.js庫中對 bind 的實現:
其中核心實現為:
// `Function.prototype.bind` method implementation // https://tc39.es/ecma262/#sec-function.prototype.bind module.exports = Function.bind || function bind(that /* , ...args */) { var F = aCallable(this); var Prototype = F.prototype; var partArgs = arraySlice(arguments, 1); var boundFunction = function bound(/* args... */) { var args = concat(partArgs, arraySlice(arguments)); return this instanceof boundFunction ? construct(F, args.length, args) : F.apply(that, args); }; if (isObject(Prototype)) boundFunction.prototype = Prototype; return boundFunction; };
這里有更多的細節:
這里判斷了 this 是否為函數類型,不是函數會報錯;
F.prototype 需要是一個對象或函數,才能賦值給新函數;
使用了普通函數和 arguments,這是為了兼容 ES5。
結尾
手寫 bind,需要我們學習更多知識:
bind 的詳盡用法:包括改變 this、預置參數、new 的表現;
閉包的使用:保存一些私有變量;
通過原型鏈的方式(this instanceof boundFn)判斷是否通過 new 調用當前函數;
使用 call 在執行時改變函數的 this 指向。
以上就是全部內容,歡迎大家繼續關注后續更多精彩內容。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/128375.html
JavaScript筆試部分 點擊關注本公眾號獲取文檔最新更新,并可以領取配套于本指南的 《前端面試手冊》 以及最標準的簡歷模板. 實現防抖函數(debounce) 防抖函數原理:在事件被觸發n秒后再執行回調,如果在這n秒內又被觸發,則重新計時。 那么與節流函數的區別直接看這個動畫實現即可。 showImg(https://segmentfault.com/img/remote/146000002...
摘要:第一種直接調用避免在不必要的情況下使用,是一個危險的函數,他執行的代碼擁有著執行者的權利。來自于此外,實現需要考慮實例化后對原型鏈的影響。函數柯里化的主要作用和特點就是參數復用提前返回和延遲執行。手寫路徑導航 實現一個new操作符 實現一個JSON.stringify 實現一個JSON.parse 實現一個call或 apply 實現一個Function.bind 實現一個繼承 實現一個J...
摘要:最近準備初級前端面試,發現有很多手寫實現什么的,例如什么手寫實現,。后面以這道題為引線面試官可能會追問什么是執行上下文的判斷,的區別手寫一個函數實現斐波那契數列首先拷一個阮神在他教程里的一個寫法。 最近準備初級前端面試,發現有很多手寫實現什么的,例如什么手寫實現bind,promise。手寫ajax,手寫一些算法。翻閱了很多書籍和博客。 這里做一個總結改進,算是對我后面大概為期一個月找...
摘要:先說下我面試情況,我一共面試了家公司。篇在我面試的眾多公司里,只有同城的面問到相關問題,其他公司壓根沒問。我自己回答的是自己開發組件面臨的問題。完全不用擔心對方到時候打電話核對的問題。 2019的5月9號,離發工資還有1天的時候,我的領導親切把我叫到辦公室跟我說:阿郭,我們公司要倒閉了,錢是沒有的啦,為了不耽誤你,你趕緊出去找工作吧。聽到這話,我虎軀一震,這已經是第2個月沒工資了。 公...
閱讀 561·2023-03-27 18:33
閱讀 750·2023-03-26 17:27
閱讀 647·2023-03-26 17:14
閱讀 603·2023-03-17 21:13
閱讀 537·2023-03-17 08:28
閱讀 1823·2023-02-27 22:32
閱讀 1315·2023-02-27 22:27
閱讀 2199·2023-01-20 08:28