一、前言
本篇文章是记录各种手写实现JavaScript
中的各种操作,如:new
apply
等,如果有你有更好的方法,记得告诉我哦。
二、实现
1. 实现一个new操作符
new
的原理,大致分为四点:
-
创建一个空的对象;
-
让此空对象的__proto__
指向构造函数的原型对象Constructor.prototype
;
-
绑定this
,执行构造函数;
-
返回新对象;
1 2 3 4 5 6 7 8
| function _New(func){ let _tempObj = {}; if(func.prototype !== null){ _tempObj.__proto__ = func.prototype; } let obj = func.apply(_tempObj,Array.prototype.slice.call(arguments,1)); return (typeof obj === "object") ? obj : _tempObj; }
|
2. 实现一个call方法
call
的核心其实是:
-
将函数设置为对象的属性;
-
执行&删除此函数;
-
指定this到函数并传入给定参数执行函数;
-
如果不传入参数,默认指向为window;
1 2 3 4 5 6 7 8
| 简单的 var obj = { a:1, b:function(){ console.log(this.a); } } obj.b();//1
|
1 2 3 4 5 6 7 8
| Function.prototype.ncall = function(contex=window){ contex.fn = this; let args = [...arguments].slice(1); let res = contex.fn(..args); delete contex.fn; return res; }
|
apply
的实现和call
基本一样,只是参数略有不同,如下代码:
1 2 3 4 5 6 7 8 9 10 11 12
| Function.prototype.napply = function(contex = window) { contex.fn = this; let res ; if(arguments[1]){ //有参数 res = contex.fn(...arguments[1]); }else{ res = contex.fn(); } delete context.fn; return res }
|
bind
的实现,会创建一个新函数。当这个新函数被调用时,bind()
的第一个参数将作为它运行时的 this
,之后的一序列参数将会在传递的实参前传入作为它的参数。bind
的实现会借助apply
或者call
;
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Function.prototype.nbind = function(contex = window) { //if (typeof contex !== 'function'){throw Error('not a func')}; //可选 let fn = this; newFunc = function(){}; let arg = Array.prototype.slice.call(arguments,1); let resfunc = function(){ fn.apply(this instanceof newFunc ? this : contex,arg.concat(...arguments)); } if(this.prototype){ newFunc.prototype = this.prototype; } resfunc.prototype = new newFunc(); return resfunc; }
|
bind
的实现有一个难点,bind
返回的函数作为构造函数的时候,bind
时指定的 this
值会失效,但传入的参数依然生效.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| var value = 2;
var foo = { value: 1 };
function bar(name, age) { this.habit = 'shopping'; console.log(this.value); console.log(name); console.log(age); }
bar.prototype.friend = 'kevin';
var bindFoo = bar.bind(foo, 'daisy');
var obj = new bindFoo('18'); // undefined // daisy // 18 console.log(obj.habit); console.log(obj.friend); // shopping // kevin
|
具体参考
3. 实现一个instanceof方法
1 2 3 4 5 6 7 8 9
| function ninstanceof(arg1,arg2){ let proto = arg1.__proto__; let proto2 = arg2.prototype; while(true){ if(proto == proto2) return true; if(proto == null) return false; proto = proto.__proto__;//深度继续往上早; } }
|
4. 实现一个js的深copy
1 2 3 4 5 6 7 8 9 10 11 12 13
| function deepCopy(obj){ var r ; if(typeof obj == "object"){ r = obj.constructor == Array ? [] : {}; for (let i in obj){ r[i] = typeof obj[i] == "object" ? deepCopy(obj[i]) : obj[i]; } }else{ r = obj; } return r; }
|
5. 实现节流和防抖函数
节流:一段时间内函数只执行一次;
防抖:如果事件执行时,又触发了事件,那事件会重新执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| //isDebounce 是否防抖 const throttle = function(fn,delay, isDebounce){ let timer ; let lastTimer = 0; return function(){ if(isDebounce){ //防抖 if(timer) clearTimeout(timer); timer = setTimeout(() => { // Todo... fn(); }, delay) }else{ //节流 let now = new Date().getTime(); if(now - lastTimer < delay)return; lastTimer = now; fn(); } } }
|
三、总结
函数柯里化和promise的原理,菜鸡正在学习中,之后会补充到这。已上有什么错误,请及时联系。