实现洋葱模型 redux.compose
// newFn = compose(fn1, fn2 ,fn3, fn4, fn5)
// newFn(...args) <=> fn1(fn2(fn3(...fnk(...args))))
// fn1 = a => a + 1
// fn2 = a => a + 10
// fn3 = a => a + 100
// fn4 = a => a + 1000
// fn5 = (a,b,c,d,e,f) => a + b + c + d + e + f
// newFn = compose(fn1, fn2, fn3, fn4, fn5)
// newFn(1,2,3,4,5,6) == 1132 // 等价于下面
// fn1(fn2(fn3(fn4(fn5(1,2,3,4,5))))) == 1132 // true
function compose(...funcs) {
return function proxy(...args) {
let len = funcs.length
if (len === 0) {
return args
} else if (len === 1) {
return funcs[0](...args)
} else {
return funcs.reverse().reduce((prev, cur) => {
return typeof prev === "function" ? cur(prev(...args)) : cur(prev)
})
}
}
}
重写new
function _new(Ctor,...params){
let obj={}
obj.__proto__ = Ctor.prototype;
let result = Ctor.call(obj,...params)
if(typeof result == "object" || typeof result == "function") {
return result
} else {
return obj
}
}
防抖
主体思路:在当前点击完成后,我们等wait这么长的时间,看是否还会触发第二次,如果没有触发第二次,属于非频繁操作,我们直接执行想要执行的函数func;如果触发了第二次,则以前的不算了,从当前这次再开始等待
function debounce(func, wait = 300, immediate = false) {
let timer = null;
return function annoymous(...params) {
let now = immediate && !timer;
clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
!immediate ? func.call(this, ...params) : null;
}, wait);
now ? func.call(this, ...params) : null
}
}
function sayHi() {
console.log("防抖成功");
}
var inp = document.getElementById("inp");
inp.addEventListener("input", debounce(sayHi,300));
节流
function throttle(func,wait=300){
let timer = null,
previous = 0;
return function annoymous(...params){
let now = new Date(),
remaining=wait - (now - previous);
if(remaining<=0){
timer = null;
window.clearTimeout(timer)
previous = now;
func.call(this,...parems)
} else if(!timer) {
timer = setTimeout(()=>{
timer = null;
previous = new Date();
func.call(this,...params)
},remaining)
}
}
}
function sayHi(e) {
console.log(e.target.innerWidth, e.target.innerHeight);
}
window.addEventListener("resize", throttle(sayHi,3000));
重写call、apply
Function.prototype.call = function call(context, ...params) {
//fn.call=>call中的this是fn
//this->fn 当前执行的函数
//context->obj 需要改变的this
//params->[10,20]需要函数传递的实参信息
if (context == null) {
context = window
}
if (typeof context !== "object"||typeof context !=='function') {
context = Object(context)
}
let key = Symbol("key")
context[key] = this
//this要执行的函数
let result = context[key](...params)
delete context[key]
return result
}
let a = "1"
function fn() {
console.log(this)
}
fn()
重写bind
事件触发/定时器到时间执行对应方法
原理:闭包、柯里化
Function.prototype.bind = function bind(context,...params){
let that = this
return function proxy(...args){
匿名函数中的this是当前元素
params = params.concat(args)
return that.call(context,...params);
}
}
function foo(name) {
this.name = name;
}
let obj = {};
let bar = foo.bind(obj);
bar("jack");
console.log(obj.name);
let tar = foo.bind(obj, "rose");
tar();
console.log(obj.name);
let alice = new bar("alice");
console.log(obj.name);
console.log(alice.name);
重写instanceof
function instance_of(obj, constructor) {
let proto = obj.__proto__,
prototype = constructor.prototype
while (true) {
if (proto === null) return false
//找到Object.prototype.__proto__都没有相等的,则证明不是当前累的实例
if (proto === prototype) return true
//找到对象的原型链包含类的原型,则证明对象是类的一个实例
proto = proto.__proto__
//一级级查找
}
}
console.log(instance_of([],Array))
console.log(instance_of([],RegExp))
类的继承
组合继承
function Parent(){
this.x =100
}
Parent.prototype.getX = function getX(){
return this.x
}
function Child(){
Parent.call(this)
this.y = 200
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
Child.prototype.getY = function getY(){
return this.y
}
let c1 = new Child
console.log(c1)
题干
function Parent() {
this.x = 100
}
Parent.prototype.getX = function getX() {
return this.x
}
function Child() {
this.y = 100
}
Child.prototype.getY = function getY() {
return this.y
}
let c1 = new Child()
console.log(c1)
es6继承
class Parent {
constructor() {
this.x = 100;
}
getX() {
return this.x
}
}
class Child extends Parent {
constructor() {
super();
this.y = 200;
}
getY() {
return this.y;
}
}
let c1 = new Child;
console.log(c1);
题干
class Parent {
constructor() {
this.x = 100;
}
getX() {
return this.x;
}
}
class Child extends Parent {
constructor() {
super();
this.y = 200;
}
getY() {
return this.y;
}
}
let c1 = new Child();
console.log(c1);
手写flatten
function flatten(arr) {
return arr.reduce((prev, item) => {
return prev.concat(Array.isArray(item) ? flatten(item) : item);
}, []);
}
let arr = [1, 2, 3,[4, [5, 6]]];
console.log(flatten(arr));
手写Object.create
新建一个空的构造函数 F ,然后让 F.prototype 指向 obj,最后返回 F 的实例
const myCreate = function (obj) {
function F() {};
F.prototype = obj;
return new F()
}
手写深拷贝
function _cloneDeep(obj) {
if (obj === null) return null;
if (typeof obj !== "object") return obj;
if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Date) return new Date(obj);
let cloneObj = new obj.constructor();
for (let key in obj) {
if (!obj.hasOwnProperty(key)) break;
cloneObj[key] = _cloneDeep(obj[key]);
}
return cloneObj;
}
let obj = { a: { b: { c: 2 } } };
let newObj = _cloneDeep(obj);
newObj.a.b.c = 33;
console.log(obj, newObj);
手写深比较
function _assignDeep(obj1, obj2) {
// 先把OBJ1中的每一项深度克隆一份赋值给新的对象
let obj = _cloneDeep(obj1)
// 再拿OBJ2替换OBJ中的每一项
for (let key in obj2) {
if (!obj2.hasOwnProperty(key)) break
let v2 = obj2[key],
v1 = obj[key]
// 如果OBJ2遍历的当前项是个对象,并且对应的OBJ这项也是一个对象,此时不能直接替换,需要把两个对象重新合并一下,合并后的最新结果赋值给新对象中的这一项
if (typeof v1 === "object" && typeof v2 === "object") {
obj[key] = _assignDeep(v1, v2)
continue
}
obj[key] = v2
}
return obj
}
let obj1 = { a: 2, b: { c: 2 } }
let obj2 = { a: 1, b: { c: 1 } }
console.log(_assignDeep(obj2, obj1))
发布订阅
class EventEmitter {
_events = {};
on() {
let [eventName, cb, ...argus] = arguments;
if (!this._events[eventName]) {
this._events[eventName] = [];
}
this._events[eventName].push(cb);
}
emit() {
let [eventName, ...args] = arguments;
this._events[eventName].map((cb) => {
cb(args);
});
}
off() {
let [eventName, cb, ...argus] = arguments;
let index = this._events[eventName].indexOf(cb);
this._events[eventName].splice(index, 1);
}
once() {
let [eventName, cb] = arguments;
let fn = (argus) => {
cb && cb(...argus);
this.off(eventName, fn);
};
this.on(eventName, fn);
}
}
let eventEmitter = new EventEmitter();
实现lazyMan
class LazyMan {
constructor(str) {
console.log(str);
this.task = [];
setTimeout(() => {
this.next();
});
}
next() {
if (this.task.length === 0) return;
let nextTask = this.task.shift();
nextTask();
}
eat(sth) {
let _this = this;
let fn = () => {
console.log(`eat ${sth} ~~~`);
_this.next();
};
this.task.push(fn);
return this;
}
sleep(time) {
let _this = this;
let fn = () => {
setTimeout(() => {
console.log(`timeout ${time} s`);
_this.next();
}, time);
};
this.task.push(fn);
return this;
}
}
let lazyMan = (str) => {
return new LazyMan(str);
};
lazyMan("lazyMan ~~").sleep(1000).eat("breakfirst").sleep(1000).eat("lunch");
手写promise
(function () {
function Promise(executor) {
if (typeof executor !== "function") {
throw new TypeError("Promise resolver " + executor + " is not a function");
}
var self = this;
self.PromiseState = "pending";
self.PromiseResult = undefined;
self.onFulfilledCallbacks = [];
self.onRejectedCallbacks = [];
var run = function run(state, result) {
if (self.PromiseState !== "pending") return;
self.PromiseState = state;
self.PromiseResult = result;
setTimeout(function () {
var arr = state === "fulfilled" ? self.onFulfilledCallbacks : self.onRejectedCallbacks;
for (var i = 0; i < arr.length; i++) {
let itemFunc = arr[i];
if (typeof itemFunc === "function") {
itemFunc(self.PromiseResult);
}
}
});
};
var resolve = function resolve(value) {
run("fulfilled", value);
};
var reject = function reject(reason) {
run("rejected", reason);
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
Promise.prototype = {
customize: true,
constructor: Promise,
then: function (onfulfilled, onrejected) {
var self = this;
switch (self.PromiseState) {
case "fulfilled":
setTimeout(function () {
onfulfilled(self.PromiseResult);
});
break;
case "rejected":
setTimeout(function () {
onrejected(self.PromiseResult);
});
break;
default:
self.onFulfilledCallbacks.push(onfulfilled);
self.onRejectedCallbacks.push(onrejected);
}
},
catch: function () {},
};
window.Promise = Promise;
})();
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("OK");
console.log(2);
}, 1000);
});
p1.then(
(value) => {
console.log("成功", value);
},
(reason) => {
console.log("失败", reason);
}
);
p1.then(
(value) => {
console.log("成功", value);
},
(reason) => {
console.log("失败", reason);
}
);
p1.then(
(value) => {
console.log("成功", value);
},
(reason) => {
console.log("失败", reason);
}
);
console.log(1);
手写Promise.all
function all(args) {
return new Promise((resolve, reject) => {
let len = args.length;
let num = 0;
let res = [];
function setRes(val, idx) {
res[idx] = val;
if (num === len) {
resolve(res)
}
}
args.map((el, idx) => {
if (el && typeof el.then === 'function' && el instanceof Promise) {
el.then(result => {
console.log(result)
num++;
setRes(result, idx)
})
} else {
num++;
setRes(el, idx)
}
})
})
}
function promiseAll(promises) {
if (!Array.isArray(promises)) {
throw new Error("must be an array");
}
return new Promise((resolve, reject) => {
let len = promises.length;
let count = 0;
let result = new Array(len);
promises.forEach((item, index) => {
Promise.resolve(item).then(
(value) => {
result[index] = value;
count++;
if (count === len) {
resolve(result);
}
},
(err) => {
rejext(err);
}
);
});
});
}
let fn = new Promise((resolve) => {
setTimeout(() => {
resolve(1);
}, 3000);
});
promiseAll([fn, 2, 3]).then((res) => {
console.log(res);
});
手写Promise.race
function promiseRace(promises) {
if (!Array.isArray(promises)) {
throw new Error("must be an array");
}
return new Promise((resolve, reject) => {
promises.forEach((p) => {
Promise.resolve(p).then(
(data) => {
resolve(data);
},
(err) => {
reject(err);
}
);
});
});
}
let fn = new Promise((resolve, reject) => {
setTimeout(() => {
reject(222);
}, 1000);
});
promiseRace([fn, 2, 3])
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
const now = ()=>{
const [count,setCount] = useState(new Date())
useEffect(()=>{
timer = setTimeout(()=>{
setCount(new Date())
},1000)
return ()=>{
clearTimer(timer)
}
},[count])
}