手写 bind 函数
bind定义:Function.prototype.bind() - JavaScript | MDN (mozilla.org)
注意:绑定函数也可以使用 new
运算符构造,它会表现为目标函数已经被构建完毕了似的。提供的 this
值会被忽略,但前置参数仍会提供给模拟函数。
简易版
// 模拟 bind(简易版)
Function.prototype.bind1 = function () {
// 将参数拆解为数组
const args = Array.prototype.slice.call(arguments)
// 获取 this(数组第一项)
const t = args.shift()
// fn1.bind(...) 中的 fn1
const self = this
// 返回一个函数
return function () {
return self.apply(t, args)
}
}
function fn1(a, b, c) {
console.log('this', this)
console.log(a, b, c)
return 'this is fn1'
}
const fn2 = fn1.bind1({x: 100}, 10, 20, 30)
const res = fn2()
console.log(res)
完整版:
参考:js 手动实现bind方法,超详细思路分析! - 听风是风 - 博客园 (cnblogs.com)
Function.prototype.bind_ = function () {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
};
var args = Array.prototype.slice.call(arguments[0], 1);
var obj = arguments[0]
var fn = this;
//创建中介函数(让fn的实例多了一层__proto__,达到修改原型不会影响fn原型的目的)
var fn_ = function () {};
var bound = function () {
var params = Array.prototype.slice.call(arguments);
// 当成构造函数调用时,构造函数中会创建一个实例对象,函数内部的this指向此实例
//可通过constructor判断调用方式,为true this指向实例,否则为obj
fn.apply(this.constructor === fn ? this : obj, args.concat(params));
console.log(this);
};
fn_.prototype = fn.prototype;
bound.prototype = new fn_();
return bound;
};
// 实际上多了个new 调用时的构造函数的判断,并实现对调用函数的继承
// 可使用寄生组合继承优化
Function.prototype.bind_ = function (obj, ...args) {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
};
var fn = this;
var bound = function () {
//通过constructor判断调用方式,为true this指向实例,否则为obj
fn.apply(this.constructor === fn ? this : obj, [...args, ...arguments]);
console.log(this);
};
bound.prototype = Object.create(fn.prototype)
return bound;
};
完整简化版:
Function.prototype.myBind = function(thisArg, ...arg1) {
const _this = this;
return function _a (...arg2) {
const params = [...arg1, ...arg2];
if(this instanceof _a) {
return new _this(...params);
}
else {
return _this.apply(thisArg, params);
}
}
}
JS 实现 call 和 apply
参考:www.cnblogs.com/echolun/p/1…
call 和 apply 的区别
除了都能改变this指向并执行函数,call与apply唯一区别在于参数不同
var fn = function (arg1, arg2) {
// do something
};
fn.call(this, arg1, arg2); // 参数散列
fn.apply(this, [arg1, arg2]) // 参数使用数组包裹
call 和 apply 的使用场景
检验数据类型:
function type(obj) {
var regexp = /\s(\w+)]/;
var result = regexp.exec(Object.prototype.toString.call(obj))[1];
return result;
};
console.log(type([123]));//Array
console.log(type('123'));//String
console.log(type(123));//Number
console.log(type(null));//Null
console.log(type(undefined));//Undefined
函数arguments类数组操作:
var fn = function () {
var arr = Array.prototype.slice.call(arguments);
console.log(arr); //[1, 2, 3, 4]
};
fn(1, 2, 3, 4);
es6实现:
// ES6 call
Function.prototype.call_ = function (obj, ...args) {
//判断是否为null或者undefined,同时考虑传递参数不是对象情况
obj = obj ? Object(obj) : window;
obj.fn = this;
// 利用拓展运算符直接将arguments转为数组
// let args = [...arguments].slice(1);
let result = obj.fn(...args);
delete obj.fn
return result;
};
// ES6 apply
Function.prototype.apply_ = function (obj, arr) {
obj = obj ? Object(obj) : window;
obj.fn = this;
const result = obj.fn(...(arr || []));
delete obj.fn
return result;
};