JS 常见知识点总结

119 阅读3分钟

this 的绑定

  1. 显示绑定 call,apply,bind
  • call,apply 实现:使函数成为新传入 this(context) 的属性并通过 context.fn() 调用,再将 context.fn 删除
Function.prototype.myCall = function (context, ...args) {
  let context = context || window;
  context.fn = this;
  let result = context.fn(...args);
  delete context.fn;
  return result;
};

Function.prototype.myApply = function (ctx, arr) {
  let ctx = ctx || window;
  ctx.fn = this;
  let res = ctx.fn(...arr);
  delete ctx.fn;
  return res;
};
  • bind 实现: 返回一个强制绑定 this 的新函数,且该函数继承原函数的属性
Function.prototype.myBind = function (ctx, ...args1) {
  let self = this;
  function fn(...args2) {
    return self.call(this instanceof fn ? this : ctx, ...args1, ...args2);
  }
  fn.prototype = Object.create(self.prototype);
  return fn;
};
  1. new 绑定
  • 通过 new 调用的构造函数 this 指向返回的新对象
  • new 过程:
    • 通过 Object.create() 创建一个新的对象,该对象继承构造函数的属性
    • 显示绑定构造函数的 this 到该对象
    • 如果构造函数返回对象则返回构造函数返回的对象,否则返回新建的对象
function myNew(...args) {
  const constructor = args.shift();
  const obj = Object.create(constructor.prototype);
  const res = constructor.apply(obj, args);
  return typeof res === 'object' ? res : obj;
}

  1. 各种绑定的优先级 new 绑定 > 显示绑定 > 隐式绑定

深克隆 & 浅克隆

  • 浅克隆: 只能拷贝第一层值类型,无法拷贝引用类型
function shallowClone(target) {
  let cloneTarget = {};
  for (const key in target) {
    cloneTarget[key] = target[key];
  }
  return cloneTarget;
}
  • 深克隆:通过递归拷贝多层对象
function deepClone(target) {
  if (typeof target !== 'object') return target;
  let cloneTarget = target instanceof Array ? [] : {};
  for (const key in target) {
    if (target.hasOwnProperty(key)) {
      cloneTarget[key] = deepClone(target[key]);
    }
  }
  return cloneTarget;
}
  • 深克隆升级版:通过 map 储存克隆过的对象,避免循环引用
function deepClone(target, map = new Map()) {
  let obj = target instanceof Array ? [] : {};
  if (typeof target !== 'object') return target;
  if (map.get(target)) {
    return map.get(target);
  }
  map.set(target, obj);
  for (let key in Object.keys(target)) {
    obj[key] = deepClone(target[key], map);
  }
  return obj;
}

js 继承

最佳原生继承方案:寄生组合式继承

function Person(name) {
  this.name = name;
}
Person.prototype.sayHello = function () {
  console.log(`Hi my name is ${this.name}.`);
};

function Student(name, grade) {
  // 继承 Person 实例属性
  Person.call(this, name);
  this.grade = grade;
}

// 继承 Person 原型方法
Object.prototype.create = function (target) {
  function F() {}
  F.prototype = target.prototype;
  return new F();
};

Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

Student.prototype.sayGrade = function () {
  console.log(`my grade is ${this.grade}.`);
};

ES6 继承:class 继承

  • extends 继承父类原型属性;
  • 调用 super() 可重写 constructor,继承父类实例属性;
  • 调用 super.method() 可重写父类方法
class Person {
  constructor(name) {
    this.name = name;
  }
  sayHello() {
    console.log('hello');
  }
}
class Student extends Person {
  constructor(name, age) {
  // 继承 Person 实例属性
    super(name);
    this.age = age
  }
  sayBye() {
    console.log('bye');
  }
  // 重写 Person 原型方法
  sayHello() {
    super.sayHello();
    this.sayBye();
  }
}

类型判断

js 中变量的值分为原始类型和引用类型

  • 原始类型:number, string, boolean, undefined, null, symbol
  • 引用类型:对象,包括 Array,Function,Date 等 判断类型的方法
  1. typeof: 只能判断原始类型,引用类型全部返回 'object',注意 typeof null 也返回'object'

  2. instanceof:判断对象是否是某类的实例,可用来判断引用类型 Array,Function,null instanceof Object 返回 false

  3. Object.prototype.toString.call():可用来判断所有原始类型和引用类型, null 返回 '[Object null]',undefined 返回 '[Object undefined]'

instanceof 代码实现:递归循环皆可

function myInstanceOf(instance, Class) {
  if (typeof instance !== 'object') return false;
  if (!instance.__proto__) return false;
  if (instance.__proto__ === Class.prototype) return true;
  return myInstanceOf(instance.__proto__, Class);
}

函数柯里化 & compose

  1. 柯里化作用:将函数参数分成多次传入

fn(a,b,c) === curry(fn)(a)(b)(c)

function curry(fn) {
  return function curried(...args1) {
    if (args1.length < fn.length) {
    // 参数不够,继续柯里化
      return function (...args2) {
        return curried.call(this, ...args1, ...args2);
      };
    }
    return fn.call(this, ...args1);
  };
}

应用:redux 中间件, HOC

  1. compose 作用:

compose(fn1, fn2, fn3)(args) === fn1(fn2(fn3(args)))

应用:redux 中间件

节流防抖

  1. 节流: 每隔一段时间内只触发一次事件回调函数
// immediate 可配置立刻触发或稍后触发
function throttle(fn, wait, immediate) {
  let timer;
  return function (...args) {
    let ctx = this;
    if (immediate) {
      if (!timer) {
        fn.call(ctx, ...args);
        timer = setTimeout(() => {
          timer = null;
        }, wait);
      }
    } else {
      if (!timer) {
        timer = setTimeout(() => {
          fn.call(ctx, ...args);
          timer = null;
        }, wait);
      }
    }
  };
}
  1. 防抖: 一段时间多次触发事件内只调用最后一次事件回调函数

应用: input 输入框多次输入只获取最终输入值

// immediate 可配置立刻触发或稍后触发
function debounce(fn, wait, immediate) {
  let timer;
  return function (...args) {
    let ctx = this;
    clearTimeout(timer);
    if (immediate) {
      if (!timer) fn.call(ctx, ...args);
      timer = setTimeout(() => {
        timer = null;
      }, wait);
    } else {
      timer = setTimeout(() => {
        fn.call(ctx, ...args);
      }, wait);
    }
  };
}