// 首先看下原生的js的call()
var obj = {
name: 'Nicholas S.Zakas',
age: 41,
from: 'America',
getName: function (prefix) {
// console.log(prefix + this.name)
return prefix + this.name
}
}
var obj2 = {
name: 'Evan You',
age: '35',
from: 'China'
}
console.log(obj.getName.call(obj2, 'hello, everyone, i am '))
// hello, everyone, i am Evan You
// call()做了什么?
// 1、将调用call的函数的this指向call函数的第一个参数
// 2、将call()第一个参数后的参数作为调用call函数的形参
Function.prototype._call = function (context) {
var result
var args = [].slice.apply(arguments, [1])
context.fn = this
result = context.fn(...args)
delete context.fn
return result
}
// 不使用 apply 函数的实现
Function.prototype._newCall = function (context) {
var args = []
var result
for (var i = 1; i < arguments.length; i++) {
args.push('arguments[' + i + ']')
}
context.fn = this
result = eval('context.fn(' + args + ')')
delete context.fn
return result
}
console.log(obj.getName._newCall(obj2, 'hello, everyone, i am '));
// hello, everyone, i am Evan You
// ECMAScript6 的实现
Function.prototype._es6Call = function (context, ...args) {
const fn = Symbol();
context[fn] = this;
const result = context[fn](...args);
delete context[fn];
return result;
}
console.log(obj.getName._es6Call(obj2, 'hello, everyone, i am '));
// hello, everyone, i am Evan You
在 context 上添加 fn 属性的目的其实就是在 call 的目标对象 obj 上添加一个属性 fn,使用了 js 语言特有的 this 隐式上下文绑定关系,如:
const obj = {
a: 1,
test: function(){
console.log(this.a)
}
}
这里调用 obj.test()
test 函数内部打印的 this 指针就是指向 obj,我们手写的 call 函数就是利用这一特性实现了所谓 this 指针的改变。