国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

underscore 誕生記(一)—— 基本結(jié)構(gòu)搭建

xiaolinbang / 2676人閱讀

摘要:簡(jiǎn)介是一款成熟可靠的第三方開源庫,正如統(tǒng)一了不同瀏覽器之間的操作的差異,讓我們可以簡(jiǎn)單地對(duì)進(jìn)行操作,則提供了一套完善的函數(shù)式編程的接口,讓我們更方便地在中實(shí)現(xiàn)函數(shù)式編程。

1. 簡(jiǎn)介

underscore 是一款成熟可靠的第三方開源庫,正如 jQuery 統(tǒng)一了不同瀏覽器之間的 DOM 操作的差異,讓我們可以簡(jiǎn)單地對(duì) DOM 進(jìn)行操作,underscore 則提供了一套完善的函數(shù)式編程的接口,讓我們更方便地在 JavaScript 中實(shí)現(xiàn)函數(shù)式編程。

jQuery 在加載時(shí),會(huì)把自身綁定到唯一的全局變量 $ 上,underscore 與其類似,會(huì)把自身綁定到唯一的全局變量 _ 上,這也是為啥它的名字叫 underscore 的原因。

在搭建 underscore 之前,讓我們先來了解一下什么是 “立即執(zhí)行函數(shù)(IIFE)”.

2. 立即執(zhí)行函數(shù)(IIFE)

立即執(zhí)行函數(shù),顧名思義,就是定義好的匿名函數(shù)立即執(zhí)行,寫法如下:

(function(name) {
  console.log(name);
})("suporka");

其作用是:通過定義一個(gè)匿名函數(shù),創(chuàng)建了一個(gè)新的函數(shù)作用域,相當(dāng)于創(chuàng)建了一個(gè)“私有”的命名空間,該命名空間的變量和方法,不會(huì)破壞污染全局的命名空間。

// 函數(shù)外部拿不到內(nèi)部的變量,因此不會(huì)造成變量污染,內(nèi)部的變量在內(nèi)部使用即可
(function() {
  var name = "suporka";
})();

console.log(name); // name is undefinded
3. 全局變量 _ 的掛載

當(dāng)我們?cè)跒g覽器中使用 _.map([1,2,3], function(item){console.log(item)}) 時(shí), _ 是掛載在 Window對(duì)象上的,如果我們想在 node 環(huán)境中使用呢 ?

(function() {
  // root 為掛載對(duì)象,為 self 或 global 或 this 或 {}
  var root =
    (typeof self == "object" && self.self === self && self) ||
    (typeof global == "object" && global.global === global && global) ||
    this ||
    {};

  // _ 應(yīng)該是一個(gè)對(duì)象,對(duì)象內(nèi)有屬性函數(shù)
  var _ = {};
  root._ = _;
  _.VERSION = "1.9.1"; // 給我們的 underscore 一個(gè)版本號(hào)吧
})();
4. 函數(shù)式風(fēng)格 && 面向?qū)ο箫L(fēng)格的雙重實(shí)現(xiàn)

首先我們實(shí)現(xiàn)一個(gè)倒裝字符串的方法

(function() {
  // root 為掛載對(duì)象,為 self 或 global 或 this 或 {}
  var root =
    (typeof self == "object" && self.self === self && self) ||
    (typeof global == "object" && global.global === global && global) ||
    this ||
    {};

  // _ 應(yīng)該是一個(gè)對(duì)象,對(duì)象內(nèi)有屬性函數(shù)
  var _ = {};

  root._ = _;

  _.VERSION = "1.9.1"; // 給我們的 underscore 一個(gè)版本號(hào)吧

  /**
   * 字符串倒裝
   */
  _.reverse = function(string) {
    return string
      .split("")
      .reverse()
      .join("");
  };
})();

_.reverse("suporka"); // akropus

不錯(cuò),很快實(shí)現(xiàn),但是這種是函數(shù)式寫法,調(diào)用一個(gè)函數(shù)去實(shí)現(xiàn),如果我們要實(shí)現(xiàn)面向?qū)ο髮懛兀咳?_("suporka").reverse()! underscore 是支持這種寫法的,仔細(xì)觀察 _("suporka") , 你會(huì)發(fā)現(xiàn),_ 是一個(gè)函數(shù)啊,和我們前面定義的 var _ = {}; 不一致,那么該怎么實(shí)現(xiàn)呢?

實(shí)例原型

我們先測(cè)試一下:如果 _ 為函數(shù),我們需要保存其傳進(jìn)來的參數(shù) obj . new _() 生成一個(gè)實(shí)例原型對(duì)象

function _(obj) {
  this._wrapped = obj;
}
_.reverse = function(string) {
  return string
    .split("")
    .reverse()
    .join("");
};
_.reverse("suporka"); // "akropus", 函數(shù)式調(diào)用沒問題

new _("suporka");

從圖中我們可以看出,實(shí)例原型對(duì)象的 __proto__ (原型)的 constructor 構(gòu)造函數(shù)指回了原來的 _(obj) 函數(shù),要調(diào)用其 reverse() 方法只能 new _("suporka").constructor.reverse()多了一個(gè)層級(jí),不符合我們?cè)镜钠谕D俏覀儾蝗缭?b>_proto_ 屬性下增加一個(gè)和 reverse 一樣的函數(shù),這樣不就可以直接調(diào)用了嗎?

let us try it !

function _(obj) {
  this._wrapped = obj;
}
_.reverse = function(string) {
  return string
    .split("")
    .reverse()
    .join("");
};
_.reverse("suporka"); // "akropus", 函數(shù)式調(diào)用沒問題

_.prototype.reverse = function() {
  return this._wrapped
    .split("")
    .reverse()
    .join("");
};
new _("suporka").reverse(); // "akropus", 面向?qū)ο笫秸{(diào)用沒問題
5. 改造 _() function

new _("suporka").reverse() 有點(diǎn)累贅,去掉 new, 重寫 function _()

var _ = function(obj) {
  // 如果傳入的是實(shí)例后對(duì)象,返回它
  if (obj instanceof _) return obj;
  // 如果還沒有實(shí)例化,new _(obj)
  if (!(this instanceof _)) return new _(obj);
  this._wrapped = obj;
};

_("suporka").reverse(); // "akropus", 面向?qū)ο笫秸{(diào)用沒問題
6. 寫一個(gè)迭代函數(shù) map()
/**
 * 數(shù)組或?qū)ο蟊闅v方法,并返回修改后的對(duì)象或數(shù)組
 * @param iteratee 回調(diào)函數(shù)
 * @param context 回調(diào)函數(shù)中this的指向
 */
_.map = function(obj, iteratee, context) {
  var length = obj.length,
    results = Array(length);
  for (var index = 0; index < length; index++) {
    results[index] = iteratee.call(context, obj[index], index, obj);
  }

  return results;
};

_.prototype.map = function(iteratee, context) {
  var length = this._wrapped.length,
    results = Array(length);
  for (var index = 0; index < length; index++) {
    results[index] = iteratee.call(
      context,
      this._wrapped[index],
      index,
      this._wrapped
    );
  }

  return results;
};

_([1, 2, 3]).map(
  function(item) {
    console.log(item + this.value);
  },
  { value: 1 }
); // 2,3,4
_.map(
  [1, 2, 3],
  function(item) {
    console.log(item + this.value);
  },
  { value: 1 }
); // 2,3,4

嗯嗯,真好,完美實(shí)現(xiàn)。到這里你會(huì)發(fā)現(xiàn)一個(gè)問題,每次我新增一個(gè)方法,都得在 prototype 上同時(shí)寫多一次這個(gè)相似函數(shù),你會(huì)發(fā)現(xiàn)兩者之間只是 obj 換成了 this._wrapped.有沒有辦法讓它自動(dòng)生成呢?答案肯定是有!

7. 自動(dòng)創(chuàng)建原型方法

在這之前,我們需要先實(shí)現(xiàn)一個(gè)遍歷方法 each(),如下:

// 最大數(shù)值
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
// 判斷是否為數(shù)組
var isArrayLike = function(collection) {
  var length = collection.length;
  return typeof length == "number" && length >= 0 && length <= MAX_ARRAY_INDEX;
};

/**
 * 數(shù)組或?qū)ο蟊闅v方法
 */
_.each = function(obj, callback) {
  var length,
    i = 0;

  if (isArrayLike(obj)) {
    // 數(shù)組
    length = obj.length;
    for (; i < length; i++) {
      //   這里隱式的調(diào)用了一次 callback.call(obj[i], obj[i], i);
      if (callback.call(obj[i], obj[i], i) === false) {
        break;
      }
    }
  } else {
    // 對(duì)象
    for (i in obj) {
      if (callback.call(obj[i], obj[i], i) === false) {
        break;
      }
    }
  }

  return obj;
};

用 each() 來遍歷 _ 上掛載的所有方法函數(shù),并給 prototype 創(chuàng)建相應(yīng)的方法函數(shù)。那么,在此之前,我們需要知道 _ 上掛載了哪些方法名,來寫個(gè) functions() 實(shí)現(xiàn)它

/**
 * 判斷是否為 function
 */
_.isFunction = function(obj) {
  return typeof obj == "function" || false;
};

/**
 * 獲取_的所有屬性函數(shù)名
 */
_.functions = function(obj) {
  var names = [];
  for (var key in obj) {
    if (_.isFunction(obj[key])) names.push(key);
  }
  return names.sort();
};

用 each()實(shí)現(xiàn)它:

var ArrayProto = Array.prototype;
var push = ArrayProto.push;
_.each(_.functions(_), function(name) {
  var func = _[name];
  _.prototype[name] = function() {
    var args = [this._wrapped];
    // args = [this._wrapped, arguments[0], arguments[1]...], 相當(dāng)于用 this._wrapped 代替 obj 實(shí)現(xiàn)
    push.apply(args, arguments);
    return func.apply(_, args);
  };
});
7. 當(dāng)前最終代碼
(function() {
  // root 為掛載對(duì)象,為 self 或 global 或 this 或 {}
  var root =
    (typeof self == "object" && self.self === self && self) ||
    (typeof global == "object" && global.global === global && global) ||
    this ||
    {};

  var _ = function(obj) {
    // 如果傳入的是實(shí)例后對(duì)象,返回它
    if (obj instanceof _) return obj;
    // 如果還沒有實(shí)例化,new _(obj)
    if (!(this instanceof _)) return new _(obj);
    this._wrapped = obj;
  };

  // 最大數(shù)值
  var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
  var ArrayProto = Array.prototype;
  var push = ArrayProto.push;
  // 判斷是否為數(shù)組
  var isArrayLike = function(collection) {
    var length = collection.length;
    return (
      typeof length == "number" && length >= 0 && length <= MAX_ARRAY_INDEX
    );
  };

  root._ = _;

  _.VERSION = "1.9.1"; // 給我們的 underscore 一個(gè)版本號(hào)吧

  /**
   * 字符串倒裝
   */
  _.reverse = function(string) {
    return string
      .split("")
      .reverse()
      .join("");
  };
  /**
   * 判斷是否為 function
   */
  _.isFunction = function(obj) {
    return typeof obj == "function" || false;
  };

  /**
   * 獲取_的所有屬性函數(shù)名
   */
  _.functions = function(obj) {
    var names = [];
    for (var key in obj) {
      if (_.isFunction(obj[key])) names.push(key);
    }
    return names.sort();
  };
  /**
   * 數(shù)組或?qū)ο蟊闅v方法,并返回修改后的對(duì)象或數(shù)組
   * @param iteratee 回調(diào)函數(shù)
   * @param context 回調(diào)函數(shù)中this的指向
   */
  _.map = function(obj, iteratee, context) {
    var length = obj.length,
      results = Array(length);
    for (var index = 0; index < length; index++) {
      results[index] = iteratee.call(context, obj[index], index, obj);
    }

    return results;
  };

  /**
   * 數(shù)組或?qū)ο蟊闅v方法
   */
  _.each = function(obj, callback) {
    var length,
      i = 0;

    if (isArrayLike(obj)) {
      // 數(shù)組
      length = obj.length;
      for (; i < length; i++) {
        //   這里隱式的調(diào)用了一次 callback.call(obj[i], obj[i], i);
        if (callback.call(obj[i], obj[i], i) === false) {
          break;
        }
      }
    } else {
      // 對(duì)象
      for (i in obj) {
        if (callback.call(obj[i], obj[i], i) === false) {
          break;
        }
      }
    }

    return obj;
  };

  _.each(_.functions(_), function(name) {
    var func = _[name];
    _.prototype[name] = function() {
      var args = [this._wrapped];
      // args = [this._wrapped, arguments[0], arguments[1]...], 相當(dāng)于用 this._wrapped 代替 obj 實(shí)現(xiàn)
      push.apply(args, arguments);
      return func.apply(_, args);
    };
  });
})();
未完待續(xù),靜待下篇

前端進(jìn)階小書(advanced_front_end)

前端每日一題(daily-question)

webpack4 搭建 Vue 應(yīng)用(createVue)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/103887.html

相關(guān)文章

  • underscore 誕生(二)—— 鏈?zhǔn)秸{(diào)用與混入(mixin)

    摘要:上篇文章講述了的基本結(jié)構(gòu)搭建,本文繼續(xù)講鏈?zhǔn)秸{(diào)用與混入。獲得一個(gè)經(jīng)包裹后的實(shí)例標(biāo)識(shí)當(dāng)前實(shí)例支持鏈?zhǔn)秸{(diào)用小試牛刀返回的為一個(gè)實(shí)例對(duì)象,后面的方法判斷屬性是否為為的話再調(diào)用一次方法再返回原來實(shí)例即可。 showImg(https://segmentfault.com/img/bVbrSwH?w=1374&h=773); 上篇文章講述了 underscore 的基本結(jié)構(gòu)搭建,本文繼續(xù)講鏈?zhǔn)秸{(diào)...

    yck 評(píng)論0 收藏0
  • 采用vue+webpack構(gòu)建的單頁應(yīng)用——私人博客MintloG誕生

    摘要:我采用原生編寫后臺(tái),因?yàn)楦杏X增刪改查的功能很簡(jiǎn)單,就懶得用框架了其實(shí)是不會(huì)。瀏覽模式它也有一個(gè),用來切換文章列表和文章詳情,也就是和編輯模式它加載了作為工具欄,然后可以進(jìn)行文章的撰寫與修改。 介紹 項(xiàng)目地址:https://github.com/jrainlau/MintloG (特別亂,參考就好-_-|||)showImg(https://segmentfault.com/img/b...

    Terry_Tai 評(píng)論0 收藏0
  • 即將立秋的《課多周刊》(第2期)

    摘要:即將立秋的課多周刊第期我們的微信公眾號(hào),更多精彩內(nèi)容皆在微信公眾號(hào),歡迎關(guān)注。若有幫助,請(qǐng)把課多周刊推薦給你的朋友,你的支持是我們最大的動(dòng)力。課多周刊機(jī)器人運(yùn)營中心是如何玩轉(zhuǎn)起來的分享課多周刊是如何運(yùn)營并堅(jiān)持下來的。 即將立秋的《課多周刊》(第2期) 我們的微信公眾號(hào):fed-talk,更多精彩內(nèi)容皆在微信公眾號(hào),歡迎關(guān)注。 若有幫助,請(qǐng)把 課多周刊 推薦給你的朋友,你的支持是我們最大...

    ruicbAndroid 評(píng)論0 收藏0
  • 即將立秋的《課多周刊》(第2期)

    摘要:即將立秋的課多周刊第期我們的微信公眾號(hào),更多精彩內(nèi)容皆在微信公眾號(hào),歡迎關(guān)注。若有幫助,請(qǐng)把課多周刊推薦給你的朋友,你的支持是我們最大的動(dòng)力。課多周刊機(jī)器人運(yùn)營中心是如何玩轉(zhuǎn)起來的分享課多周刊是如何運(yùn)營并堅(jiān)持下來的。 即將立秋的《課多周刊》(第2期) 我們的微信公眾號(hào):fed-talk,更多精彩內(nèi)容皆在微信公眾號(hào),歡迎關(guān)注。 若有幫助,請(qǐng)把 課多周刊 推薦給你的朋友,你的支持是我們最大...

    MRZYD 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<