likes
comments
collection
share

前端基础之手写代码篇

作者站长头像
站长
· 阅读数 7

01.常用方法

// 01. Math相关方法
Math.floor(x) // 向下取整
Math.abs(x) // 取绝对值
Math.max(x,y) // 取较大值
Math.min(x,y) // 取较小值
Math.round(x) // 四舍五入

// 02. Array相关方法
push() // 向数组的末尾添加一个或更多元素,并返回新的长度。
unshift() // 向数组的开头添加一个或更多元素,并返回新的长度。
reverse() // 颠倒数组中元素的顺序。
pop() // 删除并返回数组的最后一个元素
shift()	// 删除并返回数组的第一个元素
slice(start,end) // 从已有的数组中返回选定的元素
splice(index,howmany,item1,.....,itemX) // 删除元素,并向数组添加新元素。

// 03. string相关方法
charAt() // 返回在指定位置的字符。
indexOf() // 检索字符串。
substring(start,end)	// 提取字符串中两个指定的索引号之间的字符。

02.实现new操作符

// 1、Con: 接收一个构造函数
// 2、args:传入构造函数的参数
function create(Con, ...args){
    let obj = {};
    obj._proto_ = Con.prototype;
    let result = Con.apply(obj,args)
    return result instanceof Object ?  result : obj;
}
// 构造函数
function Test(name, age) {
    this.name = name
    this.age = age
}
Test.prototype.sayName = function () {
    console.log(this.name)
}
// 实现一个 new 操作符
const a = create(Test,'小鹿','23')
console.log(a.age)

03.实现一个深拷贝

乞丐版

JSON.parse(JSON.stringify());

基础版

function clone(target) {
    let cloneTarget = {};
    for (const key in target) {
        cloneTarget[key] = target[key];
    }
    return cloneTarget;
};

考虑数组

function clone(target) {
    if (typeof target === 'object') {
        let cloneTarget = Array.isArray(target) ? [] : {};
        for (const key in target) {
            cloneTarget[key] = clone(target[key]);
        }
        return cloneTarget;
    } else {
        return target;
    }
};

考虑循环引用

// function clone(target, map = new WeakMap()) {
function clone(target, map = new Map()) {
    if (typeof target === 'object') {
        let cloneTarget = Array.isArray(target) ? [] : {};
        if (map.get(target)) {
            return map.get(target);
        }
        map.set(target, cloneTarget);
        for (const key in target) {
            cloneTarget[key] = clone(target[key], map);
        }
        return cloneTarget;
    } else {
        return target;
    }
};

04.继承实现

组合继承(构造函数+原型链)

function SuperType(name){ 
 this.name = name; 
 this.colors = ["red", "blue", "green"]; 
} 
SuperType.prototype.sayName = function(){ 
 alert(this.name);
}; 
function SubType(name, age){ 
 //继承属性
 SuperType.call(this, name); 
 this.age = age; 
} 
//继承方法
SubType.prototype = new SuperType(); 
SubType.prototype.constructor = SubType; 
SubType.prototype.sayAge = function(){ 
 alert(this.age); 
}; 
var instance1 = new SubType("Nicholas", 29); 
instance1.colors.push("black"); 
alert(instance1.colors); //"red,blue,green,black" 
instance1.sayName(); //"Nicholas"; 
instance1.sayAge(); //29 
var instance2 = new SubType("Greg", 27); 
alert(instance2.colors); //"red,blue,green" 
instance2.sayName(); //"Greg"; 
instance2.sayAge(); //27

05. 防抖与节流

// 防抖-定时器版
function debounce(fn,delay=500){
    let timer
    return function(){
        timer && clearTimeout(timer) 
        timer = setTimeout(() => {
            fn.apply(this, arguments)
        },delay)
    }
}
// 节流-定时器版
throttle (fn, delay = 500) {
  let timer = null
  return function () {
    if (!timer) {
      timer = setTimeout(() => {
        fn.apply(this, arguments)
        clearTimeout(timer)
        timer = null
      }, delay)
    }
  }
}
// 节流-时间戳版
function throttle(func, delay=500){
  let prev = Date.now();
  return function(){
    let context = this;
    let args = arguments;
    let now = Date.now();
    if(now - prev >= delay){
      func.apply(context, args);
      prev = Date.now();
    }
  }
}

06. call、apply、bind实现

Function.prototype.myCall = function(context) {
  var context = Object(context) || window;
  context.fn = this;
  const args = [...arguments].slice(1);
  //const args = Array.prototype.slice.call(arguments, 1);
  //const args = Array.from(arguments).slice(1);
  let result = context.fn(...args);
  delete context.fn;
  return result;
}

Function.prototype.myApply = function(context, args) {
    var context = Object(context) || window
    context.fn = this
    let result = args ? context.fn(...args) : context.fn()
    delete context.fn
    return result
}

Function.prototype.myBind = function(context) {
    const self = this;
    const args1 = [...arguments].slice(1);
    const bindFn = function() {
        const args2 = [...arguments];
        return self.apply(this instanceof bindFn ? this : context, args1.concat(args2));
    }
    function proFn() {} 
    proFn.prototype = self.prototype; 
    return bindFn
}

07. 函数柯理化实现

function add(...args) {
    let res = 0
    args.forEach(num => {
        res += num
    })
    return res
}
function curry (fn, ...arg) {
    let all = arg || []
    return function sum(...arg) {
        if (arg.length == 0) {
            return fn.apply(null,all)
        } else {
            all.push(...arg)
            return sum
        }
    }
}
console.log(curry(add, 1, 5)(2,3)())

08. EventBus实现

class EventBus{
    constructor(){
      this.event = Object.create(null);
    };
    //注册事件
    on(name,fn){
      if(!this.event[name]){
        //一个事件可能有多个监听者
        this.event[name]=[];
      };
      this.event[name].push(fn);
    };
    //触发事件
    emit(name,...args){
      //给回调函数传参
      this.event[name]&&this.event[name].forEach(fn => {
        fn(...args)
      });
    };
    //只被触发一次的事件
    once(name,fn){
      //在这里同时完成了对该事件的注册、对该事件的触发,并在最后并取消该事件。
      const cb=(...args)=>{
        //触发
        fn.apply(this,args);
        //取消
        this.off(name,fn);
      };
      //监听
      this.on(name,cb);
    };
    //取消事件
    off(name,offcb){
      if(this.event[name]){
        let index=this.event[name].findIndex((fn)=>{
          return offcb===fn;
        })
        this.event[name].splice(index,1);
        if(!this.event[name].length){
          delete this.event[name];
        }
      }
    }
  }

08. promise.all实现

function isPromise(obj) {
    return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';  
}

const myPromiseAll = (arr)=>{
    let result = new Array(arr.length)
    return new Promise((resolve,reject)=>{
        for(let i = 0;i < arr.length;i++){
            if(isPromise(arr[i])){
                arr[i].then((data)=>{
                    result[i] = data;
                    let tag = true
                    for (let val of result) {
                        if (val === undefined) {
                            tag = false
                            break
                        }
                    }
                    if(tag){
                        resolve(result)
                    }
                },reject)
            }else{
                result[i] = arr[i];
            }
        }    
    })
}
// 测试
let p1 = Promise.resolve(3);
let p2 = 1337;
let p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
}); 
myPromiseAll([p1, p2, p3]).then(values => { 
  console.log(values); // [3, 1337, "foo"] 
});