一、call
1.开始
我们先看下原生 call 做了什么事
1 2 3 4 5 6 7 8 9 10 11 12 13
| function bar(name,age){ this.hobby = 'shopping'; console.log(this.value); console.log(this.hobby); console.log(name); console.log(age); } bar.prototype.friend = 'kevin'; var obj = { hobby: 'gamming' }
var hah = bar.call(obj,'jack',18);
|
输出是:
这说明 call 只是修改了 this 的指向,没有返回对象。
2.模拟实现
所以我们只要尝试着去修改 this 的指向并执行就行了,不需要有返回值:
1 2 3 4 5 6 7 8 9 10 11
| Function.prototype.calls = function(){ var dir = arguments[0]; var args = []; for(var i = 1; i < arguments.length; i++){ args.push(arguments[i]) }; dir.pau = this; // 这里用到了ES6的新特性,不好 dir.pau(...args); delete dir.pau; }
|
eval 实现
1 2
| eval('dir.pau(' + args +')'); delete dir.pau;
|
二、apply
apply 的功能和 call 一样只不过是参数是由一个数组传递
1 2 3 4 5 6 7 8
| Function.prototype.applys = function(){ var dir = arguments[0]; var args = []; dir.pau = this; // 这里用到了ES6的新特性,不好 dir.pau(...arguments[1]); delete dir.pau; }
|
三、bind
1.开始
假设我们有一个函数,一个对象
1 2 3 4 5 6 7 8 9 10
| var foo = { value:1 } function bar(name,age){ this.hobby = 'shopping'; console.log(this.value); console.log(name); console.log(age); } bar.prototype.friend = 'kevin';
|
我们试一试用原生的 bind 可以输出什么:
1 2
| var bindFoo = bar.bind(foo, 'daisy'); var obj = new bindFoo('18');
|
可以看到指定原型链,指定了 this,bind 的同时可以传参数。
① 指定 this,bind 的同时穿参数:
我们知道 bind 返回一个函数并绑定了 this,这个模拟起来比较简单
1 2 3 4 5 6 7 8
| Function.prototype.binds = function(dir){ var self = this; var _args = [].slice.call(arguments,1); return function(){ var args = _args.cancat([].slice.call(arguments)); self.apply(dir,args); } }
|
② 指定原型链的指向,即 prototype 的指向:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Function.prototype.binds = function(dir){ var self = this; var _args = [].slice.call(arguments,1);
var inn = function(){ var args = _args.concat([].slice.call(arguments)); self.apply(dir,args); }
inn.prototype = new dir(); inn.prototype.constructor = inn;
return inn; }
|
到这里,如果不去 new 出一个实例的话,都可以了,如果需要 new 出一个实例来,我们就需要重新指定下 this,因为如果使用 new 操作符会把 this 指向新创建的对象,但我们还是需要他指向原本指向的对象,所以,我们要判断当前调用对象是否为原对象的一个实例属性,修改后的代码为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Function.prototype.binds = function(dir){ var self = this; var _args = [].slice.call(arguments,1);
var inn = function(){ var args = _args.concat([].slice.call(arguments)); self.apply(this instanceof self ? this : dir,args); }
inn.prototype = new self(); inn.prototype.constructor = inn;
return inn; }
|
到这里,我们应该已经完成了对 bind 的模拟,输出看下结果:
多出的几个 undefined 是在 new 时产生。