Function.prototype.bind()
仅供本人学习使用
方法
bind()方法主要就是将函数绑定到某个对象,
bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()中的第一个参数的值,
例如:f.bind(obj),实际上可以理解为obj.f(),这时f函数体内的 this 自然指向的是 obj
var a = {
b: function(){
var func = function(){
console.log(this.c);
}
func();
},
c:'hello'
}
a.b(); // undefined 这里的this指向的是全局作用域
console.log(a.c); // hello
// 对比
var a = {
b: function(){
var _this = this;
var func = function(){
console.log(_this.c);
}
},
c: 'hello'
}
a.b(); // hello
console.log(a.c) // hello
var a = {
b: function(){
var func = function(){
console.log(this.c);
}
func.bind(this)();
},
c:'Hello!'
}
a.b(); // Hello!
这里有个比较容易混淆的,我一开始以为 bind 是把某个函数的this绑定到某个对象,并且这个函数已经被改变了,但是,bind 并没有改变原函数,它只是返回了一个这个函数的 this 绑定了传入进去的对象的函数,也就是说它并没有改变原函数。
函数柯里化
function f(y, z){
return this.x + y + z;
}
let m = f.bind({x: 1}, 2);
console.log(m(3)); // 6
从第二个参数起,会依次传递给原始函数。这里的第二个参数,对应的是f函数的y参数,最后调用 m(3) 的时候,3对应的便是最后一个参数 z, 所以执行结果为:1 + 2 + 3 = 6 。
用 bind 方式预定义参数
function list(){
// console.log(arguments);
// console.log(Array.prototype.slice.call(arguments));
return Array.prototype.slice.call(arguments);
}
// 预定义参数
let x = list.bind(undefined, 10);
let list1 = x(); // [10]
let list2 = x(1, 2, 3); // [10, 1, 2, 3]
其中 Array.prototype.slice.call(arguments) 是用来将参数由类数组转换为真正的数组,undefined 表示 this 的指向,10 是 x 中真正的第一个参数
实现 bind 方法
方法一,仅可以绑定,不可传参
Function.prototype.my_bind = function(context){
let self = this;
return function(){
return self.apply(context, arguments);
}
}
function RName(){
return this.name;
}
RName(); // ""
let person = {name: 'kong'};
RName.bind(person)(); // kong
RName.my_bind(person)(); // kong
方法二
Function.prototype.my_bind = function(context){
let args = Array.prototype.slice.call(arguments, 1); // [2022, 4]
let self = this;
return function(){
let innerArgs = Array.prototype.slice.call(arguments); // [30]
let finalArgs = args.concat(innerArgs);
return self.apply(context, finalArgs);
}
}
function RName(year, month, day){
return this.name + ' ' + year + '/' + month + '/' + day;
}
let person = {name: 'kong'};
RName.my_bind(person, 2022, 4)(30) // 'kong 2022/4/30'
args 表示的是在bind时传入的预定义参数,即为 2022 和 4 ,分别表示year 和 month
innerArgs 表示的时调用返回的参数的时候传入的参数,这里为 30
方法三
bind返回的函数如果作为构造函数,搭配new关键字出现的话,我们绑定的this就需要被忽略
// 处理构造函数场景下的兼容
Function.prototype.bind = Function.prototype.bind || function(context){
// 确保调用bind方法的一定要是一个函数
if(typeof this !== "function"){
throw new TypeError("Function.prototype.bind-what is trying to be bound is not callable");
}
let args = Array.prototype.slice.call(arguments, 1);
let self = this;
let F = function(){};
let bound = function(){
let innerArgs = Array.prototype.slice.call(arguments);
let finalArgs = args.concat(innerArgs);
return self.apply(this instanceof F ? this : context || this, finalArgs);
}
bound.prototype = new F();
return bound;
}
参考文章: JS中的bind()方法