JS的bind方法用法是怎样,如何实现完整的bind
Admin 2022-08-06 群英技术资讯 342 次浏览
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 预置好的参数。
其他保持原样。
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; };
这里有更多的细节:
手写 bind,现在想来并不简单,需要掌握好很多知识点:
this instanceof boundFn
)判断是否通过 new 调用当前函数;免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
用JavaScript怎样做查询快递单号的功能?一些朋友可能每天都会收到或者寄出很多快递,因此查询快递单号的功能是很重要的,本文给分享模拟京东快递单号查询的功能,实现效果及代码如下,感兴趣的朋友可以参考。
ES6的扩展运算符,它的语法很简单,使用三个点号表示“...”。可以将一个数组转为用逗号分隔的参数序列。它将可迭代对象展开到其单独的元素中,所谓的可迭代对象就是任
本文主要介绍了Vite+Electron快速构建VUE3桌面应用的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
递归是算法中一个重要的解法,因此,有必要单拎出来讲讲,所以下面这篇文章主要给大家介绍了关于JavaScript递归经典案例题的相关资料,需要的朋友可以参考下
这篇文章主要介绍了Vue前端打包的详细流程,下面文章围绕Vue前端打包的相关资料展开详细内容,需要的小伙伴可以参考一下,希望对大家有所帮助
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008