面试题十九:手写call()、apply()和bind()-Qui-Note

要想实现手写call,必须知道call()这个函数的定义,如何使用?有什么特点?

call

call()定义

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

call()语法

function.call(thisArg, arg1, arg2, ...)
  • thisArg,this指向,可以省略!
  • arg1...参数

手写call()

知道了call的定义和特点,就可以来实现其方法了,另外call是在function函数的原型上:

Function.prototype.mycall = function(content){
	if(typeof this != 'function'){
		throw new TypeError('this is not a function')
	}
	let ctx = content || window   // 未传值时指向window
	ctx.fn = this  // 找到调用的方法
	let args = Array.from(arguments).slice(1)  // 拷贝参数
	let res = args ? ctx.fn(...args) : ctx.fn()   // 创建一个 新对象,改变this指向
	delete ctx.fn    // 删除 上下文 避免全局污染
	return res
}

同样的,要想实现手写apply,必须知道apply()这个函数的定义,如何使用?有什么特点?

apply

apply()定义

apply() 方法调用一个具有给定this值的函数,以及以一个数组(或类数组对象)的形式提供的参数。

apply()语法

function.apply(thisArg, [argsArray])
  • thisArg,this指向,可以省略!
  • [argsArray],数组参数

手写apply()

根据apply的特点,就可以实现一个apply了:

Function.prototype.myApply = function(content){
	if(typeof this != 'function'){
		throw new TypeError('this is not a function')
	}
	let ctx = content || window   // 未传值时指向window
	ctx.fn = this  // 找到调用的方法
	let args = arguments[1]  // 拷贝参数
	let res = args ? ctx.fn(...args) : ctx.fn()   // 创建一个 新对象,改变this指向
	delete ctx.fn    // 删除 上下文 避免全局污染
	return res
}

apply和call很像,就是传参不一样,所以手写的函数也是 拷贝参数的方法不一样! 最后一个bind,和这两个不一样!

bind

bind()定义

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

bind()语法

function.bind(thisArg[, arg1[, arg2[, ...]]])

  • thisArg,this指向,可以省略!
  • arg1...参数

 

手写bind()

Function.prototype.myBind = function(content){
    if(typeof this != 'function'){
		throw new TypeError('this is not a function')
	}
    let that = this;
    let args = Array.prototype.slice.call(arguments,1);
    let Fn = function(){}
    Fn.prototype = this.prototype;
    let binds = function(){
    	let bindArgs = Array.prototype.slice.call(arguments);
    	return that.apply(this instanceof Fn ? this : content,args.concat(bindArgs))
    }
    binds.prototype = new Fn();
    return binds;
}