常见js封装用法
1、红灯3秒亮一次,绿灯1秒亮一次,黄灯2秒亮一次;如何使用Promise让三个灯不断交替重复亮灯?
function mylight(value,time){ return new Promise((resolve,reject) => { setTimeout((params) => { console.log(value); resolve() },time) }) } let step =()=>{ Promise.resolve() .then(() => { return mylight('red',3000) }) .then((res) => { return mylight('green',1000) }) .then((res) => { return mylight('yellow',1000) }) .then(res=>{ // 递归执行 step() }) } step()
2、async和await把异步改为同步,得到最新的state的值
使用Promise来封装setState(异步编程)
changeCount = (state)=>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ this.setState(state) //resolve包裹成功时的结果 resolve(this.state.count) },100) }) }, pushRouter = async() => { // await this.setState({ // count:this.state.count+1 // }) const result = await this.changeCount({ count:this.state.count + 1 }) }
3、async,await结合try,catch使用捕获异常
async componentDidMount() { const { dispatch } = this.props try { const response = await dispatch({ type: "netValueQuery/queryListData", payload: {} }) if (response.httpStatus !== 200) { throw new Error(response.msg); } const json = await response.json(); this.setState({ data: json }); } catch (error) { console.log(error); } }
4、多个请求,后面的请求里需使用前面请求里返回的值
getSign(result){ return this.$post(`/share/saveRecord`) } getTask() { const actid = this.$route.query.id; return this.$get(`/lottery/powerTask/${actid}`); } async getReady(){ const task = await this.getTask() this.result = task.data.find(item => item.name.includes("分享")) const str = await this.getSign(this.result) }
5、实现多个请求并发执行,可以使用 Promise.all
const p1 = () => setTimeout(() => { console.log(1) }, 100) const p2 = () => setTimeout(() => { console.log(2) }, 0) const p3 = () => { console.log(3) } async function promiseAll() { const [result1, result2, result3] = await Promise.all([p1(), p2(), p3()]) } promiseAll()
5、
function Person() { this.name = "志杰啊"; // 属性 this.age = 20; this.run = function () { //定义的方法 console.log(666) } };
Person.getInfo = function () { // 添加静态的方法 console.log("添加静态方法!") } //web类 继承Person类 原型链+对象冒充的组合继承模式 function Web() { Person.call(this); /* 对象冒充实现继承*/ } var w = new Web(); // 实例化w Web继承Person的属性与方法 w.run(); w.work(); // 报错 // 对象继承可以继承构造函数里面的属性和方法 但是无法继承原型链的上面的属性和方法
6、ES5原型链继承(未考虑父类构造可传参的场景)所谓原型链继承,就是让子类构造函数的 prototype 指向父类的实例对象
function Person() {
this.name = "志杰啊"; // 属性
this.age = 20;
this.run = function () { //定义的方法
console.log(666)
}
};
Person.prototype.sex = "男";
Person.prototype.work = function () {
console.log(this.name + "在认真学习typescript")
}
function Web() {
};
Web.prototype = new Person(); // 原型链的实现的继承
// 实例化
var w = new Web();
w.run();
console.log(w.name)
// 通过原型链继承的方法既能够继承构造函数里面的方法 也能继承原型链里面的方法
w.work(); // 志杰啊在认真学习typescript
7、ES5中组合继承:指的是将原型链和构造函数的技术组合到一起来实现继承。其背后的思路就是使用原型链实现对原型属性和方法的继承,而通过构造函数来实现对实例属性的继承。
function A() { this.a = "a"; } A.prototype.b = function() { console.log("b"); } function B() { A.call(this); } B.prototype = new A(); var b = new B(); // {a: "a"} b.__proto__; // {a: "a"} b.__proto__.__proto__; // {b: f}
8、ES6实现继承
//父类:两个属性,一个普通方法,一个静态方法 class Person{ constructor(name,age){ this.name= name; this.age = age; } sayName(){ console.log("我的名字是: "+this.name); } static sayHello(){ console.log("hello!!!!!!"); } } //子类继承父类 class Chinese extends Person{ constructor(name,age,addr){ super(name,age);//必须现在最前面 this.addr = addr; } sayMyaddr(){ console.log("我是中国人,我住在:"+this.addr); } } //测试 var wlk = new Chinese("wk",20,"中国-重庆"); wlk.sayName(); wlk.sayMyaddr(); Person.sayHello(); Chinese.sayHello();//静态方法也可以被继承
9、手写一个防抖函数
function debounce(callback, time) {return function () { if (timer) { clearTimeout(timer)
timer = null } timer = setTimeout(callback, time) } }
10、requestIdleCallback实现一帧执行多任务举例
let taskQueue = [ () => { console.log('task1 start') console.log('task1 end') }, () => { console.log('task2 start') // sleep(950) console.log('task2 end') }, () => { console.log('task3 start') console.log('task3 end') } ] const performUnitWork = (deadline) => { // 取出第一个队列中的第一个任务并执行 console.log(`此帧的剩余时间为: ${deadline.timeRemaining()}`) taskQueue.shift()() } const workloop = (deadline) => { // 如果此帧剩余时间大于0或者已经到了定义的超时时间(上文定义了timeout时间为1000,到达时间时必须强制执行),且当时存在任务,则直接执行这个任务 // 如果没有剩余时间,则应该放弃执行任务控制权,把执行权交还给浏览器 while ((deadline.timeRemaining() > 0 || deadline.didTimeout) && taskQueue.length > 0) { performUnitWork(deadline) } // 如果还有未完成的任务,继续调用requestIdleCallback申请下一个时间片 if (taskQueue.length > 0) { window.requestIdleCallback(workloop, { timeout: 1000 }) } } requestIdleCallback(workloop, { timeout: 1000 })
11、实现一个sleep函数
async function test() {
console.log('Hello')
await sleep(1000)
console.log('world!')
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
test()
或
function sleep(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(time)
}, time)
})
}
sleep(5000).then(
(time) => {
console.log(`你睡了${time / 1000}s,然后做你的事情`)
}
)
12、实现数组push
Array.prototype.push2 = function(...arrs) { let len = this.length for(var i = 0; i < arrs.length; i++) { this[this.length] = arrs[i] } return this.length }
13、实现数组map
Array.prototype.map2 = function(callback) { let newArr = [] for(var i = 0; i < this.length; i++) { newArr.push(callback(this[i], i)) } return newArr } var arr = [1,2,3,4,5,6,7,8,9] console.log(arr.map2((item,index) => { return item * 2 }))
15、react setState 异步打印
class Root extends Component { constructor(props) { super(props); this.state = { count: 0 }; } componentDidMount() { let that = this; that.setState({ count: that.state.count + 1 }); console.log(that.state.count); // 打印出 0 that.setState({ count: that.state.count + 1 }); console.log(that.state.count); // 打印出 0 setTimeout(function(){ that.setState({ count: that.state.count + 1 }); console.log(that.state.count); // 打印出 2 }, 0); setTimeout(function(){ that.setState({ count: that.state.count + 1 }); console.log(that.state.count); // 打印出 3 }, 0); } render() { return ( <h1>{this.state.count}</h1> ) } }
16、队列调用
let fun1 = () => {console.log(1)} let fun2 = () => {console.log(2)} let fun3 = () => {console.log(3)} let fun4 = () => {console.log(4)} let fun5 = () => {console.log(5)} let fun6 = () => {console.log(6)} let arr = [fun1, fun2, fun3, fun4, fun5, fun6] function sleep(callBack){ return new Promise((resolve, regect) => { setTimeout(() => {resolve(); callBack(); arr.shift()}, 2000) }) } function row(){ if(arr && arr.length>0){ sleep(arr[0]).then(() => { row() console.log('123654') }) } }
17、保证每个时间点只有两个任务执行
let fun1 = () => {console.log(1)} let fun2 = () => {console.log(2)} let fun3 = () => {console.log(3)} let fun4 = () => {console.log(4)} let fun5 = () => {console.log(5)} let fun6 = () => {console.log(6)} let fun7 = () => {console.log(7)} let fun8 = () => {console.log(8)} let fun9 = () => {console.log(9)} let fun10 = () => {console.log(10)} let fun11 = () => {console.log(11)} let arr = [fun1, fun2, fun3, fun4, fun5, fun6, fun7, fun8, fun9, fun10, fun11] function sleep(callBack){ return new Promise((resolve, regect) => { let randon = Math.floor(Math.random() * 5000) setTimeout(() => {resolve(); callBack(); console.log(randon)}, randon) }) } function row(){ if(arr && arr.length>0){ sleep(arr.shift()).then(() => { row() }) } } row() row()
18、实现对数据的监听,当数据改变后触发操作
function createProxy(data) { if (typeof data === 'object' && data.toString() === '[object Object]') { for (let k in data) { if (typeof data[k] === 'object') { defineObjectReactive(data, k, data[k]) } else { defineBasicReactive(data, k, data[k]) } } } } function defineObjectReactive(obj, key, value) { // 递归 createProxy(value) obj[key] = new Proxy(value, { set(target, property, val, receiver) { if (property !== 'length') { RunAuto() // console.log('Set %s to %o', property, val) } return Reflect.set(target, property, val, receiver) } }) } function defineBasicReactive(obj, key, value) { Object.defineProperty(obj, key, { enumerable: true, configurable: false, get() { return value }, set(newValue) { if (value === newValue) return console.log(`发现 ${key} 属性 ${value} -> ${newValue}`) value = newValue } }) } let fun1 = () => {console.log(1)} let fun2 = () => {console.log(2)} let fun3 = () => {console.log(3)} let fun4 = () => {console.log(4)} let fun5 = () => {console.log(5)} let fun6 = () => {console.log(6)} let fun7 = () => {console.log(7)} let fun8 = () => {console.log(8)} let fun9 = () => {console.log(9)} let fun10 = () => {console.log(10)} let fun11 = () => {console.log(11)} let arr = [fun1, fun2, fun3, fun4, fun5, fun6, fun7, fun8, fun9] let data = {arr: arr, obj:{aaa: 'aaa'}} function sleep(callBack){ return new Promise((resolve, regect) => { let randon = Math.floor(Math.random() * 5000) setTimeout(() => {resolve(); callBack(); console.log(randon)}, randon) }) } function row(){ if(arr && arr.length>0){ sleep(arr.shift()).then(() => { row() }) } } function RunAuto(){ row(); row() } createProxy(data) data.arr.push(fun10, fun11)//数组改变后触发RunAuto() data.obj.aaa = 'aaa111'//发现 aaa 属性 aaa -> aaa111
19、节流函数
// 思路:在规定时间内只触发一次 function throttle (fn, delay) { // 利用闭包保存时间 let prev = Date.now() return function () { let context = this let arg = arguments let now = Date.now() if (now - prev >= delay) { fn.apply(context, arg) prev = Date.now() } } }
20、字符串转驼峰
// 字符串转驼峰 // camelCase('dwdDdwdS') => "DwdDdwdS" // camelCase('abc-de-FghiJ') => "AbcDeFghiJ" function camelCase(name) { return name.charAt(0).toUpperCase() + name.slice(1).replace(/-(\w)/g, (m, n) => { return n.toUpperCase(); }); }
21、多维数组展开
// 多维数组展开 export const flat = (list: any = []) => { return list.reduce((pre, cur) => { return cur.children ? [...pre, ...(cur.path ? [cur.path] : []), ...flat(cur.children)] : [...pre, ...(cur.path ? [cur.path] : [])] }, []) }
22、实现一个once函数,传入的函数只能执行一次
function ones(func){ var tag=true; return function(){ if(tag==true){ func.apply(null,arguments); tag=false; } } } function myfun() { console.log('hhhhhh') } myfun = ones(myfun) myfun() myfun()
23、将原生的 ajax 封装成 promise
//将原生的 ajax 封装成 promise function myNewAjax(url){ return new Promise(function(resolve,reject){ var xhr = new XMLHttpRequest(); xhr.open('get',url); xhr.send(data); xhr.onreadystatechange=function(){ if(xhr.status==200 && xhr.readyState==4){ var json=JSON.parse(xhr.responseText); resolve(json) }else if(xhr.readyState==4 && xhr.status!=200){ reject('error'); } } }) }
24、JS 监听对象属性的改变
// 方法一 let user = { name: 'hhhh' } let a = new Proxy(user, { get: function(target,key,value) { console.log('get') return Reflect.get(target,key,value); }, set:function(target,key,value,receiver){ console.log('set') return Reflect.set(target,key,value,receiver) } }) a.name = 'ggg'
// 方法二
let user = {
name: {
firstName: '李',
lastName: '楠',
},
age: 23,
}
function objectListenerES5(obj) { function loopObj(nextObj) { for (const key in nextObj) { if (Object.prototype.hasOwnProperty.call(nextObj, key)) { let element = nextObj[key]; console.log({ element, key }, typeof element === "object"); if (typeof element === "object") { loopObj(element); } else { Object.defineProperty(nextObj, key, { get: function () { console.log("====> get"); return element; }, set: function (newValue) { console.log("====> set", newValue); element = newValue; }, }); } } } } loopObj(obj); }
objectListenerES5(user)
user.name.lastName = '楠欣'
// 方法二 let user = { name: 'lll' } Object.defineProperty(user,'name',{ set: function(key,value){ console.log('set') user[key] = value }, get: function(value) { console.log('get') return value } }) user.name = 'ghj'
25、如何实现一个私有变量,用 getName 方法可以访问,不能直接访问
// 方法一: obj={ name:yuxiaoliang, getName:function(){ return this.name } } object.defineProperty(obj,"name",{ //不可枚举不可配置 enumerable: false }); // 方法二:通过函数的创建形式 function product(){ var name='yuxiaoliang'; this.getName=function(){ return name; } } var obj=new product();
26、写个函数,可以转化下划线命名到驼峰命名
// 写个函数,可以转化下划线命名到驼峰命名 function underLineTo(str) { strArr = str.split('_') return strArr.map((item, index) => { if (index == 0) { return item } return item.slice(0, 1).toUpperCase() + item.slice(1) }).join('') }