近日,看八股文,学源码,一些汇总,记录于此,如有疑问,欢迎指正。
防抖
function debounce(cb, delay, immediate){
let timer;
return function(){
if(!timer&&immediate){
cb.apply(this, arguments)
}
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
cb.apply(this, arguments)
}, delay)
}
}
节流
function throttle(cb, delay, immediate){
let timer, callNow = immediate;
return function(){
if(callNow){
callNow = false;
cb.apply(this, arguments)
}
if(!timer){
timer = setTimeout(() => {
cb.apply(this, arguments);
timer = null;
}, delay)
}
}
}
数组转树形结构
function arrayToTree(arr){
let result = [], map = {};
for(let item of arr){
let pid = item.pid, id =item.id;
if(!map[id]){
map[id] = {
children: []
}
}
map[id] = {
...item,
children: map[id].children
}
let mapItem = map[id];
if(pid === 0){
result.push(mapItem)
}else{
if(!map[pid]){
map[pid] = {
children: []
}
}
map[pid].children.push(mapItem)
}
}
return result
}
数组中默认pid=0的项为树结构的顶层
arr = [
{ pid: 0, id: 1, name: '1' },
{ pid: 1, id: 2, name: '2' },
{ pid: 1, id: 3, name: '3' },
{ pid: 2, id: 4, name: '4' },
{ pid: 3, id: 5, name: '5' },
{ pid: 3, id: 6, name: '6' },
{ pid: 4, id: 7, name: '7' }
]
arrayToTree(arr)
[
{
"pid": 0,
"id": 1,
"name": "1",
"children": [
{
"pid": 1,
"id": 2,
"name": "2",
"children": [
{
"pid": 2,
"id": 4,
"name": "4",
"children": [
{
"pid": 4,
"id": 7,
"name": "7",
"children": []
}
]
}
]
},
{
"pid": 1,
"id": 3,
"name": "3",
"children": [
{
"pid": 3,
"id": 5,
"name": "5",
"children": []
},
{
"pid": 3,
"id": 6,
"name": "6",
"children": []
}
]
}
]
}
]
类型检测
function typeOf(value){
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase()
}
数据拷贝
function deepClone(target, map = new Map()){
if(map.get(target)){
return target
}
let constructor = target.constructor;
if(/^(RegExp|Date)$/.test(constructor.name)){
return new constructor(target)
}
if(target!==null && (typeof target === 'object' || typeof target === 'function')){
map.set(target, true)
if(typeof target === 'function'){
return new Function('return '+target.toString())()
}else{
let result = Array.isArray(target)?[]:{};
for(let key in target){
if(target.hasOwnProperty(key)){
result[key] = deepClone(target[key], map)
}
}
return result
}
}
return target
}
数据拷贝(Symbol)
const isObject = obj => obj !== null && (typeof obj === 'object' || typeof obj === 'function')
const isFunction = obj => typeof obj === 'function'
function deepClone(target, map = new WeakMap()){
if(map.has(target)){
return map.get(target)
}
if(!isObject(obj)) return obj
const constructor = obj.constructor;
if(/^(Date|RegExp)$/.test(constructor.name)){
return new constructor(obj)
}
let result = new constructor();
if(isFunction(obj)){
result = new Function('return '+obj.toString())
}
map.set(obj, result)
[...Object.getOwnPropertyNames(obj), ...Object.getOwnPropertySymbols(obj)].forEach(key => {
result[key] = deepClone(obj[key], map)
})
return result
}
柯里化
function curry(fn){
return function curried(...args){
if(args.length < fn.length){
return function(...args2){
return curried.apply(this, args.concat(args2))
}
}
return fn.apply(this, args)
}
}
// 具体使用方式
function sum(a, b, c){
return a + b + c
}
curry(sum)(1)(2)(3) // 6
sleep
async function sleep(delay){
return new Promise((resolve, reject) => {
setTimeout(resolve, delay)
})
}
(async function(){
console.log(Date.now())
await sleep(1000)
console.log(Date.now())
})()
继承
const inherit = (function(){
let F = function () { }
return function (target, origin) {
F.prototype = origin.prototype;
target.prototype = new F();
target.prototype.constructor = target;
target.prototype.originPrototype = origin.prototype
}
})()
new操作符
function _new(constructor, ...args){
if(typeof constructor !== 'function'){
throw new Error('constructor must be a funciton')
}
let obj, result;
obj = Object.create(constructor.prototype);
result = constructor.apply(obj, args);
if(result!==null && (typeof result === 'object' || typeof result === 'function')){
return result;
}
return obj
}
Object.assign
- 浅拷贝
- 同名属性替换,数组视为对象存在索引覆盖
- 取值函数,不会复制取值函数,只会使用最终属性值
- 不能拷贝不可枚举属性,只拷贝自身属性
- 可以拷贝symbol
- target始终是一个对象,如果是基本类型,会被转成对应的基本包装类型,null和undefined无法转成对象,会报错
- source参数如果是数字和布尔值,不会产生效果,字符串内部有iterator接口
- target如果是字符串,转成基本包装类型时属性时只读的(writable属性为false)。此会导致
Object.assign('a', 'bc')报错,TypeError: Cannot assign to read only property '0' of object '[object String]'
let str = Object('abc')
Object.getOwnPropertyDescriptors(a)
// ===>
{
"0": {
"value": "a",
"writable": false,
"enumerable": true,
"configurable": false
},
"1": {
"value": "b",
"writable": false,
"enumerable": true,
"configurable": false
},
"2": {
"value": "c",
"writable": false,
"enumerable": true,
"configurable": false
},
"length": {
"value": 3,
"writable": false,
"enumerable": false,
"configurable": false
}
}
function assign(target, ...source){
if(target == null){
throw new TypeError('Cannot convert undefined or null to object')
}
return source.reduce((prev, next) => {
if(!(prev !==null &&(typeof prev === 'object' || typeof next === 'function'))){
prev = new Object(prev)
}
if(next == null) return prev;
[...Object.keys(next), ...Object.getOwnPropertySymbols(next)].forEach(key => {
prev[key] = next[key]
})
return prev
}, target)
}
instanceof
function instanceOf(left, right){
let proto = Object.getPrototypeOf(left);
while(true){
if(proto == null) return false;
if(proro === right.prototype) return true;
proto = Object.getPrototypeOf(proto)
}
}
首篇文章,以上。