手写代码系列
1.手写深拷贝
function deepClone(obj){
if(typeof obj !='object || obj==null){
//如果object是null,或者不是对象和数组,直接返回
return obj
};
let result;
if(obj instanceof Array){
result=[]
}else {
result={}
};
for(let key in object){
//保证key不是原型的属性
if(obj.hasOwnProperty(key)){
result[key]=deepClone(obj[key])
}
};
return result;
}
2.手写promise(简易版)
/*
* pending:初始化成功
* fulfilled:成功
* rejected:失败
* */
function Promise(executor) {// 执行器
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
this.fulfilledCallback = [];
this.rejectCallback = [];
let resolve = (value)=>{
if(this.status=='pending'){
this.status = 'resolve';
this.value = value;
this.fulfilledCallback.forEach(fn=>fn())
}
};
let reject = (reason)=>{
if(this.status =='pending'){
this.status = 'reject';
this.reason = reason;
this.rejectCallback.forEach(fn=>fn())
}
};
try{
executor(resolve,reject)
}catch(e){
reject(e)
}
}
Promise.prototype.then = function (onfulfilled,onrejected) {
if(this.status == 'resolve'){
onfulfilled(this.value)
}
if(this.status == 'reject'){
onrejected(this.reason)
}
if(this.status == 'pending'){
this.fulfilledCallback.push(()=>{
onfulfilled(this.value)
});
this.rejectCallback.push(()=>{
onrejected(this.reason)
})
}
};
var a = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(10)
})
});
a.then((res)=>{
console.log(res);
});
3.手写promise(复杂版)
class _Promise {
constructor(executor){
// 校验executor
if(typeof executor !== "function"){
throw new Error(`Promise resolver ${executor} is not a function!`);
};
this.value = undefined; //终值=>resolve的值
this.reason = undefined;//拒因=>reject的值
this.state = "pending";//状态
this.onFulfilledCallbacks = [];// 成功回调
this.onRejectedCallbacks = [];// 失败回调
const resolve = (value)=>{
// 成功后的一系列操作(状态的改变,成功回调的执行)
if(this.state === "pending"){
this.state = "fulfilled";
this.value = value;
this.onFulfilledCallbacks.forEach(fn=>fn(this.value));
};
};
const reject = (reason)=>{
// 失败后的一系列操作(状态的改变,成功回调的执行)
if(this.state === "pending"){
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn(this.reason));
}
};
try{
executor(resolve,reject);
}catch(err){
reject(err);
}
}
then(onFulfilled,onRejected){
// onFulfilled未传值或传的值不是function的时候
// 自动把onFulfilled变成一个函数
if(typeof onFulfilled !== "function"){
onFulfilled = value => value;
};
//onRejected未传值或传的值不是function的时候
//自动把onFulfilled变成一个函数,并抛出错误
if(typeof onRejected !== "function"){
onRejected = reason => { throw reason }
};
const promise2 = new _Promise((resolve,reject)=>{
if(this.state === "pending"){
this.onFulfilledCallbacks.push(
(value)=>{
setTimeout(()=>{
const x = onFulfilled(value);
resolve(x);
})
}
);
this.onRejectedCallbacks.push(
(reason)=>{
setTimeout(()=>{
const x = onRejected(reason);
reject(x);
})
}
);
};
if(this.state === "fulfilled"){
setTimeout(()=>{
const x = onFulfilled(this.value);
resolve(x);
});
};
if(this.state === "rejected"){
setTimeout(()=>{
const x = onRejected(this.reason);
reject(x);
});
};
});
return promise2;
}
};
new _Promise((resolve,reject)=>{
resolve(3);
})
.then(
value => console.log("value",value)
)
.then(value => console.log("value",value))
4.手写call,apply,bind函数
1) call
Function.prototype.myCall = function(context, ...args) { // 解构context 与arguments
if(typeof this !== 'function') { // this 必须是函数
throw new TypeError(`It's must be a function`)
}
if(!context) context = window; // 没有context,或者传递的是 null undefined,则重置为window
const fn = Symbol(); // 指定唯一属性,防止 delete 删除错误
context[fn] = this; // 将 this 添加到 context的属性上
const result = context[fn](...args); // 直接调用context 的 fn
delete context[fn]; // 删除掉context新增的symbol属性
return result; // 返回返回值
}
2)apply
Function.prototype.myApply = function(context, args = []) { // 解构方式
if(typeof this !== 'function') {
throw new TypeError(`It's must be a function`)
}
if(!context) context = window;
const fn = Symbol();
context[fn] = this;
const result = context[fn](...args);
delete context[fn];
return result;
}
3)bind
Function.prototype.myBind = function (context, ...args) {
const fn = this;
if(typeof fn !== 'function'){
throw new TypeError('It must be a function');
}
if(!context) context = window;
return function (...otherArgs) {
return fn.apply(context, [...args, ...otherArgs]);
};
};
5.手写New操作符
//它创建了一个全新的对象。
//它会被执行[[Prototype]](也就是__proto__)链接。
//它使this指向新创建的对象。。
//通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上。
//如果函数没有返回对象类型Object(包含Functoin, Array, Date, RegExg, Error),那么new表达式中的函数调用将返回该对象引用。
function New(func) {
var res = {};
if (func.prototype !== null) {
res.__proto__ = func.prototype;
}
var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
return ret;
}
return res;
}
6.手写防抖
function debounce(func, ms = 1000) {
let timer;
return function (...args) {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
func.apply(this, args)
}, ms)
}
}
// 测试
const task = () => { console.log('run task') }
const debounceTask = debounce(task, 1000)
window.addEventListener('scroll', debounceTask)
7.手写节流
function throttle(fn, wait) {
let prev = new Date();
return function() {
const args = arguments;
const now = new Date();
if (now - prev > wait) {
fn.apply(this, args);
prev = new Date();
}
}
8.手写柯里化
在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
function curry(fn, args) {
var length = fn.length;
var args = args || [];
return function(){
newArgs = args.concat(Array.prototype.slice.call(arguments));
if (newArgs.length < length) {
return curry.call(this,fn,newArgs);
}else{
return fn.apply(this,newArgs);
}
}
}
function multiFn(a, b, c) {
return a * b * c;
}
var multi = curry(multiFn);
multi(2)(3)(4);
multi(2,3,4);
multi(2)(3,4);
multi(2,3)(4);
//es6方式
const curry = (fn, arr = []) => (...args) => (
arg => arg.length === fn.length
? fn(...arg)
: curry(fn, arg)
)([...arr, ...args])
let curryTest=curry((a,b,c,d)=>a+b+c+d)
curryTest(1,2,3)(4) //返回10
curryTest(1,2)(4)(3) //返回10
curryTest(1,2)(3,4) //返回10
9.手写事件监听
function bindEvent(elem,type,selector,fn){
if(fn==null){
fn=selector;
selector=null;
}
elem.addEventListener(type,event=>{
const {target}=event;
if(selector){
if(target.matches(selector)){
fn.call(target,event)
}
}else{
fn.call(target,event)
}
})
}
10.手写深度比较isEqual()
const obj1 = {a:100,b:{x:10,y:20}}
const obj2 = {a:100,b:{x:10,y:20}}
isEqual(obj1,obj2) === true
//实现
//判断是否是对象或数组
function isObject(obj) {
return typeof obj === 'object' && obj !== null
}
function isEqual(obj1,obj2) {
// 两个数据有任何一个不是对象或数组
if (!isObject(obj1) || !isObject(obj2)) {
// 值类型(注意:参与equal的一般不会是函数)
return obj1 === obj2
}
// 如果传的两个参数都是同一个对象或数组
if (obj1 === obj2) {
return true
}
// 两个都是对象或数组,而且不相等
// 1.先比较obj1和obj2的key的个数,是否一样
const obj1Keys = Object.keys(obj1)
const obj2Keys = Object.keys(obj2)
if (obj1Keys.length !== obj2Keys.length) {
return false
}
// 如果key的个数相等,就是第二步
// 2.以obj1为基准,和obj2依次递归比较
for (let key in obj1) {
// 比较当前key的value --- 递归
const res = isEqual(obj1[key], obj2[key])
if (!res) {
return false
}
}
// 3.全相等
return true
}
const arr1 = [1, 2, 3]
const arr2 = [1,2,3,4]
console.log(isEqual(arr1,arr2)) // false