bind与apply的区别?自定义bind函数与原生Function.prototype.bind是否等价?
好问题!这个手写的bind函数确实实现了原生bind最核心的能力——固定函数的执行上下文,但它和原生版本并不完全等价,存在几个关键差异,咱们一步步说清楚:
核心差异点
1. 不支持预设参数
原生Function.prototype.bind允许在绑定上下文的同时,预先传入后续调用时的部分参数:
function greet(greeting, punctuation) { console.log(`${greeting}, ${this.name}${punctuation}`); } const boundGreet = greet.bind({name: 'Alice'}, 'Hello'); boundGreet('!'); // 输出: Hello, Alice!
而你看到的自定义bind函数完全没处理预设参数,它只能绑定上下文,没法提前传参。
2. 构造函数模式下的行为不一致
当用new关键字调用原生bind返回的绑定函数时,绑定的上下文会被忽略,this会指向新创建的实例,同时实例会继承原函数的原型链:
function Person(name) { this.name = name; } const BoundPerson = Person.bind({}); const p = new BoundPerson('Bob'); console.log(p.name); // 输出: Bob(原生bind会忽略绑定的空对象) console.log(p instanceof Person); // 输出: true
但自定义的bind返回的函数如果用new调用,this依然会被绑定到传入的context,完全破坏了构造函数的行为:
const CustomBoundPerson = bind(Person, {}); const cp = new CustomBoundPerson('Charlie'); console.log(cp); // 输出: undefined(因为this指向空对象,实例没有被正确创建) console.log(cp instanceof Person); // 输出: false
3. 函数元属性的缺失
原生bind返回的函数会保留原函数的一些元信息:
name属性:会显示为"bound 原函数名",方便调试length属性:等于原函数的形参个数减去预设参数的数量- 还会继承原函数的其他可枚举属性
而自定义的bind返回的是一个匿名函数,它的name是空字符串,length是0,也不会继承原函数的任何属性。
4. 严格模式下的细节差异
在严格模式中,原生bind对arguments的处理、this的绑定规则会更严谨。比如原生bind会确保即使在严格模式下,绑定的上下文也能正确传递,而自定义的版本依赖arguments对象,虽然基本功能可用,但原生实现的鲁棒性更强。
为什么有人用自定义bind?
最常见的原因是兼容老旧浏览器:比如IE8及更早的版本没有原生的Function.prototype.bind,所以需要手写简化版的绑定逻辑(标准polyfill会处理上述差异,这个版本是极简核心版)。
另外,如果代码只需要最基础的上下文绑定功能,不需要预设参数、构造函数支持这些特性,这个简化版的bind更轻量,适合嵌入到小型脚本中。当然也有可能是开发者为了学习bind的核心原理而手动实现的。
内容的提问来源于stack exchange,提问作者trollkotze

