- 節(jié)流 防抖
- 用xhr手寫axios
- 函數(shù)柯里化
- 手寫promise
- 手寫reduce
- new
- 深拷貝
- string.indexOf()
9.reduce實(shí)現(xiàn)map - 深拷貝
- 柯里化
- 手寫repeat函數(shù)
- 手寫promise.all
- 手寫apply bind
- 實(shí)現(xiàn)一個(gè)eventbus
- 發(fā)布訂閱
1. 節(jié)流 防抖
//節(jié)流:一個(gè)函數(shù)執(zhí)行后包个,只有大于設(shè)定的執(zhí)行周期后粹庞,才會(huì)執(zhí)行第二次贩耐,
//有個(gè)需要頻繁出發(fā)的函數(shù)蚓土,出于性能優(yōu)化,在規(guī)定的時(shí)間內(nèi)桥帆,只讓出發(fā)的第一次生效医增,后邊的不生效
/* fn被節(jié)流的函數(shù) deley 規(guī)定時(shí)間*/
function throttle(fn, delay) {
//記錄上一次函數(shù)出發(fā)時(shí)間
let lastTime = 0
return function() {
//記錄當(dāng)前函數(shù)觸法的時(shí)間
let nowTime = Date.now()
if (nowTime - lastTime > delay) {
fn.call(this)
lastTime = nowTime
}
}
}
document.onscroll = throttle(() => {
console.log('觸發(fā)成功!' + Date.now())
}, 1000)
防抖
//防抖函數(shù):一個(gè)頻繁出發(fā)的函數(shù)老虫,在規(guī)定的某個(gè)時(shí)間內(nèi)叶骨,只讓最后一次生效,前邊的不生效如:頻繁點(diǎn)擊按鈕
function debounce(fn, delay) {
let timer = null
return function() {
//清楚上一次延時(shí)器
clearTimeout(timer)
//重新設(shè)置新的延時(shí)器祈匙,
timer = setTimeout(() => {
fn.call(this)
}, delay)
}
}
document.getElementById('btn').onclick = debounce(() => {
console.log("觸發(fā)了")
}, 2000)
2. 用xhr手寫axios(將原生的ajax封裝成promise)
var myNewAjax=function(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&&readyState==4){
var json=JSON.parse(xhr.responseText);
resolve(json)
}else if(xhr.readyState==4&&xhr.status!=200){
reject('error');
}
}
})
}
3. 函數(shù)柯里化
function curry(fn,val){
return function(){
//轉(zhuǎn)化為數(shù)組
var args = Array.from(arguments)
if(val){
//參數(shù)拼接
args = args.concat(val)
}
//fn.length 表示函數(shù)需要傳入多少參數(shù)
//遞歸調(diào)用 當(dāng)參數(shù)相等停止遞歸
if(fn.length > args.length){
return curry(fn,args)
}
return fn.apply(null,args)
}
}
function sum(a, b, c) {
console.log(a + b + c);
}
const fn = curry(sum);
fn(1,2,3)
fn(1)(2)(3)
4. 手寫promise
5. 手寫reduce
Array.prototype.reduce = function(fn, init) {
var arr = this // this就是調(diào)用reduce方法的數(shù)組
var total = init || arr[0] // 有初始值使用初始值
// 有初始值的話從0遍歷邓萨, 否則從1遍歷
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))
6. new
- new的具體步驟
- 創(chuàng)建一個(gè)空對(duì)象 var obj = {}
- 修改obj.proto=Dog.prototype
- 只改this指向并且把參數(shù)傳遞過去,call和apply都可以
根據(jù)規(guī)范,返回 null 和 undefined 不處理菊卷,依然返回obj
function _new(fn,...rest){
//基于fn的prototype構(gòu)建對(duì)象的原型
const thisObj = Object.create(fn.prototype);
//將thisObj作為fn的this,繼承其屬性宝剖,并獲取返回結(jié)果為result
const result = fn.apply(thisObj,rest);
//根據(jù)result對(duì)象的類型決定返回結(jié)果
return typeof result === "object" ? result : thisObj;
}
7. 深拷貝
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj==="object"){
for(key in obj){
//排除forin繼承父屬性
if(obj.hasOwnProperty(key)){
//判斷ojb子元素是否為對(duì)象洁闰,如果是,遞歸復(fù)制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是万细,簡(jiǎn)單復(fù)制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let a=[1,2,3,4],
b=deepClone(a);
a[0]=2;
console.log(a,b);
8. string.indexOf()
String.prototype.indexO = function(st){
// console.log(this.length);
let str = this;
var j = 0;
let reflag;
for(let i = 0;i< str.length;i++){
if (str.charAt(i) == st.charAt(0)){
// console.log(str.charAt(i))
// console.log(st.charAt(0))
let re_selft = i;
let _self = i;
while(j<st.length){
if(str.charAt(_self)!= st.charAt(j)){
reflag = -1;
return reflag;
}
else{
reflag = re_selft
}
_self++;
j++;
}
}
}
return reflag
}
9.reduce實(shí)現(xiàn)map
Array.prototype.mymap = function(fn,mapthis){
var res = []
var redthis = mapthis||null
this.reduce(function(sum,val,index,arr){
res.push(fn.call(redthis,val,index,arr))
},null)
return res
}
var arr = [1,2,3,5,1]
console.log(arr.mymap(val=>val*2));
10. 深拷貝
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj==="object"){
for(key in obj){
//排除forin繼承父屬性
if(obj.hasOwnProperty(key)){
//判斷ojb子元素是否為對(duì)象扑眉,如果是,遞歸復(fù)制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是赖钞,簡(jiǎn)單復(fù)制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let a=[1,2,3,4],
b=deepClone(a);
a[0]=2;
console.log(a,b);
11. 柯里化
function curry(fn,val){
return function(){
//轉(zhuǎn)化為數(shù)組
var args = Array.from(arguments)
if(val){
//參數(shù)拼接
args = args.concat(val)
}
//fn.length 表示函數(shù)需要傳入多少參數(shù)
//遞歸調(diào)用 當(dāng)參數(shù)相等停止遞歸
if(fn.length > args.length){
return curry(fn,args)
}
return fn.apply(null,args)
}
}
function sum(a, b, c) {
console.log(a + b + c);
}
const fn = curry(sum);
fn(1,2,3)//6
fn(1)(2)(3)//6
fn(1,2)(3)//6
12. 手寫repeat函數(shù)
function sleep (func,wait,args) {
return new Promise((resolve)=>{
setTimeout(()=>{
func.apply(this,args);
resolve()
},wait)
})
}
function repeat(func, times, wait,args) {
return async function () {
for(i = 0;i<times;i++){
await sleep(func,wait,args)
}
}
}
function alert(){
console.log('hellowWord');
}
const repeatFunc = repeat(alert, 4, 3000);
repeatFunc()
// 調(diào)用這個(gè) repeatFunc ("hellworld")腰素,會(huì)alert4次 helloworld, 每次間隔3秒
13. 手寫promise.all
function myPromiseAll(arr) { // 參數(shù)是一個(gè)iterable對(duì)象,一般是數(shù)組
// 返回一個(gè)Promise實(shí)例
return new Promise((resolve, reject) => {
var index = 0
var result = []
function newData(i,data){
result[i] = data
if(++index === arr.length){
resolve(result)
}
}
if (arr.lenght == 0) {
resolve()
} else {
for(let i = 0; i < arr.length ; i++){
if(arr[i].then){
arr[i].then(data=>{
newData(i,data)
},(err)=>{
reject(err)
console.log(arr);
// 輸出傳入的數(shù)組中每一個(gè) promise 執(zhí)行后的狀態(tài)和值
return
})
} else {
newData(i,arr[i])
}
}
}
});
}
let p1 = new Promise((resolve, reject)=> {
setTimeout(resolve, 2000, "P1 resolved");
})
let p2 = new Promise((resolve, reject)=> {
setTimeout(reject, 3000, "P2 resolved");
})
let p3 = new Promise((resolve, reject)=> {
setTimeout(resolve, 4000, "P3 resolved");
})
let pResult = myPromiseAll([p1,p2,p3]);
pResult.then(value=>{
console.log(pResult);
console.log(value);
},err=> {
console.log(pResult);
console.log(err);
})
// 輸入不僅僅只有Array
function promiseAll (args) {
return new Promise((resolve, reject) => {
const promiseResults = [];
let iteratorIndex = 0;
// 已完成的數(shù)量雪营,用于最終的返回弓千,不能直接用完成數(shù)量作為iteratorIndex
// 輸出順序和完成順序是兩碼事
let fullCount = 0;
// 用于迭代iterator數(shù)據(jù)
for (const item of args) {
// for of 遍歷順序,用于返回正確順序的結(jié)果
// 因iterator用forEach遍歷后的key和value一樣献起,所以必須存一份for of的 iteratorIndex
let resultIndex = iteratorIndex;
iteratorIndex += 1;
// 包一層洋访,以兼容非promise的情況
Promise.resolve(item).then(res => {
promiseResults[resultIndex] = res;
fullCount += 1;
// Iterator 接口的數(shù)據(jù)無(wú)法單純的用length和size判斷長(zhǎng)度镣陕,不能局限于Array和 Map類型中
if (fullCount === iteratorIndex) {
resolve(promiseResults)
}
}).catch(err => {
reject(err)
})
}
// 處理空 iterator 的情況
if(iteratorIndex===0){
resolve(promiseResults)
}
}
)
}
Race
function myPromiseRace(arr){
return new Promise((resolve,reject)=>{
arr.forEach(p=>{
Promise.resolve(p).then(data=>{
resolve(data)
},err=>{
reject(err)
})
})
})
}
let p1 = new Promise((resolve, reject)=> {
setTimeout(resolve, 2000, "P1 resolved");
})
let p2 = new Promise((resolve, reject)=> {
setTimeout(resolve, 1000, "P3 resolved");
})
let pResult = myPromiseRace([p1,p2]);
pResult.then(value=>{
console.log(pResult);
console.log(value);
},err=> {
console.log(pResult);
console.log(err);
})
14. 手寫apply bind
bind
Function.prototype.mybind = function () {
let args = Array.from(arguments);
let thisArg = args.shift();
let thisFunc = this;
return function F() {
newArgs = args.concat(Array.from(arguments));
if (this instanceof F){
return thisFunc.apply(this.newArgs)
}
return thisFunc.apply(thisArg, newArgs);
}
}
apply
Function.prototype.myApply = function(context) {
if (typeof context === 'undefined' || context === null) {
context = window
}
context.fn = this
let args = arguments[1]
let result
if (args) {
result = context.fn(...args)
} else {
result = context.fn()
}
delete context.fn
return result
}
call
Function.prototype.myCall = function(context) {
// 判斷是否是undefined和null
if (typeof context === 'undefined' || context === null) {
context = window
}
context.fn = this
let args = [...arguments].slice(1)
let result = context.fn(...args)
delete context.fn
return result
}
15. 實(shí)現(xiàn)一個(gè)eventbus
function EventBus() {}
EventBus.prototype.on = function (name, callback) {
//如果沒有事件對(duì)象,新增一個(gè)
if(!this._events){
//創(chuàng)建一個(gè)干凈的沒有原型鏈的對(duì)象
this._events = Object.create(null);
}
//如果沒有這個(gè)事件的訂閱姻政,新增一個(gè)呆抑,如果有,push進(jìn)去
if(!this._events[name]){
this._events[name] = [callback];
}else{
this._events[name].push(callback);
}
}
EventBus.prototype.emit = function (name, ...args) {
//發(fā)布的時(shí)候汁展,如果有這個(gè)事件鹊碍,循環(huán)執(zhí)行所有這個(gè)訂閱的方法
if(this._events[name]){
this._events[name].forEach(callback => {
callback(...args);
})
}
}
EventBus.prototype.off = function (name) {
//如果有這個(gè)事件的訂閱,清除所有訂閱
if(this._events[name]){
delete this._events[name];
}
}
EventBus.prototype.once = function (name, callback) {
let once = (...args) => {
callback(...args);
this.off(name);
};
this.on(name, once);
}
let eventBus = new EventBus();
eventBus.on('on', function (msg) {
console.log(msg);
})
eventBus.once('once', function (msg) {
console.log(msg);
})
eventBus.on('off', function (msg) {
console.log(msg);
})
eventBus.emit('on', '發(fā)布o(jì)n1')//發(fā)布o(jì)n1
eventBus.emit('on', '發(fā)布o(jì)n2')//發(fā)布o(jì)n2
eventBus.emit('once', '發(fā)布o(jì)nce')//發(fā)布o(jì)nce
eventBus.emit('once', '發(fā)布o(jì)nce')
eventBus.emit('off', '發(fā)布o(jì)ff')//發(fā)布o(jì)ff
eventBus.off('off')
eventBus.emit('off', '發(fā)布o(jì)ff')
16. 發(fā)布訂閱
class Event {
// Events<String, Function[]>
events = {};
emit(type, ...args) {
// 發(fā)布事件
// 可以傳遞多個(gè)參數(shù)食绿,每個(gè)事件處理函數(shù)都會(huì)被執(zhí)行一次
const listeners = this.events[type];
for (const listener of listeners) {
listener(...args);
}
}
on(type, listener) {
// 注冊(cè)事件
// 一個(gè)事件可以綁定多個(gè)事件處理函數(shù)
this.events[type] = this.events[type] || [];
this.events[type].push(listener);
}
}
const e = new Event();
e.on("click", x => console.log(x.id));
e.emit("click", { id: 3 }); // 3
e.emit("click", { id: 4 }); // 4
17. 數(shù)組扁平化
1. reduce
function flatten(arr) {
return arr.reduce((result, item)=> {
return result.concat(Array.isArray(item) ? flatten(item) : item);
}, []);
}
2. toString & split
function flatten(arr) {
return arr.toString().split(',').map(function(item) {
return Number(item);
})
}
3. join & split
和上面的toString一樣侈咕,join也可以將數(shù)組轉(zhuǎn)換為字符串
function flatten(arr) {
return arr.join(',').split(',').map(function(item) {
return parseInt(item);
})
}
4. 遞歸
遞歸的遍歷每一項(xiàng),若為數(shù)組則繼續(xù)遍歷炫欺,否則concat
function flatten(arr) {
var res = [];
arr.map(item => {
if(Array.isArray(item)) {
res = res.concat(flatten(item));
} else {
res.push(item);
}
});
return res;
}
5. 擴(kuò)展運(yùn)算符
es6的擴(kuò)展運(yùn)算符能將二維數(shù)組變?yōu)橐痪S
[].concat(...[1, 2, 3, [4, 5]]); // [1, 2, 3, 4, 5]
function flatten(arr) {
while(arr.some(item=>Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
18. 扁平數(shù)組轉(zhuǎn)換為數(shù)
function getTree(arr, parent) {
let temp = arr.slice()
let newArr = []
temp.forEach(item => {
if (item.parentId === parent) {
let obj = {}
obj.id = item.id
obj.parentId = item.parentId // 這一塊可以寫一個(gè)深拷貝
obj.children = getTree(temp, item.id)
newArr = newArr.concat(obj)
}
})
return newArr
}