前端知識(shí)海底撈之JS

AMD CMD CommonJS

/* AMD是RequireJS對模塊化的定義
 * CMD是seaJS對模塊化的定義
 * CommonJS是Node對模塊化的規(guī)范
 **/

/* AMD 依賴關(guān)系前置 */
define(['./a', './b'], function (a, b) {
    a.something();
    b.something();
})

/* CMD 按需加載,依賴就近 */
define(function (require, exports, module) {
    var a = require('./a');
    a.something();

    var b = require('./b');
    b.something();
})

阻止默認(rèn)行為和阻止冒泡

function stopDefault( e ) {
    // 阻止默認(rèn)瀏覽器動(dòng)作(W3C)
    if ( e && e.preventDefault ) {
        e.preventDefault();
    } else {
        // IE中阻止函數(shù)器默認(rèn)動(dòng)作的方式
        window.event.returnValue = false;
    }
    return false;
}

function stopBubble(e) {
    // 如果提供了事件對象,則這是一個(gè)非IE瀏覽器
    if ( e && e.stopPropagation ) {
        // 因此它支持W3C的stopPropagation()方法
        e.stopPropagation();
    } else {
        // 否則,我們需要使用IE的方式來取消事件冒泡
        window.event.cancelBubble = true;
    }
}

JS數(shù)組

slice實(shí)現(xiàn)淺拷貝
var arr = ['old', 1, true, null, undefined];

var new_arr = arr.slice();

new_arr[0] = 'new';

console.log(arr) // ["old", 1, true, null, undefined]
console.log(new_arr) // ["new", 1, true, null, undefined]
concat實(shí)現(xiàn)淺拷貝
var arr = ['old', 1, true, null, undefined];

var new_arr = arr.concat();

new_arr[0] = 'new';

console.log(arr) // ["old", 1, true, null, undefined]
console.log(new_arr) // ["new", 1, true, null, undefined]

以上兩種方法只是淺拷貝,如果數(shù)組元素是基本類型,就會(huì)拷貝一份新的;但是如果數(shù)組元素是對象或者數(shù)組,就只會(huì)拷貝引用(類似指針),修改其中一個(gè)就會(huì)影響另外一個(gè)。

var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}];

var new_arr = arr.concat();

new_arr[0] = 'new';
new_arr[3][0] = 'new1';

console.log(arr) // ["old", 1, true, ['new1', 'old2'], {old: 1}]
console.log(new_arr) // ["new", 1, true, ['new1', 'old2'], {old: 1}]
JSON.stringify 實(shí)現(xiàn)數(shù)組深拷貝
var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}];

var new_arr = JSON.parse(JSON.stringify(arr));

new_arr[0] = 'new';
new_arr[3][0] = 'new1';

console.log(arr) // ["old", 1, true, ['old1', 'old2'], {old: 1}]
console.log(new_arr) // ["new", 1, true, ['new1', 'old2'], {old: 1}]
手動(dòng)實(shí)現(xiàn)深淺拷貝
/*淺拷貝*/
var shallowCopy = function (obj) {
    // 判斷是否是數(shù)組或者對象
    if (typeof obj !== 'object') {
        return
    }
    var newObj = obj instanceof Array ? [] : {};
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = obj[key];
        }
    }
    return newObj;
}

/*深拷貝*/
var deepCopy = function (obj) {
    if (typeof obj !== 'object') {
        return
    }
    var newObj = obj instanceof Array ? [] : {};
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
        }
    }
    return newObj
}
數(shù)組去重
/* filter + indexOf */
function unique (arr) {
    var res = arr.filter(function (item, index, array) {
        return array.indexOf(item) === index;
    })
    return res;
}

/* ES6 */
function unique (arr) {
    return [... new Set(arr)];
}
打亂數(shù)組的方法
var arr = [];
for (var i = 0; i < 100; i++) {
    arr[i] = i;
}

arr.sort(function () {
    return 0.5 - Math.random();
});
數(shù)組扁平化
  let arr = [1, [2, [3, 4]]];

  function flatten(arr) {
    while (arr.some(item => Array.isArray(item))) {
      arr = [].concat(...arr);
    }
    return arr;
  }

  console.log(flatten(arr))

柯里化

執(zhí)行add(1,2,3)(2)()就能輸出1+2+3+2=8。函數(shù)柯里化

const adder = function () {
    let _args = []; // 閉包保留了對 _args 的引用
    return function () {
      console.log(arguments)
      if (arguments.length === 0) {
        return _args.reduce(function (a, b) {
          return a + b;
        });
      }
      [].push.apply(_args, arguments);
      return arguments.callee;
    }
  };
  const sum = adder();

  console.log(sum);     // Function

  sum(100, 200)(300);    // 調(diào)用形式靈活,一次調(diào)用可輸入一個(gè)或者多個(gè)參數(shù),并且支持鏈?zhǔn)秸{(diào)用
  sum(400);
  console.log(sum());   // 1000 (加總計(jì)算)

異步函數(shù)

async關(guān)鍵詞定義的函數(shù)聲明了一個(gè)可以異步執(zhí)行的函數(shù),返回一個(gè)AsyncFunction類型的對象。淺談Async/Await

async

async—聲明一個(gè)異步函數(shù) (async function someName() {...})

  • 自動(dòng)將常規(guī)函數(shù)轉(zhuǎn)換成Promise,返回值也是一個(gè) Promise 對象;
  • 只有async 函數(shù)內(nèi)部的異步操作執(zhí)行完,才會(huì)執(zhí)行 then方法指定的回調(diào)函數(shù);
  • 異步函數(shù)內(nèi)部可以使用await。
await

await—暫停異步的功能執(zhí)行(var result = await someAsyncCall() {...})

  • 放置在Promise調(diào)用之前,await強(qiáng)制其他代碼等待,直到Promise完成并返回結(jié)果;
  • 只能與Promise 一起使用,不適用與回調(diào);
  • 只能在async函數(shù)內(nèi)部使用。
function fetchTextByPromise () {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve('es8');
      }, 2000);
    });
  }

  async function sayHello () {
    const externalFetchedText = await fetchTextByPromise();
    console.log(`Hello, ${externalFetchedText}`);
  }
  sayHello();

bind,call,apply

call

call()方法調(diào)用一個(gè)函數(shù), 其具有一個(gè)指定的this值和分別地提供的參數(shù)(參數(shù)的列表)。

thisArg
  • fun函數(shù)運(yùn)行時(shí)指定的this值。需要注意的是,指定的this值并不一定是該函數(shù)執(zhí)行時(shí)真正的this值;
  • 如果這個(gè)函數(shù)處于非嚴(yán)格模式下,則指定為nullundefinedthis值會(huì)自動(dòng)指向全局對象(瀏覽器中就是window對象);
  • 值為原始值(數(shù)字,字符串,布爾值)的this會(huì)指向該原始值的自動(dòng)包裝對象。
arg1, arg2, ...
  • 指定的參數(shù)列表。
 var foo = {
    value: 'fooValue'
  }

  function bar() {
    var value = 'barValue'
    console.log(this.value)
  }

  bar.call(foo) // 'fooValue'
call的polyfill
  • 將函數(shù)設(shè)為對象的屬性
  • 執(zhí)行該函數(shù)
  • 刪除該函數(shù)
 /*
  * 將函數(shù)設(shè)為對象的屬性 foo.bar
  * 執(zhí)行該函數(shù) foo.bar()
  * 刪除該函數(shù) delete foo.bar
  **/

  Function.prototype.myCall = function (con) {
    var context = con || window
    var args = []
    for (var i = 1, len = arguments.length; i < len; i++) {
      args.push('arguments[' + i + ']')
    }
    context.fn = this
    var result = eval('context.fn(' + args + ')')
    delete  context.fn
    return result
  }
apply

call()方法的作用和 apply() 方法類似,區(qū)別就是call()方法接受的是參數(shù)列表,而apply()方法接受的是一個(gè)參數(shù)數(shù)組。

apply的polyfill
  Function.prototype.myApply = function (con, arr) {
    var context = con || window
    context.fn = this
    var result
    if (!arr) {
      result = context.fn()
    } else {
      var args = []
      for (var i = 0; i < arr.length; i++) {
        args.push(arr[i])
      }
      result = eval('context.fn(' + args + ')')
    }
    delete context.fn
    return result
  }
bind
fun.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg
  • 調(diào)用綁定函數(shù)時(shí)作為this參數(shù)傳遞給目標(biāo)函數(shù)的值。 如果使用newnew運(yùn)算符創(chuàng)建一個(gè)用戶定義的對象類型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對象的實(shí)例。運(yùn)算符構(gòu)造綁定函數(shù),則忽略該值。
  • 當(dāng)使用bindsetTimeout中創(chuàng)建一個(gè)函數(shù)(作為回調(diào)提供)時(shí),作為thisArg傳遞的任何原始值都將轉(zhuǎn)換為object。
  • 如果沒有提供綁定的參數(shù),則執(zhí)行作用域的this被視為新函數(shù)的thisArg
arg1, arg2, ...

當(dāng)綁定函數(shù)被調(diào)用時(shí),這些參數(shù)將置于實(shí)參之前傳遞給被綁定的方法。

bind的polyfill
 Function.prototype.myBind = function (context) {

    if (typeof this !== "function") {
      throw new Error("Function.prototype.bind - what is trying to be bound is not callable")
    }

    var self = this
    var args = Array.prototype.slice.call(arguments, 1)

    var fNOP = function () {}

    var fBound = function () {
      var bindArgs = Array.prototype.slice.call(arguments)
      self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs))
    }

    fNOP.prototype = this.prototype
    fBound.prototype = new fNOP()
    return fBound
  }

詳解:JavaScript 之 call和apply,bind 的模擬實(shí)現(xiàn)

new

  • 新生成了一個(gè)對象;
  • 鏈接到原型;
  • 綁定this;
  • 返回新對象。
new的polyfill
function objectFactory() {
    var obj = new Object()
    var constructor = [].shift.call(arguments)
    obj.__proto__ = constructor.prototype
    console.log(obj)
    var result = constructor.apply(obj, arguments)
    console.log(result)
    return typeof result === 'object' ? result : obj
    // 判斷返回的值是不是一個(gè)對象,如果是一個(gè)對象,我們就返回這個(gè)對象,如果不是,我們該返回什么就返回什么。  
}

instanceof

instanceof可以正確的判斷對象的類型,因?yàn)閮?nèi)部機(jī)制是通過判斷對象的原型鏈中是不是能找到類型的 prototype。

instanceof的polyfill
  function myInstanceOf(left, right) {
    // 獲得類型的原型
    var prototype = right.prototype
    // 獲得對象的原型
    left = left.__proto__
    // 判斷對象的類型是否等于類型的原型
    while (true) {
      if (left === null)
        return false
      if (prototype === left)
        return true
      left = left.__proto__
    }
  }

檢驗(yàn)類型的方法

千萬不要使用typeof來判斷對象和數(shù)組,因?yàn)檫@種類型都會(huì)返回object。

  • typeof:是判斷基本類型的Boolean,Number,symbol,undefined,StringSymbol。對于引用類型:除function,都返回objectnull返回object。
  • instanceof:用來判斷A是否是B的實(shí)例,instanceof檢查的是原型。
  • toString:是Object的原型方法,對于Object對象,直接調(diào)用toString() 就能返回[Object Object] 。而對于其他對象,則需要通過call /apply來調(diào)用才能返回正確的類型。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文為阮一峰大神的《ECMAScript 6 入門》的個(gè)人版提純! babel babel負(fù)責(zé)將JS高級語法轉(zhuǎn)義,...
    Devildi已被占用閱讀 2,148評論 0 4
  • CSS 選擇器的分類 不同級別:總結(jié)排序:!important > 行內(nèi)樣式 > ID選擇器 > 類選擇器 > 標(biāo)...
    小小的白菜閱讀 615評論 0 7
  • 1 凌晨一點(diǎn),我還沒睡沉,小家伙突然“哇哇”大哭起來。我心一緊,匆忙起身,開燈。 寶寶哭的異常的慘烈,閉著眼睛,兩...
    YIBAO閱讀 863評論 8 4
  • 小怪在路上閱讀 325評論 3 2
  • 隨手拈來的文字我沒有,走心的隨筆卻成了我的偏愛。 偶遇長沙的初雪,兜轉(zhuǎn)讀研的生活。前兩天剛剛結(jié)束了第一學(xué)期的課程,...
    岔子小姐閱讀 239評論 0 0

友情鏈接更多精彩內(nèi)容