日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

面试常见问题之实现bind函数

發布時間:2023/12/2 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 面试常见问题之实现bind函数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言:

原文首發于我的博客,說實話,這半年來在各大社區看別人分享的面試題中 bind 函數已經出現 n 多次了,這次準備詳細探究下

首先讓我們看看 mdn 對于 bind 函數的描述是什么

語法

fun.bind(thisArg[, arg1[, arg2[, ...]]])

參數

  • thisArg ??當綁定函數被調用時,該參數會作為原函數運行時的 this 指向。當使用 new 操作符調用綁定函數時,該參數無效。
  • arg1, arg2, ... ??當綁定函數被調用時,這些參數將置于實參之前傳遞給被綁定的方法。

返回值

??返回由指定的 this 值和初始化參數改造的原函數拷貝


當代碼 new Foo(...) 執行時,會發生以下事情: 1、一個繼承自 Foo.prototype 的新對象被創建。 2、使用指定的參數調用構造函數 Foo ,并將 this 綁定到新創建的對象。new Foo 等同于 new Foo(),也就是沒有指定參數列表,Foo 不帶任何參數調用的情況。 3、由構造函數返回的對象就是 new 表達式的結果。如果構造函數沒有顯式返回一個對象,則使用步驟 1 創建的對象。(一般情況下,構造函數不返回值,但是用戶可以選擇主動返回對象,來覆蓋正常的對象創建步驟)如果你看不懂這段話,沒關系,看完下面這段代碼你就清楚了

function Foo(){} 下面代碼就是執行new Foo()時的簡單實現 let obj = {}; obj.__proto__ = Foo.prototype return Foo.call(obj)

對于new的完整實現可以參考這位大神的博客


實現

乞丐版, 無法預先填入參數,僅實現執行時改變 this 指向

let obj = {ll: 'seve' };Function.prototype.bind = function(that) {var self = this;return function() {return self.apply(that, arguments);}; }; let func0 = function(a, b, c) {console.log(this.ll);console.log([a, b, c]); }.bind(obj, 1, 2);func0(3); // seve // [ 3, undefined, undefined ] 發現1,2并沒有填入

乞丐版也太 low 了對吧,所以我們繼續完善

es6 進階版

es6 提供了結構運算符,可以很方便的利用其功能實現 bind

Function.prototype.bind = function(that, ...argv) {if (typeof this !== 'function') {throw new TypeError(`${this} is not callable`);}// 保存原函數let self = this;// 獲取bind后函數傳入的參數return function(...argu) {return self.apply(that, [...argv, ...argu]);}; }; let func1 = function(a, b, c) {console.log(this.ll);console.log([a, b, c]); }.bind(obj, 1, 2);func1(3); // seve // [ 1, 2, 3 ]

es6 版實現很簡單對吧,但是面試官說我們的運行環境是 es5,這時你心中竊喜,bable 大法好,但是你可千萬不要說有 babel,因為面試官的意圖不太可能是問你 es6 如何轉換成 es5,而是考察你其他知識點,比如下面的類數組如何轉換為真正的數組

es5 進階版

Function.prototype.bind = function() {if (typeof this !== 'function') {throw new TypeError(`${this} is not callable`);}var self = this;var slice = [].slice;// 模擬es6的解構效果var that = arguments[0];var argv = slice.call(arguments, 1);return function() {// slice.call(arguments, 0)將類數組轉換為數組return self.apply(that, argv.concat(slice.call(arguments, 0)));}; }; let func2 = function(a, b, c) {console.log(this.ll);console.log([a, b, c]); }.bind(obj, 1, 2);func2(3); // seve // [ 1, 2, 3 ]

當然,寫到這里,對于絕大部分面試,這份代碼都是一份不錯的答案,但是為了給面試官留下更好的印象,我們需要上終極版 實現完整的bind函數,這樣還可以跟面試官吹一波

終極版

為了當使用new操作符時,bind后的函數不丟失this。我們需要把bind前的函數的原型掛載到bind后函數的原型上

但是為了修改bind后函數的原型而對bind前的原型不產生影響,都是對象惹的禍。。。直接賦值只是賦值對象在堆中的地址 所以需要把原型繼承給bind后的函數,而不是直接賦值,我有在一些地方看到說Object.crate可以實現同樣的效果,有興趣的可以了解一下,但是我自己試了下,發現效果并不好,new 操作時this指向錯了(可能是我使用姿勢錯了)

通過直接賦值的效果

Function.prototype.bind = function(that, ...argv) {if (typeof this !== 'function') {throw new TypeError(`${this} is not callable`);}// 保存原函數let self = this;let func = function() {};// 獲取bind后函數傳入的參數let bindfunc = function(...arguments) {return self.apply(this instanceof func ? this : that, [...argv, ...arguments]);};// 把this原型上的東西掛載到func原型上面// func.prototype = self.prototype;// 為了避免func影響到this,通過new 操作符進行復制原型上面的東西bindfunc.prototype = self.prototype;return bindfunc; };function bar() {console.log(this.ll);console.log([...arguments]); } let func3 = bar.bind(null);func3.prototype.value = 1;console.log(bar.prototype.value) // 1 可以看到bind后的原型對bind前的原型產生的同樣的影響

通過繼承賦值的效果

Function.prototype.bind = function(that, ...argv) {if (typeof this !== 'function') {throw new TypeError(`${this} is not callable`);}// 保存原函數let self = this;let func = function() {};// 獲取bind后函數傳入的參數let bindfunc = function(...argu) {return self.apply(this instanceof func ? this : that, [...argv, ...argu]);};// 把this原型上的東西掛載到func原型上面func.prototype = self.prototype;// 為了避免func影響到this,通過new 操作符進行復制原型上面的東西bindfunc.prototype = new func();return bindfunc; };function bar() {console.log(this.ll);console.log([...arguments]); } let func3 = bar.bind(null);func3.prototype.value = 1;console.log(bar.prototype.value) // undefined 可以看到bind后的原型對bind前的原型不產生影響func3(5); // seve// [ 5 ] new func3(5); // undefined// [ 5 ]

以上代碼或者表述如有錯誤或者不嚴謹的地方,歡迎指出,或者在評論區討論,覺得我的文章有用的話,可以訂閱或者star支持我的博客

下系列文章我打算寫關于koa框架的實現,第一篇我會帶大家探究Object.create的效果及實現


更多專業前端知識,請上 【猿2048】www.mk2048.com 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的面试常见问题之实现bind函数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。