call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
这是MDN上关于call的描述,用通俗的语言解释一下就是:javascript
可能这样解释仍是有些模糊,能够看一个例子:java
function Test(name, age) { console.log(this.name); this.name = name; this.age = age; } var man = { name: 'Wei' }; Test.call(man, 'Willem', 18); // Wei console.log(man.name); // Willem console.log(man.age); // 18
在Test
函数中输出this.name
以前实际上是没有name属性的,可是在执行Test.call(man, 'Willem', 18);
以后却输出了Wei;在man对象
中也是没有age
属性而且name
属性的值为Wei,输出的值倒是Willem。说明在Test函数执行的过程当中this
的值指向了man对象
,而且能够经过call函数向Test函数传递参数。es6
这一通分析下来无非就是一句话:用于函数的call函数能够指定this并传入多个参数。
数组
在开始实现call函数以前,能够思考下如何修改this的指向,其实很简单,直接把目标函数挂载到须要修改的上下文。相似于这种:app
var obj = { name: 'Willem', sayHi: function() { console.log(this.name); } }; obj.sayHi(); /* Willem */
那代码如何实现就很清晰了啊。函数
Function.prototype.wcall = function(context) { context = context || window; // 不传入this时,默认是window context.__fn__ = this; var args = []; for (var i = 1, len = arguments.length; i < len; i++) { args.push('"'+ arguments[i] +'"'); } var ret = eval('context.__fn__(' + args + ')'); delete context.__fn__; return ret; }
上述代码中,为了执行函数因此采用了eval,固然es6的扩展运算符也能够实现相同的功能。对eval
或者js的类型转换不太熟悉的童鞋可能会对eval那段代码会有些疑惑。this
var args = ['a', 'b', 'c']; eval('context.__fn__(' + args + ')'); // 上面的代码其实是两句 // 这实际上要说到js的隐式类型转换了,这里就不过多赘述了 // 只说一点:'string ' + [1, 2] 字符串和数组使用 +, 会将数组转换为一个字符串,和join方法的效果差很少 // 因此'string' + [1, 2] === 'string 1,2' var str = 'context.__fn__(' + args + ')'; // === 'context.__fn__(a,b,c)' // eval()则是会将传入的字符串当作JavaScript代码进行执行 // eval(str) 就至关因而直接执行 context.__fn__(a,b,c) // 能够发现a, b, c其实只是参数字符串而不是变量 // 因此在最开始咱们须要将args的参数都是用字符串进行包裹,wcall代码中:args.push('"'+ arguments[i] +'"') // args = ["'a'", "'b'", "'c'"]; // 'context.__fn__(' + args + ')' === 'context.__fn__("a","b","c")' // 就至关于在直接执行 context.__fn__("a","b","c") eval(str);
以上就是关于call的实现。prototype
apply() 方法调用一个具备给定this值的函数,以及做为一个数组(或相似数组对象)提供的参数。
原理啥的就很少说了,apply和call的做用是同样的,区别是apply是将参数做为一个数组传入,而call是将参数一个一个的传入。直接上代码:code
Function.prototype.wapply = function(context, args) { context = context || window; context.__fn__ = this; var ret; if (!args || !(args instanceof Array) || args.length === 0) { ret = context.__fn__(); } else { var arr = []; for (var i = 0; i < args.length; i++) { arr.push('"' + args[i] + '"'); } ret = eval('context.__fn__(' + arr + ')'); } return ret; }
以上就是关于apply的实现。对象