Xi-Yuer

Xi-Yuer

github

Javascript

JavaScript#

JS 語法集合#

實現 call 函數#

Function.prototype.wxcall = function (thisArg, ...arg) {
  var fn = this;
  thisArg = thisArg ? Object(thisArg) : window;
  thisArg.fn = fn;
  return thisArg.fn(...arg);
};

console.log(foo.wxcall('abc', 10, 20));
console.log(foo.wxcall({}, 10, 20));
let result = foo.wxcall(null, 10, 20);
console.log(result);

apply 函數實現#

Function.prototype.wxapply = function (thisArg, arrArg) {
  var fn = this;
  thisArg = thisArg ? Object(thisArg) : window;
  thisArg.fn = fn;
  arrArg ? thisArg.fn(...arrArg) : thisArg.fn(); //是否有傳入參數
  delete thisArg.fn;
};

function foo(a, b, c) {
  console.log(a + b + c);
}
foo.wxapply({}, [10, 20, 30]);
foo.wxapply({}, [10, 20, 30]);

實現 slice 函數#

Array.prototype.wxslice = function (start, end) {
  var arr = this;
  let newArr = [];
  for (let i = start; i < end; i++) {
    newArr.push(arr[i]);
  }
  return newArr;
};
console.log([1, 2, 3, 4, 5, 6, 7, 8].wxslice(0, 2));

defineProperty#

const obj = {
  name: 'Tom',
  age: 18,
};

// Object.defineProperty(obj,'name',{
//     get:function(){
//         console.log('監聽到name屬性被訪問到了');
//     },
//     set:function(){
//         console.log('監聽到name屬性被設置了');
//     }
// })

// console.log(obj.name); //監聽到name屬性被訪問到了
// obj.name = 'Kobe' //監聽到name屬性被設置了

// 可以獲取到對象所有的keys
Object.keys(obj).forEach(key => {
  let value = obj[key];
  console.log(key);
  /*  name
        age
     */
  Object.defineProperty(obj, key, {
    get: function () {
      console.log('監聽到屬性被訪問了');
      return value;
    },
    set: function (newValue) {
      console.log('監聽到name屬性被設置了');
    },
  });
});
console.log(obj.name); //監聽到name屬性被訪問到了
obj.name = 'Kobe'; //監聽到name屬性被設置了

Proxy 代理#

const obj = {
  name: 'Tom',
  age: 18,
  height: 1.88,
};

// 創建一個proxy代理

// 參數一:對obj對象進行代理 參數二:捕獲器(有13種捕獲器)
const objProxy = new Proxy(obj, {
  // 獲取值的捕獲器(在獲取值的時候自動回調該函數)
  get: function (target, key) {
    // target 是被代理的對象; key
    console.log(target); //{ name: 'Tom', age: 18, height: 1.88 }
    console.log(key); // name 獲取了誰 key就是誰
    return target[key];
  },

  // 設置值的捕獲器(在設置值的時候自動回調該函數)
  set: function (target, key, newValue) {
    target[key] = newValue;
  },
});
// 訪問
// console.log(objProxy); // { name: 'Tom', age: 18, height: 1.88 }
// console.log(objProxy.name); // Tom
// console.log(objProxy.age); // 18
// 設置
// objProxy.name = "Kobe"; // 通過代理
console.log(objProxy.name); // Kobe

響應式原理#

class Depend {
  constructor() {
    this.reactiveFns = [];
  }
  // 收集依賴
  addDepend(reactiveFn) {
    this.reactiveFns.push(reactiveFn);
  }
  // 執行依賴
  notify() {
    // 遍歷所有依賴並執行
    this.reactiveFns.forEach(fn => {
      fn();
    });
  }
}

const depend = new Depend();
const obj = {
  name: 'Tom',
  age: 18,
};
// 監聽屬性的變化(proxy,object.defineProperty)發生改變,執行depend.notify()
const objProxy = new Proxy(obj, {
  get: function (target, key, receiver) {
    // 將獲取值返回出去
    return Reflect.get(target, key, receiver);
  },
  // 給代理對象設置值的時候會自動執行該方法
  set: function (target, key, newvalue, receiver) {
    Reflect.set(target, key, newvalue, receiver);
    // 設置值時通知depend執行依賴
    depend.notify();
  },
});
function foo() {
  console.log('執行代碼');
}
depend.addDepend(foo); //收集依賴
objProxy.name = 'Lilei';

迭代器#

//迭代器需要滿足以下條件
// 一、是個對象
// 二、對象有一個next方法
// 三、該方法返回一個對象,且該對象有done和value屬性
// const iterator = {
//   next: function () {
//     return { done: true, value: "" };
//   },
// };

// 陣列
const arr = ['abc', 'cba', 'nba'];
// 使用迭代器遍歷陣列
// 創建一個迭代器對象來訪問該陣列
let index = 0;
const arrIterator = {
  next: function () {
    if (index < arr.length) {
      return { done: false, value: arr[index++] };
    } else {
      return { done: true, value: undefined };
    }
  },
};
console.log(index); //0
console.log(arrIterator.next()); //{ done: false, value: 'abc' }

console.log(index); //1
console.log(arrIterator.next()); //{ done: false, value: 'cba' }

console.log(index); //2
console.log(arrIterator.next()); //{ done: false, value: 'nba' }

console.log(index); //3
console.log(arrIterator.next()); //{ done: true, value: undefined }

console.log(index); //3

// 迭代器優化

迭代器生成函數#

function createArryIterator(arr) {
  let index = 0;
  return {
    next: function () {
      if (index < arr.length) {
        return { done: false, value: arr[index++] };
      } else {
        return { done: true, value: undefined };
      }
    },
  };
}

const names = ['Tom', 'Sily', 'Lusy'];
const nameIterator = createArryIterator(names);
console.log(nameIterator.next()); //{ done: false, value: 'Tom' }
console.log(nameIterator.next()); //{ done: false, value: 'Sily' }
console.log(nameIterator.next()); //{ done: false, value: 'Lusy' }

const nums = [1, 2, 3, 4, 5];
const numsIterator = createArryIterator(nums);
console.log(numsIterator.next()); //{ done: false, value: 1 }
console.log(numsIterator.next()); //{ done: false, value: 2 }
console.log(numsIterator.next()); //{ done: false, value: 3 }
console.log(numsIterator.next()); //{ done: false, value: 4 }

// 創建一個無限的迭代器
function createNumberIterator() {
  let index = 0;
  return {
    next: function () {
      return {
        done: false,
        value: index++,
      };
    },
  };
}
const numberInterator = createNumberIterator();
console.log(numberInterator.next()); //{ done: false, value: 0 }
console.log(numberInterator.next()); //{ done: false, value: 1 }
console.log(numberInterator.next()); //{ done: false, value: 2 }
console.log(numberInterator.next()); //{ done: false, value: 3 }
console.log(numberInterator.next()); //{ done: false, value: 4 }
console.log(numberInterator.next()); //{ done: false, value: 5 } ......

迭代器對象#

// 該對象返回一個迭代器
const iterabalObj = {
  names: ['Tom', 'Sily', 'Lusy'],
  // 可迭代對象需要有 [Symbol.iterator] 這個屬性,對應的是一個函數,該函數返回的是一個迭代器
  [Symbol.iterator]: function () {
    let index = 0;
    return {
      next: () => {
        if (index < this.names.length) {
          return { done: false, value: this.names[index++] };
        } else {
          return { done: true, value: undefined };
        }
      },
    };
  },
};
console.log(iterabalObj[Symbol.iterator]); //[Function: [Symbol.iterator]]

// 調用該函數會為我們生成一個新的迭代器
const iterator = iterabalObj[Symbol.iterator]();
console.log(iterator.next()); //{ done: false, value: 'Tom' }
console.log(iterator.next()); //{ done: false, value: 'Sily' }
console.log(iterator.next()); //{ done: false, value: 'Lusy' }

// 新的迭代器
const iterator1 = iterabalObj[Symbol.iterator]();
console.log(iterator1.next()); //{ done: false, value: 'Tom' }
console.log(iterator1.next()); //{ done: false, value: 'Sily' }
console.log(iterator1.next()); //{ done: false, value: 'Lusy' }

for (const item of iterabalObj) {
  console.log(item);
  //   Tom
  //   Sily
  //   Lusy
}

生成器#

// 生成器函數(*)
function* foo() {
  console.log(1);
  yield;

  console.log(2);
  // yield 可以控制函數停止
  yield;

  console.log(3);
  yield;

  console.log(4);
}
// 調用生成器函數該函數不會直接執行,而是返回一個生成器對象
// console.log(foo()); // Object [Generator] {}
const Generator = foo();

// 開始執行第一段代碼(yield之前的代碼)執行next()
Generator.next(); //1

// 開始執行第二段代碼
Generator.next(); //2

// 開始執行第三段代碼
Generator.next(); //3

// 開始執行第四段代碼
Generator.next(); //4

生成器函數執行流程#

function* foo() {
  console.log(1);
  yield '返回值'; //該段代碼的返回值
  console.log(2);
  yield;
  console.log(3);
  yield;
  console.log(4);
}
const Generator = foo();
// 返回值是value ,done:false
console.log(Generator.next()); // { value: { name: 'tom', age: 18 }, done: false }
// Generator.next() // 1

// 生成器函數 function*
// yeild 關鍵字可以使代碼在這裡進行暫停
// 執行生成器函數會返回一個生成器對象
// 調用該生成器對象的next方法會依次執行yield之前的代碼,
// 再次調用next()會繼續執行下個yield之前的代碼
// 每個yield之前的代碼若想返回某些值的話,可以將返回值寫在yeild後面

生成器參數問題#

// 每段代碼的參數問題
function* foo() {
  console.log(1);
  // 第二次執行next函數傳入的參數會賦值給第一次yield的返回值
  const n = yield;

  // 第二段代碼是執行第二次next執行的
  console.log(2 * n); // 20
  yield '返回值 :console.log(Generator.next()) // 返回值 ......';

  console.log(3);
  yield;

  console.log(4);
}

const Generator = foo();
Generator.next();
Generator.next(10);

// 執行兩次 Generator.next()
// 第二次執行的時候有傳入一個參數
// 該參數會作為第一個yield的返回值  const n = yield 使用 n 接受該返回值

宏任務 & 微任務#

// await 之後的代碼屬於微任務
// async function a() {
//     console.log('a')
//     await b()
//     console.log('a end')
// }

// async function b() {
//     console.log('b')
// }

// a()

// setTimeout(function () {
//     console.log('setTimeout')
// }, 0)

// new Promise(function (resolve, reject) {
//     console.log('promise')
//     resolve()
// }).then(function () {
//     console.log('then')
// })

// console.log('main end')

// //
setTimeout(function () {
  console.log('8');
}, 0);
async function async1() {
  console.log('1');
  const data = await async2();
  console.log('6');
  return data;
}
async function async2() {
  return new Promise(resolve => {
    console.log('2');
    resolve('async2的結果');
  }).then(data => {
    console.log('4');
    return data;
  });
}
async1().then(data => {
  console.log('7');
  console.log(data);
});
new Promise(function (resolve) {
  console.log('3');
  resolve();
}).then(function () {
  console.log('5');
});

//

console.log('script start');

async function async1() {
  await async2();
  console.log('async1 end');
}
async function async2() {
  console.log('async2 end');
}
async1();

setTimeout(function () {
  console.log('setTimeout');
}, 0);

new Promise(resolve => {
  console.log('Promise');
  resolve();
})
  .then(function () {
    console.log('promise1');
  })
  .then(function () {
    console.log('promise2');
  });

console.log('script end');

//

// console.log('script start')

// async function async1() {
//     await async2()
//     console.log('async1 end')
// }
// async function async2() {
//     console.log('async2 end')
//     return Promise.resolve().then(()=>{
//         console.log('async2 end1')
//     })
// }
// async1()

// setTimeout(function() {
//     console.log('setTimeout')
// }, 0)

// new Promise(resolve => {
//     console.log('Promise')
//     resolve()
// })
// .then(function() {
//     console.log('promise1')
// })
// .then(function() {
//     console.log('promise2')
// })

// console.log('script end')

// async function async1(){
//   await async2()
//   console.log('async1 end')
// }
// async function async2(){}
// async1();
// new Promise(function(resolve){
//   resolve();
// }).then(function(){
//   console.log('promise2')
// }).then(function() {
//   console.log('promise3')
// }).then(function() {
//   console.log('promise4')
// })

防抖#

function debounce(fn, delay) {
  let timer = null;
  return (...args) => {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

// 第一次是否直接執行
function debounce(fn, delay, isImmediately = true) {
  let timer = null;
  let Immediately = isImmediately;
  return (...args) => {
    if (timer) clearTimeout(timer);
    Immediately
      ? fn.apply(this, args)
      : (timer = setTimeout(() => fn.apply(this, args), delay));
    Immediately = !isImmediately;
  };
}

節流#

function throttle(fn, delay) {
  let pre = 0;
  return (...args) => {
    let now = new Date();
    if (now - pre > delay) {
      fn.apply(this, args);
    }
    pre = now;
  };
}

深拷貝#

function isObject(value) {
  const valueType = typeof value;
  return (value !== null && valueType === 'object') || valueType === 'function';
}

function deepClone(originValue) {
  // 判斷是否是symbol類型,創建一個新的symbol
  if (typeof originValue === 'symbol') {
    return Symbol(originValue.description);
  }
  if (typeof originValue === 'function') {
    // 判斷是否是函數直接返回
    return originValue;
  }
  if (originValue instanceof Set) {
    return new Set([...originValue]);
  }
  if (originValue instanceof Map) {
    return new Map([...originValue]);
  }
  //判斷傳入的origin是否是一個對象類型
  if (!isObject(originValue)) {
    return originValue;
  }
  //判斷傳入的對象是陣列還是對象
  const newObject = Array.isArray(originValue) ? [] : {};
  //遍歷原始對象並將原始對象的屬性值克隆到新對象中
  for (const key in originValue) {
    newObject[key] = deepClone(originValue[key]); //遞歸調用
  }
  const symbolKeys = Object.getOwnPropertySymbols(originValue);
  for (const skey of symbolKeys) {
    newObject[skey] = deepClone(originValue[skey]);
  }
  return newObject;
}
const obj1 = {
  name: 'Tom',
  fridends: {
    one: {
      name: 'sily',
    },
    tow: {
      name: 'kobe',
    },
  },
};
console.log(deepClone(obj1));

事件總線#

class EventBus {
  constructor() {
    this.eventBus = {};
  }

  on(eventName, eventCallBack, thisArg) {
    let handlers = this.eventBus[eventName];
    if (!handlers) {
      handlers = [];
      this.eventBus[eventName] = handlers;
    }
    handlers.push({
      eventCallBack,
      thisArg,
    });
  }
  off() {}
  emit(eventName, ...payload) {
    const handlers = this.eventBus[eventName];
    if (!handlers) return;
    handlers.forEach(handler => {
      handler.eventCallBack.apply(handler.thisArg, payload);
    });
  }
}
const eventBus = new EventBus();

// mian.js
eventBus.on(
  'a',
  function (payload) {
    console.log(payload);
  },
  this
);
// utill.js
eventBus.emit('a', { name: 'Tom' });

實現 slice 函數#

    
Array.prototype.wxslice = function (start, end) {
    var arr = this
    let newArr = []
    for (let i = start; i < end; i++) {
        newArr.push(arr[i])
    }
    return newArr
}
console.log([1, 2, 3, 4, 5, 6, 7, 8].wxslice(0, 2));
    

實現 call 函數#

    
// 給所有函數添加一個wxapply方法
// Function.prototype.wxcall = function (thisArg, ...arg) { //傳入this和參數
//     // 在這裡需要可以執行調用該方法的那個函數
//     // 問題:那個函數執行了call
//     var fn = this //誰調用了誰就是this
//     // 對thisArg轉成對象類型,防止傳入的this是數字或者其他非對象類型
//     // 如果傳入的是Null或者undifind就將this綁定到window
//     thisArg = thisArg ? Object(thisArg) : window
//     thisArg.fn = fn //執行該函數
//     thisArg.fn(...arg) //綁定this和參數
//     delete thisArg.fn
// }

// function foo(a, b) {
//     console.log('執行');
//     console.log(this);
//     console.log(a + b);
// }
// foo.wxcall({}, 10, 20)



// Function.prototype.wxcall = function (thisArg, ...arg) {
//     var fn = this
//     thisArg = thisArg ? Object(thisArg) : window
//     thisArg.fn = fn
//     thisArg.fn(...arg)
// }

// function foo(a, b) {
//     console.log(a + b);
// }
// foo.wxcall({}, 10, 20)
// foo.wxcall(123, 10, 20)




Function.prototype.wxcall = function (thisArg, ...arg) {
    var fn = this
    thisArg = thisArg ? Object(thisArg) : window
    thisArg.fn = fn
    return thisArg.fn(...arg)
}

function foo(a, b) {
    return a + b
}
console.log(foo.wxcall('abc', 10, 20));
console.log(foo.wxcall({}, 10, 20));
let result = foo.wxcall(null, 10, 20)
console.log(result);
    

生成迭代器的函數#

    
function createArryIterator(arr){
    let index = 0
    return {
        next:function(){
            if(index < arr.length){
                return { done:false, value:arr[index++]}
            }else{
                return { done:true, value:undefined}
            }
        }
    }
}

const names = ['Tom','Sily','Lusy']
const nameIterator = createArryIterator(names)
console.log(nameIterator.next()); //{ done: false, value: 'Tom' }
console.log(nameIterator.next()); //{ done: false, value: 'Sily' }   
console.log(nameIterator.next()); //{ done: false, value: 'Lusy' }  

const nums = [1,2,3,4,5]
const numsIterator = createArryIterator(nums)
console.log(numsIterator.next()); //{ done: false, value: 1 }   
console.log(numsIterator.next()); //{ done: false, value: 2 }   
console.log(numsIterator.next()); //{ done: false, value: 3 } 
console.log(numsIterator.next()); //{ done: false, value: 4 }   



// 創建一個無限的迭代器
function createNumberIterator(){
    let index = 0
    return {
        next:function(){
            return {
                done:false,
                value:index++
            }
        }
    }
}
const numberInterator = createNumberIterator()
console.log(numberInterator.next()); //{ done: false, value: 0 }  
console.log(numberInterator.next()); //{ done: false, value: 1 } 
console.log(numberInterator.next()); //{ done: false, value: 2 }  
console.log(numberInterator.next()); //{ done: false, value: 3 } 
console.log(numberInterator.next()); //{ done: false, value: 4 }  
console.log(numberInterator.next()); //{ done: false, value: 5 } ......
    

apply 函數的實現#

    
Function.prototype.wxapply = function (thisArg, arrArg) {
    var fn = this
    thisArg = thisArg ? Object(thisArg) : window
    thisArg.fn = fn
    arrArg ? thisArg.fn(...arrArg) : thisArg.fn() //是否有傳入參數
    delete thisArg.fn
}

function foo(a, b, c) {
    console.log(a + b + c);
}
foo.wxapply({}, [10, 20, 30])
foo.wxapply({}, [10, 20, 30])


// // 陣列扁平化
// function flatten(arr) {
//     return arr.reduce((pre, cur) => {
//         return pre.concat(Array.isArray(cur) ? flatten(cur) : cur)
//     }, [])
// }

// // 冒泡排序
function bubbleSort(arr) {
    var len = arr.length
    for (var i = 0; i < len; i++) {
        for (var j = 0; j < len - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                var temp = arr[j]
                arr[j] = arr[j + 1]
                arr[j + 1] = temp
            }
        }
    }
    return arr
}




const arr = [1,9,2,8,3,7,4,6]
function fn(arr) {
    const tem = []
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] < arr[i + 1]) {
            tem.push(arr[i])
        }else{
            let tem = arr[i]
            arr[i] = arr[i + 1]
            arr[i + 1] = tem
        }
    }
    return tem
}
console.log(fn(arr))

// 發布訂閱模式
function Event() {
    this.handlers = []
}
Event.prototype.addHandler = function (handler) {
    this.handlers.push(handler)
}
Event.prototype.removeHandler = function (handler) {
    this.handlers = this.handlers.filter(item => item !== handler)
}
Event.prototype.fire = function (sender, args) {
    this.handlers.forEach(item => item(sender, args))
}

// **HTTP常見狀態碼及其含義**
// 200 OK
// 201 Created
// 202 Accepted
// 203 Non-Authoritative Information
// 204 No Content
// 205 Reset Content
// 206 Partial Content
// 300 Multiple Choices
// 301 Moved Permanently
// 302 Found
// 303 See Other
// 304 Not Modified
// 305 Use Proxy
// 307 Temporary Redirect
// 400 Bad Request
// 401 Unauthorized
// 402 Payment Required
// 403 Forbidden
// 404 Not Found
// 405 Method Not Allowed
// 406 Not Acceptable
// 407 Proxy Authentication Required
// 408 Request Timeout
// 409 Conflict
// 410 Gone
// 411 Length Required
// 412 Precondition Failed
// 413 Request Entity Too Large
// 414 Request-URI Too Long
// 415 Unsupported Media Type
// 416 Requested Range Not Satisfiable
// 417 Expectation Failed
// 500 Internal Server Error
// 501 Not Implemented
// 502 Bad Gateway
// 503 Service Unavailable
// 504 Gateway Timeout
// 505 HTTP Version Not Supported

// HTTP有哪些請求方法,GET 和 POST 有什麼區別
// GET:查詢
// POST:提交
// PUT:更新
// DELETE:刪除
// HEAD:請求頭
// OPTIONS:請求選項
// TRACE:請求軌跡
// CONNECT:請求連接
// PATCH:請求補充


//GET 和 POST 有什麼區別


// HTTP協議中的header及含義
// Accept:客戶端可以接受的內容類型
// Accept-Charset:客戶端可以接受的字符集
// Accept-Encoding:客戶端可以接受的編碼方式
// Accept-Language:客戶端可以接受的語言
// Authorization:認證信息
// Cache-Control:緩存控制
// Connection:連接方式
// Cookie:Cookie信息
// Content-Length:內容長度
// Content-Type:內容類型
// Date:日期
// Expect:期望
// From:來源
// Host:主機
// If-Match:如果匹配
// If-Modified-Since:如果修改了
// If-None-Match:如果不匹配
// If-Range:如果範圍
// If-Unmodified-Since:如果未修改
// Max-Forwards:最大轉發數
// Pragma:簡短請求頭
// Proxy-Authorization:代理認證
// Range:範圍
// Referer:來源
// TE:傳輸編碼
// Upgrade:升級
// User-Agent:用戶代理
// Via:通過
// Warning:警告
// X-Requested-With:請求類型
// X-Forwarded-For:轉發的客戶端IP
// X-Forwarded-Host:轉發的客戶端主機
// X-Forwarded-Server:轉發的服務器
// X-Frame-Options:框架配置
// X-XSS-Protection:XSS防護
// X-Content-Type-Options:內容類型配置
// X-Powered-By:服務器提供
// X-UA-Compatible:瀏覽器兼容性

// 輸入url並按下回車鍵的時候過程中發生了什麼
// 1. 客戶端發送請求
// 2. 服務器接收請求
// 3. 服務器根據請求處理請求
// 4. 服務器返回響應
// 5. 客戶端接收響應

// **瀏覽器事件傳輸機制原理**
// 在瀏覽器中,事件傳輸機制是通過事件冒泡的方式來實現的,事件冒泡是從最近的元素到最遠的元素,每個元素都會觸發事件,事件的觸發是通過事件冒泡的方式來實現的。
    

實現 instanceof#

function isPrototypeOf(obj) {
    var proto = this.prototype
    while (obj) {
        if (obj === proto) {
            return true
        }
        obj = Object.getPrototypeOf(obj)
    }
    return false
}

可迭代對象#

    
// 該對象返回一個迭代器
const iterabalObj = {
    names : ['Tom','Sily','Lusy'],
    // 可迭代對象需要有 [Symbol.iterator] 這個屬性,對應的是一個函數,該函數返回的是一個迭代器
    [Symbol.iterator]:function(){
        let index = 0
        return {
            next:()=>{
                if(index < this.names.length){
                    return { done:false, value:this.names[index++]}
                }else{
                    return { done:true, value:undefined}
                }
            }
        }
    }
}
console.log(iterabalObj[Symbol.iterator]); //[Function: [Symbol.iterator]]

// 調用該函數會為我們生成一個新的迭代器
const iterator = iterabalObj[Symbol.iterator]()
console.log(iterator.next()); //{ done: false, value: 'Tom' }   
console.log(iterator.next()); //{ done: false, value: 'Sily' }  
console.log(iterator.next()); //{ done: false, value: 'Lusy' }  

// 新的迭代器
const iterator1 = iterabalObj[Symbol.iterator]()
console.log(iterator1.next()); //{ done: false, value: 'Tom' }    
console.log(iterator1.next()); //{ done: false, value: 'Sily' }  
console.log(iterator1.next()); //{ done: false, value: 'Lusy' }  

for(const item of iterabalObj){
    console.log(item);
            //   Tom
            //   Sily
            //   Lusy
}
    

監聽對象操作#

    
const obj = {
    name:'Tom',
    age:18
}

// Object.defineProperty(obj,'name',{
//     get:function(){
//         console.log('監聽到name屬性被訪問到了');
//     },
//     set:function(){
//         console.log('監聽到name屬性被設置了');
//     }
// })

// console.log(obj.name); //監聽到name屬性被訪問到了
// obj.name = 'Kobe' //監聽到name屬性被設置了

// 可以獲取到對象所有的keys
Object.keys(obj).forEach(key=>{
    let value = obj[key]
    console.log(key); 
    /*  name
        age
     */
    Object.defineProperty(obj,key,{
        get:function(){
            console.log('監聽到屬性被訪問了');
            return value
        },
        set:function(newValue){
            console.log('監聽到name屬性被設置了');
        }
    })
})
console.log(obj.name); //監聽到name屬性被訪問到了
obj.name = 'Kobe' //監聽到name屬性被設置了
    

響應式原理#

    
class Depend {
    constructor(){
        this.reactiveFns = []
    }
    // 收集依賴
    addDepend(reactiveFn){
        this.reactiveFns.push(reactiveFn)
    }
    // 執行依賴
    notify(){
        // 遍歷所有依賴並執行
        this.reactiveFns.forEach(fn => {
            fn()
        })
    }
}

const depend = new Depend()
const obj = {
    name:'Tom',
    age:18
}
// 監聽屬性的變化(proxy,object.defineProperty)發生改變,執行depend.notify()
const objProxy = new Proxy(obj,{
    get:function(target,key,receiver){
        // 將獲取值返回出去
        return Reflect.get(target,key,receiver)
    },
    // 給代理對象設置值的時候會自動執行該方法
    set:function(target,key,newvalue,receiver){
        Reflect.set(target,key,newvalue,receiver)
        // 設置值時通知depend執行依賴
        depend.notify()
    }
})
function foo(){
    console.log('執行代碼');
}
depend.addDepend(foo) //收集依賴
objProxy.name = 'Lilei'


    

迭代器#

    
//迭代器需要滿足以下條件
// 一、是個對象
// 二、對象有一個next方法
// 三、該方法返回一個對象,且該對象有done和value屬性
// const iterator = {
//   next: function () {
//     return { done: true, value: "" };
//   },
// };


// 陣列
const arr = ['abc','cba','nba']
// 使用迭代器遍歷陣列
// 創建一個迭代器對象來訪問該陣列
let index = 0
const arrIterator = {
    next:function(){
        if(index < arr.length){
            return { done:false, value:arr[index++]}
        }else{
            return { done:true, value:undefined }
        }
    }
}
console.log(index); //0
console.log(arrIterator.next()); //{ done: false, value: 'abc' }

console.log(index); //1
console.log(arrIterator.next()); //{ done: false, value: 'cba' } 

console.log(index); //2
console.log(arrIterator.next()); //{ done: false, value: 'nba' }   

console.log(index); //3
console.log(arrIterator.next()); //{ done: true, value: undefined } 

console.log(index); //3  

// 迭代器優化

    

自定義類的可迭代性#

    
// 自定義迭代類
class Clasroom {
  constructor(address, name, students) {
    this.address = address;
    this.name = name;
    this.students = students;
  }
  entry(newStudents) {
    this.students.push(newStudents);
  }
  [Symbol.iterator]() {
    //   該函數返回一個迭代器
    let index = 0;
    return {
      next: () => {
        if (index < this.students.length) {
          return { done: false, value: this.students[index++] };
        } else {
          return { done: true, value: undefined };
        }
      },
    };
  }
}

const classroom = new Clasroom("北京市", "一小", ["tom", "sily", "kobe"]);
for (item of classroom) {
    console.log(item);
            // tom
            // sily
            // kobe
}

    

內置創建可迭代對象#

    
const names = ['abc','cba','nba']
console.log(names[Symbol.iterator]); //[Function: values]

const iterator = names[Symbol.iterator]() //執行該函數會返回一個迭代器

console.log(iterator.next()); //{ value: 'abc', done: false }
console.log(iterator.next()); //{ value: 'cba', done: false }  
console.log(iterator.next()); //{ value: 'nba', done: false }    
console.log(iterator.next()); //{ value: undefined, done: true }    
    

生成器參數問題#

    
// 每段代碼的參數問題
function* foo() {
    console.log(1);
    // 第二次執行next函數傳入的參數會賦值給第一次yield的返回值
    const n = yield

    // 第二段代碼是執行第二次next執行的
    console.log(2 * n);     // 20
    yield '返回值 :console.log(Generator.next()) // 返回值 ......'

    console.log(3);
    yield

    console.log(4);
}

const Generator = foo()
Generator.next()
Generator.next(10) 


// 執行兩次 Generator.next()
// 第二次執行的時候有傳入一個參數
// 該參數會作為第一個yield的返回值  const n = yield 使用 n 接受該返回值
    

生成器函數的執行流程#

    
function* foo() {
    console.log(1);
    yield '返回值' //該段代碼的返回值
    console.log(2);
    yield
    console.log(3);
    yield
    console.log(4);
}
const Generator = foo()
                                // 返回值是value ,done:false
console.log(Generator.next()); // { value: { name: 'tom', age: 18 }, done: false }
// Generator.next() // 1




// 生成器函數 function*
// yeild 關鍵字可以使代碼在這裡進行暫停
// 執行生成器函數會返回一個生成器對象
// 調用該生成器對象的next方法會依次執行yield之前的代碼,再次調用next()會繼續執行下個yield之前的代碼
// 每個yield之前的代碼若想返回某些值的話,可以將返回值寫在yeild後面
    

Proxy 代理的使用#

    
const obj = {
  name: "Tom",
  age: 18,
  height: 1.88,
};


// 創建一個proxy代理

                // 參數一:對obj對象進行代理 參數二:捕獲器(有13種捕獲器)
const objProxy = new Proxy(obj, {



    // 獲取值的捕獲器(在獲取值的時候自動回調該函數)
    get:function(target,key){
        // target 是被代理的對象; key
        console.log(target); //{ name: 'Tom', age: 18, height: 1.88 }
        console.log(key); // name 獲取了誰 key就是誰
        return target[key]

    },




    // 設置值的捕獲器(在設置值的時候自動回調該函數)
    set:function(target,key,newValue){
        target[key] = newValue
    },

    // 監聽 in 捕獲器
    has:function(target,key){
        console.log('使用了 in 操作符');
        return key in target
    },    

    // 監聽 delete 捕獲器
    deleteProperty:function(target,key){
        console.log('監聽到屬性被刪除了');
        delete target[key]
    }
}); 
// console.log(objProxy.name); // Kobe
// console.log('name' in objProxy); // true

delete objProxy.name

事件循環#

::: tip
event loop 是一個循環,每當有事件發生時,就會觸發事件循環,事件循環會調用所有的事件處理函數,然後把事件處理函數的執行結果返回給事件循環,事件循環會把返回的結果再次傳遞給事件循環,以此類推,直到沒有事件發生為止。
:::

宏任務#

  • script
  • setTimeout
  • setInterval
  • setImmediate
  • I/O
  • macrotask
  • UI render
  • 瀏覽器的渲染

微任務#

  • microtask
  • task
  • idle
  • promise
  • event loop

事件循環面試題#

    
// await 之後的代碼屬於微任務
// async function a() {
//     console.log('a')
//     await b()
//     console.log('a end')
// }

// async function b() {
//     console.log('b')
// }

// a()

// setTimeout(function () {
//     console.log('setTimeout')
// }, 0)

// new Promise(function (resolve, reject) {
//     console.log('promise')
//     resolve()
// }).then(function () {
//     console.log('then')
// })

// console.log('main end')

// // 
setTimeout(function () {
    console.log('8')
  }, 0) 
  async function async1() {
    console.log('1')
    const data = await async2()
    console.log('6')
    return data
  }
  async function async2() {
     return new Promise(resolve => {
      console.log('2')
      resolve('async2的結果')
    }).then(data => {
      console.log('4')
      return data
    })
  }
  async1().then(data => {
    console.log('7')
    console.log(data)
  })
  new Promise(function (resolve) {
    console.log('3')
    resolve()
  }).then(function () {
    console.log('5')
  })

//   


console.log('script start')
 
async function async1() {
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2 end')
}
async1()
 
setTimeout(function() {
console.log('setTimeout')
}, 0)
 
new Promise(resolve => {
console.log('Promise')
resolve()
})
.then(function() {
console.log('promise1')
})
.then(function() {
console.log('promise2')
})
 
console.log('script end')

// 

// console.log('script start')
 
// async function async1() {
//     await async2()
//     console.log('async1 end')
// }
// async function async2() {
//     console.log('async2 end')
//     return Promise.resolve().then(()=>{
//         console.log('async2 end1')
//     })
// }
// async1()
 
// setTimeout(function() {
//     console.log('setTimeout')
// }, 0)
 
// new Promise(resolve => {
//     console.log('Promise')
//     resolve()
// })
// .then(function() {
//     console.log('promise1')
// })
// .then(function() {
//     console.log('promise2')
// })
 
// console.log('script end')



// async function async1(){
//   await async2()
//   console.log('async1 end')
// }
// async function async2(){} 
// async1();
// new Promise(function(resolve){
//   resolve();
// }).then(function(){
//   console.log('promise2')
// }).then(function() {
//   console.log('promise3')
// }).then(function() {
//   console.log('promise4')
// })
    

生成器#

    
// 生成器函數(*)
function* foo() {
  console.log(1);
  yield;

  console.log(2);
  // yield 可以控制函數停止
  yield;

  console.log(3);
  yield;
  
  console.log(4);
}
// 調用生成器函數該函數不會直接執行,而是返回一個生成器對象
// console.log(foo()); // Object [Generator] {}
const Generator = foo();

// 開始執行第一段代碼(yield之前的代碼)執行next()
Generator.next(); //1

// 開始執行第二段代碼
Generator.next(); //2

// 開始執行第三段代碼
Generator.next(); //3

// 開始執行第四段代碼
Generator.next(); //4

    

事件總線#

    
class EventBus {
  constructor() {
    this.eventBus = {};
  }

  on(eventName, eventCallBack, thisArg) {
    let handlers = this.eventBus[eventName];
    if (!handlers) {
      handlers = [];
      this.eventBus[eventName] = handlers;
    }
    handlers.push({
      eventCallBack,
      thisArg,
    });
  }
  off() {}
  emit(eventName, ...payload) {
    const handlers = this.eventBus[eventName];
    if (!handlers) return;
    handlers.forEach(handler => {
      handler.eventCallBack.apply(handler.thisArg, payload);
    });
  }
}
const eventBus = new EventBus();

// mian.js
eventBus.on(
  'a',
  function (payload) {
    console.log(payload);
  },
  this
);
// utill.js
eventBus.emit('a', { name: 'Tom' });

    

深拷貝#

    
function isObject(value) {
  const valueType = typeof value;
  return (value !== null && valueType === 'object') || valueType === 'function';
}

function deepClone(originValue) {
  // 判斷是否是symbol類型,創建一個新的symbol
  if (typeof originValue === 'symbol') {
    return Symbol(originValue.description);
  }
  if (typeof originValue === 'function') {
    // 判斷是否是函數直接返回
    return originValue;
  }
  if (originValue instanceof Set) {
    return new Set([...originValue]);
  }
  if (originValue instanceof Map) {
      return new Map([...originValue])
  }
  //判斷傳入的origin是否是一個對象類型
  if (!isObject(originValue)) {
    return originValue;
  }
  //判斷傳入的對象是陣列還是對象
  const newObject = Array.isArray(originValue) ? [] : {};
  //遍歷原始對象並將原始對象的屬性值克隆到新對象中
  for (const key in originValue) {
    newObject[key] = deepClone(originValue[key]); //遞歸調用
  }
  const symbolKeys = Object.getOwnPropertySymbols(originValue);
  for (const skey of symbolKeys) {
    newObject[skey] = deepClone(originValue[skey]);
  }
  return newObject;
}
const obj1 = {
  name:'Tom',
  fridends:{
    one:{
      name:'sily'
    },
    tow:{
      name:'kobe'
    }
  }
}
console.log(deepClone(obj1));

    

防抖函數#

    
function debounce(fn, delay) {
  let timer = null;
  return (...args) => {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

// 第一次是否直接執行
function debounce(fn, delay, isImmediately = true) {
  let timer = null;
  let Immediately = isImmediately;
  return (...args) => {
    if (timer) clearTimeout(timer);
    Immediately
      ? fn.apply(this, args)
      : (timer = setTimeout(() => fn.apply(this, args), delay));
    Immediately = !isImmediately;
  };
}

    

節流函數#

    
function throttle(fn, delay) {
  let pre = 0;
  return (...args) => {
    let now = new Date();
    if (now - pre > delay) {
      fn.apply(this, args);
    }
    pre = now;
  };
}

    

Proxy 其他捕獲器#

    
const obj = {
  name: "Tom",
  age: 18,
  height: 1.88,
};



const objProxy = new Proxy(obj, {
    // 獲取值的捕獲器回調
    get:function(target,key){
        console.log(target);
        console.log(key);
        return target[key]

    },
    // 設置值的捕獲器回調
    set:function(target,key,newValue){
        target[key] = newValue
    },

    // 監聽 in 捕獲器
    has:function(target,key){
        console.log('使用了 in 操作符');
        return key in target
    },    

    // 監聽 delete 捕獲器
    deleteProperty:function(target,key){
        console.log('監聽到屬性被刪除了');
        delete target[key]
    }
}); 
// console.log(objProxy.name); // Kobe
// console.log('name' in objProxy); // true

delete objProxy.name

原型#

    
function Fn() {

}
Fn.prototype = {
    name: 'Tom',
    age: 18
}
const p1 = new Fn()
const p2 = new Fn()

console.log(p1.name);
console.log(p2.name);
console.log(p2.toString());
    

陣列去重#

    
const unique = (arr) => {

    if(!Array.isArray(arr)){
       return console.error('參數必須是陣列')
    }

    const temArr = []

    for(let i = 0; i < arr.length; i++){
        if(temArr.indexOf(arr[i]) === -1){
            temArr.push(arr[i])
        }
        // OR
        // if(temArr.includes(arr[i])){
        //     temArr.push(arr[i])
        // }
    }
    return temArr.sort()
}


const result = unique([1,1,1,2,3,2,3,4,5,6,4,2,9,8,7,8,7,6])

console.log(result);

console.log(typeof 3..toString());
// 3 ===> 0000 0011  ===> 0000 1100
console.log(3 << 2);
    
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。