Function的prototype原型上存放着 Function实例 的一些共有方法。
A.Function的原型不像其余类(Array、Object...)的原型同样是个对象,Fuction的原型是一个空函数,是能够执行的,只不过返回undefined,Function.prototype();可是这并不影响它做为一个对象拥有本身的属性方法
B.Function这个类,同时也是Function的一个实例,因此它也具有__proto__属性,这个属性指向它本身的原型数组
1.call方法。每一个函数均可以调用call方法,来改变当前这个函数执行的this关键字,而且支持传入参数;咱们用原生js模拟call方法,来更加深入了解它。
a.第一个参数为调用call方法的函数中的this指向
b.第二个及之后的参数为给调用call方法的函数传入的参数
c.执行这个函数,call方法返回的结果就是 调用他的函数返回的结果
d.将this指向销毁。app
Function.prototype.mycall = function(context){ context = context || window; context.fn = this; var arr = []; for(var i = 1;i<arguments.length;i++){ arr.push('arguments['+i+']'); } var result = eval('context.fn('+arr.toString()+')'); delete context.fn; return result; } var obj = {name:'qiaoshi'}; var a = {sex:1} function say(n){ console.log(this,n); } say.mycall(obj,a)
2.apply和call方法相似,做用都是改变当前函数执行的this指向,而且将函数执行。
惟一不一样就是 call方法给当前函数传参是一个一个传。而apply是以数组方式传入参数函数
Function.prototype.myApply =function(context,arr){ context = Object(context) || window; context.fn = this; var result; if(!arr){ result= context.fn(); }else{ var args = []; for(var i=0;i<arr.length;i++){ args.push('arr['+i+']'); } result = eval('context.fn('+args.toString()+')') } delete context.fn; return result; } var q = {name:'chuchu'}; var arg1 = 1; var arg2= [123] function eat(n,m){ console.log(this,n,m); } eat.myApply(q,[arg1,arg2])
3.bind方法,是改变当前调用bind方法的函数this指向,可是不会当即执行当前函数,而是返回一个新的函数。而且支持给新的函数传入参数执行,从而出发以前调用bind方法的函数执行,而且参数透传进去。bind方法是高阶函数的一种。this
Function.prototype.myBind = function(){ var context = arguments[0]; var self = this; return function (){ self.myApply(context,arguments) } }; var j = {name:1}; var k = [123] function drink (k){ console.log(this.name,k); } var fn = drink.myBind(j); fn(k);
实现原生 call、apply、bind方法的重点:
1.改变this指向:函数执行,点.前面是谁,this就是谁的原理改变this指向
2.参数透传:经过eval将字符串转变成js语法 去执行。
3.bind方法返回一个函数,返回的函数执行,会进行做用域查找context对象;而且经过原型链查找调用apply方法prototype
call、apply、bind相同和区别
相同:都能改变函数执行的this指向
不一样:callapply 是当即执行 bind是不执行code
call传参是一个一个传入,apply是数组形式传入对象