bind的实现
const data = {
name: 'zd',
age: 23,
}
Function.prototype.bind = function (content) {
// this为要调用的函数
let that = this
// 拿到bind的传参
const args = [].slice.apply(arguments, [1])
// 生命一个空函数为创建实例使用原型链的转移
function Fn() {}
function fBound() {
// 通过判断this instanceof fBound 判断是new 出来的的函数直接调用,直接调用的作用域为content,
// new 出来的this为当前的this
that.apply(this instanceof fBound ? this : content, [...args, ...arguments])
}
// 当new出来的函数有原型链的修改,需要将原型链的方法拿到并转移到Fn的原型链上
Fn.prototype = this.prototype
// 最后将fBound的原型链等于Fn的实例,fBound即可调用bindFn原型链上的属性
fBound.prototype = new Fn()
return fBound
}
function fn(name, age) {
console.log('this', this)
console.log('this.name', this.name + '养了一只' + name + age + '岁了')
}
fn.prototype.flag = '哺乳动物'
const bindFn = fn.bind(data, '猫')
// 普通调用测试
bindFn(9)
// 原型链测试
const instance = new bindFn(9)
console.log('instance', instance)
console.log('instance', instance.flag)
//以下输出为
this { name: 'zd', age: 23 }
this.name zd养了一只猫9岁了
this fn {}
this.name undefined养了一只猫9岁了
instance fn {}
instance 哺乳动物
call的实现
Function.prototype.newCall = function () {
var ctx = arguments[0] || window;
ctx.fn = this;
var args = [];
for (var i = 1; i < arguments.length; i++) {
args.push(arguments[i]);
}
var results = eval('ctx.fn(' + args.join(",") + ')')
}
apply的实现
Function.prototype.newApply = function (ctx, arr) {
ctx = ctx || window;
ctx.fn = this;
if (!arr) {
var result = ctx.fn();
delete ctx.fn;
return result;
} else {
var result = eval('ctx.fn(' + arr.join(",") + ')');
delete ctx.fn;
return result;
}
}