手写实现一个new
- 创建一个空的简单JavaScript对象(即{});
- 为步骤1新创建的对象添加属性
__proto__
,将该属性链接至构造函数的原型对象 ; - 将步骤1新创建的对象作为this的上下文 ;
- 如果该函数没有返回对象,则返回this。
new关键词执行后总会返回一个对象, 要么是实例对象, 要么是return语句指定的对象.
1 | function _new(fn,...args){ |
Object.create
1 | function create (o) { |
instanceof
- Instanceof: 用于检测构造函数的
prototype
属性是否出现在某个实例对象的原型链上。 - 通俗一点就是: 判断new出的实例对象是否是当前构造函数生成的对象
1 | function my_instanceof(left, right) { |
🔥手写Promise.all
- 参数可迭代
- 返回值是promise
- 如果全部成功,状态变为resolve
- 但凡有一个失败,状态变为reject
1 | function PromiseAll(arr) { |
手写call, apply, bind
- https://juejin.cn/post/6844904042452221960#heading-9 可参考
- https://juejin.cn/post/6844903809206976520#heading-10 可参考
- 共同点:都是改变this指向
- 区别
- call 和 apply是立即执行的,而bind是返回一个新的函数,需要手动去调用
- call可以传递多个参数,第一个参数和apply’一样,是用来替换的对象,后边是参数列表
- apply最多智能有两个参数 (新this对象,数组argsArray)-> fun.apply(thisArg, [argsArray])
call
- 改变this指向
- 函数立即执行,返回执行结果
- https://juejin.cn/post/6844903906279964686#heading-19 可参考
1 | Function.prototype._call = function(context, ...args) { |
apply
1 | // func.apply(thisArg, [argsArray]) |
bind
- 改变this指向
- 返回一个新函数
- 新函数可能被当做构造函数调用,函数可能有返回值
- 当 bind 返回的函数作为构造函数的时候,bind 时指定的 this 值会失效
- 传递参数并柯里化
- https://www.jianshu.com/p/b540e1e17f54 参考
- https://github.com/mqyqingfeng/Blog/issues/12 冴羽
1 | // // ES2015 arguments是一个对象,类数组; |
bind2
1 | // https://jsgodroad.com/interview/js/#%E6%89%8B%E5%86%99%E9%A2%98 |
🔥bind3 new 2021-12-13
1 | Function.prototype.myBind = function(objThis, ...args) { |
bind-polyfill-core-js
1 | // Yes, it does work with `new (funcA.bind(thisArg, args))` |
防抖和节流
防抖 debounce
- 事件响应函数在一段时间后才执行,如果这段时间内再次调用,则重新计算。 在一定的时间间隔内,将多次触发变成一次触发
应用场景
- 限制鼠标连续点击(按钮提交等)
- Scroll事件滚动防抖
- 搜索框输入查询
- 浏览器窗口缩放,resize事件
1 | // https://www.30secondsofcode.org/js/s/debounce 目前看见最简写法,best! |
节流 throttle
- 持续的触发事件,每隔一段时间, 只执行一次 ,减少一段时间的触发频率
时间戳版本
1 | const throttle = (fn, wait) => { |
定时器版本
1 | const throttle = (fn, wait) => { |
deepClone深拷贝 !!!
浅拷贝
- Object.assign()
...
扩展运算符let cloneObj = {...obj}
let newArr = [...arr]
- 数组的Slice(), concat()
1 | const shallowClone = obj => Object.assign({}, obj); |
深拷贝
乞丐版
1 | let newObj = JSON.parse( JSON.stringify( obj ) ) |
- 拷贝对象的值中如果有
函数
、undefined
、Symbol
,JSON.stringify序列化后的字符串中,这个键值对丢失 - 拷贝Date引用类型会变成字符串
- 拷贝RegExp会变成空对象
{}
- 对象中含有
NaN
、Infinity
会变成null
- 无法拷贝对象的原型链
- 无法拷贝不可枚举的属性 如Symbol
- 无法拷贝对象的循环引用 , 即对象成环
obj[key] = obj
🔥优化版
考虑 Date、RegExp类型, 直接生成一个新的实例返回
考虑数组
let target = Array.isArray(obj)? [] : {}
考虑循环引用 利用WeakMap作为hash表, 检测到对象已存在于哈希表中,取出该值返回即可
针对不可枚举属性以及 Symbol 类型,使用 Reflect.ownKeys()
函数部分太复杂,函数的原型,多层柯里化等
针对Map, Set, Error等,Object.getOwnPropertyDescriptors(obj) 也不考虑
递归爆栈问题,改用循环解决,广度优先
-
1
RangeError: Maximum call stack size exceeded
1 | // 检测对象 |
实现 (5).add(3).minus(2) 功能
1 | Number.prototype.add = function(n) { |
如何求数组最大值和最小值
- 循环后Math.max
- reduce
- sort排序后取最后
- ES6 … + Math.max
1 | // 1. Math.max |
数组去重
- 双重for循环
- new Set
- indexOf
- array.filter + indexOf
- sort排序 + 相邻元素对比
- Object 键值对 obj.hasOwnProperty
1 | // 0. 双重for循环 |
数组扁平化 flatten
1 | var arr = [1, [2, [3, 4]]]; |
🔥循环递归
1 | // 方法 1 |
toString
如果数组元素都是Number, 可以使用;但不推荐这种 toString+split方式
1 | [1, [2, [3, 4]]].toString() // "1,2,3,4" |
1 | // 方法2 |
🔥用reduce实现flat
1 | // 方法3 |
ES6 …
==[].concat(…arr)==
1 | var arr = [1, [2, [3, 4]]]; |
🔥柯里化 curry
柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术
1 | const curry = (fn, ...args) =>{ |
函数组合 compose
1 | // redux中的实现 不一定准确 ,待整理 |
EventEmitter
https://juejin.cn/post/7031322059414175774#heading-16
千位分隔符
https://juejin.cn/post/6844903911686406158#heading-19