this 的绑定
- 显示绑定 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;
};
- 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;
}
- 各种绑定的优先级 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 等 判断类型的方法
-
typeof: 只能判断原始类型,引用类型全部返回 'object',注意 typeof null 也返回'object'
-
instanceof:判断对象是否是某类的实例,可用来判断引用类型 Array,Function,null instanceof Object 返回 false
-
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
- 柯里化作用:将函数参数分成多次传入
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
- compose 作用:
compose(fn1, fn2, fn3)(args) === fn1(fn2(fn3(args)))
应用:redux 中间件
节流防抖
- 节流: 每隔一段时间内只触发一次事件回调函数
// 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);
}
}
};
}
- 防抖: 一段时间多次触发事件内只调用最后一次事件回调函数
应用: 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);
}
};
}