一.重写bind方法
p1.play.call(p2, '男'); // call会改变this指向并立即执行
p1.play.bind(p2, ['男', 20]); //bind会改变this指向后返回一个新的函数,不执行
Function.prototype.bindy = function(context){
var _self = this;
return function(){
_self.apply(context);
}
}
在写一个匿名函数是因为要求不执行,其次保存this是因为匿名函数的中的this指向的是window
Function.prototype.bindy = function(context){
var _self = this,
args = Array.prototype.slice.call(arguments, 1);
return function(){
var newArgs = Array.prototype.slice.call(arguments);
_self.apply(context, args.concat(newArgs));
}
}
利用slice的方法截取arguments的第二位以后的形参。通过contcat连接两种方式的传值
Person.bindy(p, 'zza')('zzb');
有参数要考虑三种情况,第一种是在调用的时候传参,第二种是在执行的时候传参,第三种是都传。
var p ={
age: 20
}
function Person(name,sex){
console.log(this.age);
console.log(name, sex);
}
Function.prototype.bindy = function(context){
var _self = this,
args = Array.prototype.slice.call(arguments, 1);
var fn = function(){
var newArg = Array.prototype.slice.call(arguments);
_self.apply(this instanceof _self ? this : context, args.concat(newArg))
}
fn.prototype = this.prototype;
return fn;
}
var ar = Person.bindy(p, '张三');
new ar('15');
将返回的匿名函数赋值给一个变量,这时候再将变量的原型指向为调用函数的属性的原型。这时候判断如果当前的作用域是由当前调用函数的属性创建的,则将this指向为调用函数的属性(实例化对象),如果不是,则照常处理。
其中fn.prototype = this.prototype;的作用:
实例化后this无论如何都是指向实例化对象的。但是constructor是不同的,不赋值原型的话构造器是指向fn的,这样就会导致判断失效一直为false。
所以将fn的原型改为当前调用函数的属性的原型,这样就可以让判断生效了,如果为实例化的对象,在instanceof中this指向的是实例化对象,constructor却为Person.没有实例化的,则this直接指向window。
Function.prototype.bindy = function(context){
var _self = this,
args = Array.prototype.slice.call(arguments, 1),
tempFn = function(){},
fn = function(){
var newArg = Array.prototype.slice.call(arguments);
_self.apply(this instanceof _self ? this : context, args.concat(newArg))
}
tempFn.prototype = this.prototype;
fn.prototype = new tempFn();
return fn;
}