call,apply,bind源码实现

1,719 阅读2分钟

1,call和apply

callapply非常相似,都是在函数调用时,改变函数的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的属性。