call的实现
call的作用有两点:1.改变this 2.让函数执行
实现call之前,简单梳理一下:
1.call的第一个参数可以为null,undefined,当为null和undefined的时候,函数中的this指向window
2.函数的返回值可以顺利返回
3.当第一个参数传入基本类型的数据时 会被包装成对象
Function.prototype.myCall = function (thisArgs, ...args) {
var _this = this;
// 如果是简单类型就包装一下 如果是null或者undefined 就返回window
thisArgs = thisArgs == null ? window : Object(thisArgs)
var fn = Symbol('fn');//避免属性被覆盖
thisArgs[fn]= _this;
var res = thisArgs[fn](...args); // 采用默认绑定 让调用hycall的函数中this指向thisArgs
delete thisArgs[fn];
return res
}
到这里就完成了call的原理实现,这里再给大家出一道题,测试一下自己对call的理解
我们的函数执行可以用aaa.call()来执行,也可以直接aaa()来执行
function aaa(){
console.log('aaa')
}
aaa()//aaa
aaa.call()//aaa
下面的例子中fn中的this是{name: 'yql'}, "hello"和world是传给fn的参数
function fn(a, b) {
console.log(this); // { name: 'yql' }
console.log(a, b); // hello world
}
fn.call({ name: "yql" }, "hello", "world")
最后我们再看一下多次call的例子:
function fn(){
console.log(this)
}
function fn1(a, b){
console.log('100')
console.log(a, b)
}
fn.call.call.call.call(fn1, 'hello', 'world') ?
有了上面两个小例子作为基础,多次call也方便理解了,首先不管写几个call 都是call方法本身去调了一下call(fn1),最后可以简写成call.call(fn1), 也就是call方法中的this是fn1,最后相当于执行fn1.call(),也就是fn1执行,所以最后打印出100,"world", "undefined"
apply的实现
apply的作用有两点:1.改变this 2.让函数执行
apply实现之前,简单梳理一下:
1.当apply的第二个参数可以不传
2.apply第二个参数必须是一个数组
3.其余跟call一样
Function.prototype.myApply = function (thisArgs, args) {
var _this = this;
// 如果是简单类型就包装一下 如果是null或者是undefined 就返回window
thisArgs = thisArgs == null ? window : Object(thisArgs)
var fn = Symbol('fn');//避免属性被覆盖
thisArgs[fn] = _this;
args = args || [] //没有传参数的时候 args是undefined 不能用展开运算符
var res = thisArgs[fn](...args); // 默认绑定 函数中this指向thisArgs
delete thisArgs[fn];
return res
}
bind的实现
bind的作用:1.返回一个新函数2.改变this,3.需要手动调用执行
bind的实现之前,简单梳理一下:
1.调bind会返回一个函数
2.函数的参数可以分开传,也可以一次性传
3.其余跟call一样
Function.prototype.myBind = function (thisArgs, ...argsArray) {
var _this = this;
thisArgs = thisArgs == null ? window : Object(thisArgs)
return function (...args) {
var fn = Symbol('fn');
thisArgs[fn]= _this;
args = args || [] //没有传参数的时候 args是undefined 不能用展开运算符
var res = thisArgs[fn](...argsArray, ...args); // 参数拼接
delete thisArgs[fn];
return res
}
}
function sum1(num1, num2, num3, num4) {
return num1 + num2 + num3 + num4
}
// 使用方式 参数可以分开传 也可以一次性传完
var fn = sum1.bind('abc', 10, 20)
var result = fn(30, 40)
var foo = {
value: 1,
bar: function() {
console.log(this.value)
}
};
foo.bar(); // 1