您好,登錄后才能下訂單哦!
這篇文章主要介紹“JS之如何處理new的情況”,在日常操作中,相信很多人在JS之如何處理new的情況問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”JS之如何處理new的情況”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
Function.prototype.myBind = function(thisArg, ...prefixArgs) { const fn = this; return function(...args) { return fn.call(thisArg, ...prefixArgs, ...args); } }
但沒有處理 通過 new 創(chuàng)建實例 的情況。
因為很少會遇到給 bind 返回的函數(shù)做 new 操作的場景。
我們先學(xué)習(xí)一下 new 操作符。
new 用于通過函數(shù)來創(chuàng)建一個對象實例,在很多語言中都能看到。
JS 的函數(shù),除了可以是普通函數(shù),比如:
function sum(a, b) { return a + b; }
還可以是構(gòu)造函數(shù),只需要在構(gòu)造時在它前面加一個 new:
function Person(name, age) { this.name = name; this.age = age; } const person = new Person('前端西瓜哥', 100) // Person {name: '前端西瓜哥', age: 100}
new 創(chuàng)建一個新對象,做了下面幾件事:
創(chuàng)建一個空對象 {}
;
空對象的原型屬性 __proto__
指向構(gòu)造函數(shù)的原型對象 Person.prototype
;
函數(shù)中的 this 設(shè)置為這個空對象;
如果該函數(shù)不返回一個對象,就返回這個 this,否則返回這個對象。
怎么判斷一個函數(shù)正在被 new 操作符調(diào)用?
答案是 使用 instanceof 判斷 this 是否為當前函數(shù)的實例,即 this instanceof Fn
為 true,表示在通過 new 構(gòu)建實例。
我們看一個例子:
function Person() { if (this instanceof Person) { console.log('通過 new 構(gòu)建實例'); } else { console.log('普通調(diào)用') } } Person() // 輸出:普通調(diào)用 new Person() // 輸出:通過 new 構(gòu)建實例
在 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) }
你在開發(fā)環(huán)境如果不通過 new 來使用 Vue 對象,會在控制臺提示你要通過 new 來調(diào)用 Vue。
如果我們 new 的是 Function.prototype.bind 返回的新函數(shù),會發(fā)生什么事情?
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
結(jié)果等價于直接去 new 原始函數(shù)。
不同的是,仍舊可以進行參數(shù)的預(yù)置??梢钥吹?,構(gòu)造函數(shù)的第一個參數(shù),在調(diào)用 bind 的時候就提前設(shè)置為 '前端西瓜哥'。
完整實現(xiàn)如下:
Function.prototype.myBind = function(thisArg, ...prefixArgs) { const fn = this; const boundFn = function(...args) { // 通過 new 使用當前函數(shù) if (this instanceof boundFn) { return new fn(...prefixArgs, ...args); } // 普通的方法調(diào)用當前函數(shù) return fn.call(thisArg, ...prefixArgs, ...args); } boundFn.prototype = fn.prototype; return boundFn; }
這里我通過 this instanceof boundFn
來判斷是否用了 new,如果是,就直接 new 原始函數(shù)然后返回,記得帶上 bind 預(yù)置好的參數(shù)。
其他保持原樣。
boundFn.prototype = fn.prototype;
這個可寫可不寫,只是讓 bind 返回的新函數(shù)的 prototype 指向原函數(shù)的 prototype。
如果是原生 bind 返回的函數(shù),它是沒有 protoype 屬性的,可以認為它是一種特別的函數(shù),而我們實現(xiàn)的 bind 返回的卻是一個普通函數(shù),所以并不能完全模擬的。
如果你 追求完美的實現(xiàn),可以研讀一下 Function.prototype.bind 的標準:
然后再看看知名的 core.js 庫中對 bind 的實現(xiàn):
其中核心實現(xiàn)為:
// `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; };
這里有更多的細節(jié):
這里判斷了 this 是否為函數(shù)類型,不是函數(shù)會報錯;
F.prototype 需要是一個對象或函數(shù),才能賦值給新函數(shù);
使用了普通函數(shù)和 arguments,這是為了兼容 ES5。
到此,關(guān)于“JS之如何處理new的情況”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。