1,call和apply
call和apply非常相似,都是在函数调用时,改变函数的this指向,返回值都是使用调用者提供的this值和参数调用该函数的返回值,若该方法没有返回值,则返回undefined。所不同的是call方法接收的是一个参数列表,而apply方法接收的是一个包含多个参数的数组。
2,call
call语法:
function.call(thisArg,arg1,arg2,...)
thisArg是函数运行时指定的this值,如果传入null或者undefined则会自动替换指向为全局对象;如果是原始值,则会被包装。
arg1,arg2,...是指定的参数列表;
根据以上用法自己实现代码如下:
Function.prototype.mycall = function (thisArg) {
//判断this是否是函数,不是则报错
if (typeof this !== 'function') {
throw new TypeError('this is not a function');
}
//使用symbol创建一个唯一变量
const fn = Symbol('fn');
//截取第二位已经之后传入的所有参数,作为函数调用时的参数列表
const args = [].splice.call(arguments, 1);
// thisArg为null或者undefined,则指向window
thisArg = thisArg || window;
thisArg[fn] = this;
const result = thisArg[fn](...args);
delete thisArg[fn];
return result;
};
3,apply
apply语法:
function.apply(thisArg,[argsArr])
thisArg是函数运行时指定的this值,如果传入null或者undefined则会自动替换指向为全局对象;如果是原始值,则会被包装。
[argsArr]是传入的参数数组;
所以apply源码实现如下:
Function.prototype.myapply = function (thisArg) {
if (typeof this !== 'function') {
throw new TypeError('this is not a function');
}
let args = arguments[1];
thisArg = thisArg || window;
let fn = Symbol('fn');
thisArg[fn] = this;
let result = thisArg[fn](...args);
delete thisArg[fn];
return result;
};
4,bind
bind() 方法创建一个新的函数,在bind()被调用时,这个新函数的this被指定为bind()的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
Function.prototype.bind = function (target) {
if (typeof this !== 'function') {
throw new TypeError('Bind must be called on a function');
}
let self = this;
let args = [].slice.call(arguments, 1);
let temp = function () {};
let f = function () {
let _arg = [].slice.call(arguments, 0);
target = target || window;
return self.apply(
this instanceof temp ? this : target,
args.concat(_arg)
);
};
temp.prototype = self.prototype;
f.prototype = new temp();
return f;
};
如果使用new运算符构造绑定函数,则会改变this指向,this指向当前的实例。
通过temp链接原型,这样f就可以通过原型链访问父类temp的属性。