JavaScript之call模拟实现
call
-
call()方法在使用指定的this值和若干个指定的参数值的前提下调用某个函数和方法。
var obj = {
value : 1
}
function foo(){
console.log(this.value)
}
foo.call(obj)
注意:
-
call改变了this的指向,指向到obj
-
foo函数执行了
模拟实现第一步
试想当调用 call 的时候,把obj对象改造成如下
var obj = {
value :1,
foo : function(){
console.log(this.value)
}
}
obj.foo()
这个时候this就指向了obj
但是这样却给obj对象上添加了一个属性。
这样可不行,我们用
delete 删除掉就好了。
所以我们模拟步骤可以分为:
-
将函数设置为对象的属性
-
执行该函数
-
删除该函数
以上个例子为例,就是:
// 第一步
obj.fn=foo
// 第二步
obj.fn()
// 第三步
deleteobj.fn
按照这个思路,尝试写第一版call2函数
Function.prototype.call2 = function(context){
context.fn=this
context.fn()
delete context.fn
}
var obj = {
value : 2
}
function foo(){
console.log(this.value)
}
foo.call2(obj)
模拟实现第二步
一开始也有提到,call 函数还能指定参数执行函数
var obj = {
value : 1
}
function foo(name,age){
console.log(name)// hy
console.log(age)// 18
console.log(this.value)// 1
}
foo.call(obj,'hy',18)
注意: 传入的参数不确定,该怎么办!
我们可以从Arguments对象中取值,取出第二个到最后一个参数,然后放到一个数组里。
var args = []
for(let i=1; i<arguments.length; i++) {
args.push('arguments['+i+']');
}
不定长的参数问题解决了,我们接着要把这个参数数组放到要执行的函数的参数里面去。
eval('context.fn('+ args +')')
第二版代码如下:
Function.prototype.call2 = function(context){
context.fn=this
var args = []
for(let i=1; i<arguments.length; i++) {
args.push('arguments['+i+']');
}
eval('context.fn('+args+')');
delete context.fn
}
var obj = {
value :2
}
function foo(name,age){
console.log(name)
console.log(age)
console.log(this.value)
}
foo.call2(obj,'hy',18)
模拟实现第三步
还有两个地方需要注意:
-
this参数可以传null,当为null的时候this指向window
var value = 1
function foo(){
console.log(this.value)
}
foo.call(null)// 1
2. 函数是可以有返回值的
var obj = {
value :1
}
function foo(name,age){
return{
value : this.value,
name : name,
age : age
}
}
console.log(foo.call(obj,'hy',18))// { value: 1, name: 'hy', age: 18 }
到目前为止已经完成了 call 的模拟
Function.prototype.call2 = function(context){
context.fn=this
var args = []
for(leti=1;i<arguments.length;i++) {
args.push('arguments['+i+']');
}
var result = eval('context.fn('+args+')');
delete context.fn
return result
}
var obj = {
value : 2
}
function foo(name,age){
return{
value : this.value,
name : name,
age : age
}
}
console.log(foo.call2(obj,'hy',18))