call()
特点:
- 被函数调用(函数也是对象),相当于 call 和 apply 是函数的属性
- 如果没有传入需要 this 指向对象,那么 this 指向全局对象
- 函数执行了
- 最后改变了 this 的指向
Function.prototype.newCall = function(context){
//判断context是否为object,如果是object就代表可能是Object 或者 null,
//如果不是就赋值一个空对象
if (typeof context === 'object') {
//context 如果是null就会赋值为window
context = context || window
} else {
context = Object.create(null)
}
//在context下挂载一个函数,函数所在的key随机生成,防止context上已有同名key,
//用时间戳+随机数拼接成一个随机字符串作为一个新的key
var fn = +new Date() + '' + Math.random()
context[fn] = this
//newCall如果还有其他的参数传入也要考虑用到
var args = []
for(var i = 1; i < arguments.length; i++) {
args.push('arguments['+ i + ']')
}
//使用eval执行context[fn]这个函数,因为newCall的入参参数不确定,
//args是一个数组,但是当它和字符串相加时自动调用内部的toString方法转成字符串
var result = eval('context[fn]('+args+')')
//用完后从context上删除这个函数
delete context[fn]
//返回结果
return result
}
apply()
apply与call原理基本一样,只是入参不一样
Function.prototype.newApply = function(context, array){
//通过Array接受入参是数组,这个参数便确定了,不需要从argument那里取参数
if (typeof context === 'object') {
context = context || window
} else {
context = Object.create(null)
}
var fn = +new Date() + '' + Math.random()
context[fn] = this
var args = []
if(array){
for(var i = 0; i < array.length; i++) {
args.push('array['+ i + ']')
}
}
var result = eval('context[fn]('+args+')')
delete context[fn]
return result
}
bind()
特点:
- 返回一个函数
- 函数参数以逗号的形式传入
- 改变了 this 的指向
- bind()返回的函数作为构造函数时,搭配new关键字出现的话,this绑定需要被忽略。
Function.prototype.newBind = function(context){
if(typeof this !=== 'function'){
throw new TypeError('Function.prototype.bind - what is trying to be bound is not calleble')
}
var self = this;
//间接调用数组方法,获取第一次传的参数
var args = Array.protrtype.slice.call(arguments,1);
//利用一个空函数做中转
let tempFun = function(){};
//修改返回函数的prototype属性,以实现继承绑定函数原型中的值
tempFun.prototype = this.prototype;
var resultFun = function(){
var innerArgs = Array.prototype.slice(arguments);
//如果返回函数被当做构造函数后,生成的对象是tempFun的实例,
//此时应将this执行创建的实例
if(this instanceof tempFun){
return fn.apply(this,args.concat(innerArgs));
}else{
return self.apply(context,args.concat(innerArgs));
}
}
resultFun = new TempFun();
return resultFun;
}})
总结
1. eval(),计算某个字符串,并执行其中的的 JavaScript 代码
2. bind()与 call(),apply()的区别在于,bind()返回一个指定了 this 的函数,函数并未执行。其次,当返回的函数作为构造函数时,之前绑定的 this 会失效。