call
call()方法在使用一个指定的this的值和若干个指定的参数值的前提下调用某个函数或方法。
var foo = {
value: 1
}
function bar() {
console.log(this.val)
}
bar.call(foo) // 1
注意两点:
- call改变了bar的this指向,指向到foo
- bar执行了
模拟实现第一步
模拟实现的思路为:
- 将函数设为对象的属性
- 执行该函数
- 删除该函数
按照这个思路,尝试着去写第一版call2函数
Function.prototype.call2 = function(context) {
context.fn = this
context.fn()
delete context.fn
}
// 测试
bar.call2(foo)
模拟实现第二步
call函数可以给定参数执行函数
var foo = {
value: 1
}
function bar(name, age) {
console.log(name, age)
console.log(this.value)
}
bar.call(foo, 'kack', 19) // 'kack' 19 1
但是参数并不是固定的,这里我们可以从Arguments中取值,取出第二个到最后一个参数,然后放到一个数组中。
第二版改造
Function.prototype.call2 = function(context) {
context.fn = this
var args = []
for(var i = 1; i < arguments.length; i++) {
args.push('arguments[' + i + ']')
}
eval('context.fn('+ args +')')
delete context.fn
}
bar.call2(foo, 'kack', 19) // 'kack' 19 1
模拟实现第三步
1、this参数可以为null,当为null的时候,视为指向window
2、函数时可以有返回值的
Function.prototype.call2 = function(context) {
var context = context || window
context.fn = this
var args = []
for(var i = 1; i < arguments.length; i++) {
args.push('arguments[' + i + ']')
}
var reslut = eval('context.fn('+ args +')')
delete context.fn
return reslut
}
apply的模拟实现
apply与call类似,apply的参数定义不一样,基本原理是一样的
// call
bar.call(fn, 'kack', 19)
// apply
bar.apply(fn, ['kack', 19])
实现代码
Function.prototype.apply2 = function(context, arr) {
var context = Object(context) || window
context.fn = this
var reslut
if(!arr) {
reslut = context.fn()
} else {
var args = []
for(var i = 0; i < arr.length; i++) {
args.push('arr['+i+']')
}
reslut = eval('context.fn(' + args +')')
}
delete context.fn
return reslut
}