<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
大家好,我是前端西瓜哥。
之前寫了一篇關於 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 用於通過函數來建立一個物件範例,在很多語言中都能看到。
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
;怎麼判斷一個函數正在被 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 的是 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 的時候就提前設定為 '前端西瓜哥'。
完整實現如下:
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/ 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; };
這裡有更多的細節:
手寫 bind,現在想來並不簡單,需要掌握好很多知識點:
this instanceof boundFn
)判斷是否通過 new 呼叫當前函數;到此這篇關於JS手寫bind之處理new的情況詳解的文章就介紹到這了,更多相關JS處理new內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45