call apply bind sleep
1.自己实现一个call
1)利用对象的方式的形式改变this指针 funcion add; add.call(temObj) 只需要 在temObj对象临时添加一个方法即可 Function.prototype.mycall2=function(context){ context.fn=this; context.fn(); Reflect.deleteProperty(context,'fn') }
2)call还可以携带实参传入 利用函数的arguments截取除了第一个即可 Function.prototype.mycall2=function(context){ var args=[]; for(var i=1;i<arguments.length;i++){ args.push('arguments['+i+']') }; debugger context.fn=this; context.fn(args); //但是args是一个类数组 Reflect.deleteProperty(context,'fn') }
3)实现拆解函数的参数 将args这个类数组拆解为(args[0],args[1],....) Es6可以用扩展运算符
也可以用new Functionvar result = new Function('context', 'arguments', 'context.fn(' + args + ')')(context, arguments)
Es3可以利用eval语法,eval中,args 自动调用 args.toString()方法;而数组中的toString的效果就是[].join(',')
var temArr=[1,2,3]; temArr.toString(); //1,2,3 temArr.join() //1,2,3 temArr.join=temArr.shift temArr.toString() //1
最终效果 context.fn(arguments[1], arguments[2], ...);
Function.prototype.mycall2=function(context){ var args=[]; for(var i=1;i<arguments.length;i++){ args.push('arguments['+i+']') }; context.fn=this; //context.fn(args); eval('context.fn('+args+')') Reflect.deleteProperty(context,'fn') }
function test(x,y){
debugger;
return console.log(x+y+this.name)
}
var temObj={name:'penguin'}
test.mycall2(temObj,1,2)
4)实现当传null时候this指向window;还有有返回值 Function.prototype.mycall2=function(context){ var context = context || window; var args=[]; for(var i=1;i<arguments.length;i++){ args.push('arguments['+i+']') }; context.fn=this; var result=eval('context.fn('+args+')') Reflect.deleteProperty(context,'fn') return result }
参考:https://github.com/mqyqingfeng/Blog/issues/11
实现一个apply
Function.prototype.myApply=function(context,arr){ var context=context||window; context.fn=this; var args=[],result;
for (var i = 0, len = arr.length; i < len; i++) {
args.push('arr[' + i + ']');
}
if(!arr){ result=context.fn() }else{ result=eval('context.fn('+args+')'); } return result; }
1.自己实现一个bind函数 原理:通过apply或者call方法来实现。 (1)初始版本 Function.prototype.bind=function(obj,arg){ var arg=Array.prototype.slice.call(arguments,1); var context=this; return function(newArg){ arg=arg.concat(Array.prototype.slice.call(newArg)); return context.apply(obj,arg); } } (2) 考虑到原型链 为什么要考虑?因为在new 一个bind过生成的新函数的时候,必须的条件是要继承原函数的原型 Function.prototype.bind=function(obj,arg){ var arg=Array.prototype.slice.call(arguments,1); var context=this; var bound=function(newArg){ arg=arg.concat(Array.prototype.slice.call(newArg)); return context.apply(obj,arg); } var F=function(){} //这里需要一个寄生组合继承 F.prototype=context.prototype; bound.prototype=new F(); return bound; }
如何实现sleep的效果(es5或者es6) (1)while循环的方式 function sleep(ms){ var start=Date.now(),expire=start+ms; while(Date.now()<expire); console.log('1111'); return; } 执行sleep(1000)之后,休眠了1000ms之后输出了1111。上述循环的方式缺点很明显,容易造成死循环。 (2)通过promise来实现 function sleep(ms){ var temple=new Promise( (resolve)=>{ console.log(111);setTimeout(resolve,ms) }); return temple } sleep(500).then(function(){ //console.log(222) }) //先输出了111,延迟500ms后输出222 (3)通过async封装 function sleep(ms){ return new Promise((resolve)=>setTimeout(resolve,ms)); } async function test(){ var temple=await sleep(1000); console.log(1111) return temple } test(); //延迟1000ms输出了1111 ####(4).通过generate来实现 function* sleep(ms){ yield new Promise(function(resolve,reject){ console.log(111); setTimeout(resolve,ms); }) } sleep(500).next().value.then(function(){console.log(2222)})
Function._proto_(getPrototypeOf)是什么? 获取一个对象的原型,在chrome中可以通过__proto__的形式,或者在ES6中可以通过Object.getPrototypeOf的形式。 那么Function.proto是什么么?也就是说Function由什么对象继承而来,我们来做如下判别。 Function.__proto__==Object.prototype //false Function.__proto__==Function.prototype//true 复制代码 我们发现Function的原型也是Function。
Function._proto_(getPrototypeOf)是什么?
获取一个对象的原型,在chrome中可以通过__proto__的形式,或者在ES6中可以通过Object.getPrototypeOf的形式。
那么Function.proto是什么么?也就是说Function由什么对象继承而来,我们来做如下判别。
Function.__proto__==Object.prototype //false
Function.__proto__==Function.prototype//true
复制代码
我们发现Function的原型也是Function。