防抖
function debounce(func, wait) {
let timeout;
return function () {
const context = this;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.call(context, arguments)
}, wait);
}
}
节流
function throttle(func, wait) {
var previous = 0;
return function() {
let now = Date.now();
let context = this;
if (now - previous > wait) {
func.call(context, arguments);
previous = now;
}
}
手写一个Promise
三种状态pending| fulfilled(resolved) | rejected
当处于pending状态的时候,可以转移到fulfilled(resolved)或者rejected状态
当处于fulfilled(resolved)状态或者rejected状态的时候,就不可变。
promise特征:
1 立即执行性。创建promise时,作为参数传入的函数被立刻执行。
2 3种状态。
3 状态不可改。
4 链式调用。
必须有一个then异步执行方法,then接受两个参数且必须返回一个promise:
// onFulfilled 用来接收promise成功的值
// onRejected 用来接收promise失败的原因
promise1=promise.then(onFulfilled, onRejected);
用法:
var promise = new Promise((resolve,reject) => {
if (操作成功) {
resolve(value)
} else {
reject(error)
}
})
promise.then(function (value) {
// success
},function (value) {
// failure
})
function myPromise(constructor){
let self=this;
self.status="pending" //定义状态改变前的初始状态
self.value=undefined;//定义状态为resolved的时候的状态
self.reason=undefined;//定义状态为rejected的时候的状态
function resolve(value){
//两个==="pending",保证了状态的改变是不可逆的
if(self.status==="pending"){
self.value=value;
self.status="resolved";
}
}
function reject(reason){
//两个==="pending",保证了状态的改变是不可逆的
if(self.status==="pending"){
self.reason=reason;
self.status="rejected";
}
}
//捕获构造异常
try{
constructor(resolve,reject);
}catch(e){
reject(e);
}
}
myPromise.prototype.then = function(onFullfilled,onRejected) {
let self = this
switch(self.status){
case 'resolved':
onFullfilled(self.value)
break
case 'rejected':
onRejected(self.reason)
break
default:
break
}
}
var p = new Promise(function(resolve,reject) {resolve(1)})
p.then(function(x){console.log(x)})
实现一个链式调用
new Promise((resolve,reject)=>{
console.log('1')
resolve('2')
}).then(res=>{
console.log(res)
return new Promise((resolve,reject)=>{
reject(new Error('4'))
})
}).then(res=>{
console.log(res)
}).catch(e=>console.log(e))
promiseAll
function PromiseAll(proArray) {
return new Promise((resolve,reject)=>{/////返回一个promise
if(!Array.isArray(proArray)) {
return reject(new Error('输入数组'))//new error
}
var len = proArray.length
let count = 0
var arr=[]
for(let i=0;i<len;i++) {////let
Promise.resolve(proArray[i]).then((res)=>{
arr[i] = res
count++
if (count == len) {
resolve(arr)
}
}).catch(e => reject(e))
}
})
}
const pro1 = new Promise((res,rej) => {
setTimeout(()=>{
res('1')
},1000)
})
const pro2 = new Promise((res,rej) => {
setTimeout(()=>{
res('2')
},2000)
})
const pro3 = new Promise((res,rej) => {
setTimeout(()=>{
res('3')
},3000)
})
const proAll = PromiseAll([pro1,pro2,pro3])
.then(res =>
console.log(res)
)
.catch((e) =>{
console.log(e)
})
js实现一个深拷贝
var obj = {
a:1,
b: [2,3,4],
c: true,
d: function() {
console.log('5')
},
e: new RegExp('\\w+')
}
var obj1 = JSON.parse(JSON.stringify(obj))
console.log('obj1',obj1)
如果obj里面有时间对象,正则,函数,都不能正确拷贝
function deepCopy(obj){
//判断是否是简单数据类型,
if(typeof obj == "object"){
//复杂数据类型
var result = obj.constructor == Array ? [] : {};
for(let i in obj){
result[i] = typeof obj[i] == "object" ? deepCopy(obj[i]) : obj[i];
}
}else {
//简单数据类型 直接 == 赋值
var result = obj;
}
return result;
}
instanceOf
检测对象A是不是另一个对象B的实例的原理是:查看对象B的prototype属性指向的原型对象是否在对象A的原型链上,若在则返回true,若不在则返回false。
function instanceOf(left,right) {
let proto = left.__proto__;
let prototype = right.prototype
while(true) {
if(proto === null) return false
if(proto === prototype) return true
proto = proto.__proto__;
}
}
let arr = []
let obj = {}
arr instanceof Array // true
arr instanceof Object // true
obj instanceof Object // true
obj instanceof Array // false
arr 数组相当于 new Array() 出的一个实例,所以 arr.proto === Array.prototype,又因为 Array属于 Object 子类型,即 Array.prototype.proto === Object.prototype.
因此 Object 构造函数在 arr 的原型链上。
所以 instanceof 仍无法判断一个值到底属于数组还是普通对象。
Object.prototype.toString()
Object.prototype.toString.call({})
// '[object Object]'
Object.prototype.toString.call([])
// '[object Array]'
Object.prototype.toString.call(() => {})
// '[object Function]'
Object.prototype.toString.call('wangergou')
// '[object String]'
Object.prototype.toString.call(null)
// '[object Null]'
Object.prototype.toString.call(undefined)
// '[object Undefined]'
call,apply,bind
Function.prototype.call = function (context, ...args) {
context = context || window;
context.fn = this;
let result = eval('context.fn(...args)');
delete context.fn
return result;
}
Function.prototype.apply = function (context, args) {
context = context || window;
context.fn = this;
let result = eval('context.fn(...args)');
delete context.fn
return result;
}
Function.prototype.ownBind = function(context) {
context = context || window;
return (...args)=>{
this.call(context, ...args)
}
}
实现Object.create方法
let demo = {
c : '123'
};
let cc = Object.create(demo);
console.log(cc);
function create(proto) {
function Fn() {};
// 将Fn的原型指向传入的 proto
Fn.prototype = proto;
Fn.prototype.constructor = Fn;
return new Fn();
};
函数实现柯里化
function sum(a, b, c, d, e) {
return a+b+c+d+e;
};
let a = curring(sum)(1,2)(3,4)(5);
console.log(a); // 15
const curring = (fn, arr = []) => {
let len = fn.length;
return function (...args) {
arr = [...arr, ...args];
if (arr.length < len) {
return curring(fn, arr);
} else {
return fn(...arr);
}
};
};
拍平
Array.prototype.flat() 特性总结
Array.prototype.flat() 用于将嵌套的数组“拉平”,变成一维的数组。
该方法返回一个新数组,对原数据没有影响。
不传参数时,默认“拉平”一层,可以传入一个整数,表示想要“拉平”的层数。
传入 <=0 的整数将返回原数组,不“拉平”
Infinity 关键字作为参数时,无论多少层嵌套,都会转为一维数组
如果原数组有空位,Array.prototype.flat() 会跳过空位。
用 reduce 实现 flat 函数
const arr = [1, 2, 3, 4, [1, 2, 3, [1, 2, 3, [1, 2, 3]]], 5, "string", { name: "弹铁蛋同学" }]
// 首先使用 reduce 展开一层
arr.reduce((pre, cur) => pre.concat(cur), []);
// [1, 2, 3, 4, 1, 2, 3, [1, 2, 3, [1, 2, 3]], 5, "string", { name: "弹铁蛋同学" }];
// 用 reduce 展开一层 + 递归
const flat = arr => {
return arr.reduce((pre, cur) => {
return pre.concat(Array.isArray(cur) ? flat(cur) : cur);
}, []);
};
// [1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 3, 5, "string", { name: "弹铁蛋同学" }];
通过传入整数参数控制“拉平”层数
// reduce + 递归
function flat(arr, num = 1) {
return num > 0
? arr.reduce(
(pre, cur) =>
pre.concat(Array.isArray(cur) ? flat(cur, num - 1) : cur),
[]
)
: arr.slice();
}
const arr = [1, 2, 3, 4, [1, 2, 3, [1, 2, 3, [1, 2, 3]]], 5, "string", { name: "弹铁蛋同学" }]
flat(arr, Infinity);
// [1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 3, 5, "string", { name: "弹铁蛋同学" }];
手写一个reduce
//实现一个reduce
Array.prototype.reduce = function(fn, init){
var arr = this
var total = init || arr[0]
for(var i=init?0:1; i<arr.length; i++){
total = fn(total,arr[i],i,arr)
}
return total
}
var arr = [1,2,3]
console.log(arr.reduce((prev,item)=>prev+item,10))