成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Arale源碼解析(1)——Class

_ivan / 1705人閱讀

摘要:先來看源碼中,首先是做的是參數(shù)的處理工作,針對(duì)某些參數(shù)未傳的情況作了調(diào)整,最后達(dá)到的效果是的值為傳入的父類構(gòu)造函數(shù),如果沒有,設(shè)為。下一個(gè)語句其作用是處理父類構(gòu)造函數(shù)沒有修改的屬性值并且有方法的時(shí)候,在上調(diào)用方法。

本文同步自我的GitHub

概述

Arale是支付寶開發(fā)的一套基礎(chǔ)類庫,提供了一整套前端模塊架構(gòu),基于CMD規(guī)范,所有模塊均是以sea.js的標(biāo)準(zhǔn)進(jìn)行開發(fā)。其開發(fā)過程借鑒了優(yōu)秀的開源類庫如jQuery, underscore等的經(jīng)驗(yàn),并融合發(fā)展,最后建立了一套自己的開發(fā)機(jī)制。

結(jié)構(gòu)
Arale
  |--基礎(chǔ)設(shè)施
  |    |-- Base
  |    |-- Class
  |    |-- Events
  |    `-- Widget
  |--工具
  |    |-- Cookie
  |    |-- Detector
  |    |-- Dnd
  |    |-- Easing
  |    |-- Iframe-Shim
  |    |-- Messenger
  |    |-- Name-Storage
  |    |-- Position
  |    |-- Qrcode
  |    |-- Sticky
  |    |-- Templatable
  |    `-- Upload
  `--UI組件
       |-- Autocomplete
       |-- Calendar
       |-- Dialog
       |-- Overlay
       |-- Popup
       |-- Switchable
       |-- Select
       |-- Tip
       `-- Validator
開篇明義

這是本系列的第一篇,對(duì)于Arale中每個(gè)模塊的分析文章將采取同樣的結(jié)構(gòu)。前半部分是帶注釋源碼,在模塊源碼中會(huì)添加盡可能詳細(xì)的注釋。后半部分則是分析,針對(duì)模塊的運(yùn)作方式進(jìn)行具體分析。

帶注釋源碼
// The base Class implementation.
// 基礎(chǔ)Class類的實(shí)現(xiàn),Class類作為返回的對(duì)象,本身也可接受對(duì)象參數(shù)
function Class(o) {
  // Convert existed function to Class.
  // 將現(xiàn)有的函數(shù)轉(zhuǎn)換為Class類
  if (!(this instanceof Class) && isFunction(o)) {
    return classify(o)
  }
}

module.exports = Class


// Create a new Class.
//
//  var SuperPig = Class.create({
//    Extends: Animal,
//    Implements: Flyable,
//    initialize: function() {
//      SuperPig.superclass.initialize.apply(this, arguments)
//    },
//    Statics: {
//      COLOR: "red"
//    }
// })
//
/**
 * 創(chuàng)建Class子類
 * @param  {Function} parent     要繼承的父類的構(gòu)造函數(shù)
 * @param  {Object} properties 包含要混入屬性的對(duì)象
 * @return {Function} 生成子類的構(gòu)造函數(shù)
 */
Class.create = function(parent, properties) {
  // 首先對(duì)第一個(gè)參數(shù)進(jìn)行類型驗(yàn)證,是否為函數(shù)
  if (!isFunction(parent)) {
    // 如不是函數(shù),將值賦給properties,再將parent設(shè)為null
    properties = parent
    parent = null
  }
  // 如properties是undefined或null等為false的值,將properties設(shè)為空對(duì)象
  properties || (properties = {})
  // 如parent為null,且properties有Extends屬性,則將Extends屬性的值賦給parent,
  // 如properties沒有Extends屬性,則將Class賦給parents,以Class為父類
  parent || (parent = properties.Extends || Class)
  // 將parents賦給properties,如原來properties無Extends屬性,此時(shí)其Extends屬性將為父類構(gòu)造函數(shù)或Class
  properties.Extends = parent

  // The created class constructor
  // 用作生成子類的構(gòu)造函數(shù)雛形
  function SubClass() {
    // Call the parent constructor.
    // 在this上調(diào)用父類構(gòu)造函數(shù)
    parent.apply(this, arguments)

    // Only call initialize in self constructor.
    // 當(dāng)this.constructor為SubClass本身(即Parent的構(gòu)造函數(shù)未修改constuctor屬性值),
    // 及父類構(gòu)造函數(shù)中有initialize方法時(shí),在this上調(diào)用自身的initialize方法
    if (this.constructor === SubClass && this.initialize) {
      this.initialize.apply(this, arguments)
    }
  }

  // Inherit class (static) properties from parent.
  // 從parent繼承類的靜態(tài)屬性
  // 判斷parent不是Class
  if (parent !== Class) {
    // 將parent的靜態(tài)屬性混入SubClass中,如果parent有StaticsWhiteList屬性,則復(fù)制其指定的屬性。
    mix(SubClass, parent, parent.StaticsWhiteList)
  }

  // Add instance properties to the subclass.
  // 調(diào)用implement方法,具體操作見implement函數(shù)注釋
  implement.call(SubClass, properties)

  // Make subclass extendable.
  // 最后,對(duì)SubClass構(gòu)造函數(shù)進(jìn)行classify操作,在SubClass上添加extend和implement這兩個(gè)Class類特有的方法,然后返回出去
  return classify(SubClass)
}

/**
 * 使子類混入屬性或調(diào)用一些特殊的方法,這個(gè)方法只有在構(gòu)建SubClass時(shí)的時(shí)候才會(huì)有用,所以沒有掛載到Class上
 * @param  {Object} properties 包含某些屬性的對(duì)象
 */
function implement(properties) {
  var key, value

  // 遍歷properties中的屬性
  for (key in properties) {
    // 暫存properties中屬性對(duì)應(yīng)的屬性值
    value = properties[key]
    // 如果Class類的工具方法中有同名方法,則在this上調(diào)用該方法,暫存的value值作為參數(shù)
    if (Class.Mutators.hasOwnProperty(key)) {
      Class.Mutators[key].call(this, value)
    } else {
      // 如沒有同名方法,則進(jìn)行簡單的賦值操作
      this.prototype[key] = value
    }
  }
}


// Create a sub Class based on `Class`.
// 以Class類或調(diào)用extend方法的類為父類,生成混入properties屬性的子類
Class.extend = function(properties) {
  // 如不存在properties,給properties賦空對(duì)象作為默認(rèn)值
  properties || (properties = {})
  // 將properties的Extends屬性設(shè)為this,表示以this為父類
  properties.Extends = this

  // 調(diào)用create方法返回新的子類
  return Class.create(properties)
}

// 給cls添加`Class.extend`和`implement`方法
function classify(cls) {
  cls.extend = Class.extend
  cls.implement = implement
  return cls
}


// Mutators define special properties.
// Class類自有的一些方法,保存在Class的一些屬性上,子類不會(huì)繼承,只是作為構(gòu)建子類時(shí)的工具函數(shù)使用
Class.Mutators = {
  /**
   * SubClass調(diào)用此方法,在原型上添加父類原型上的方法
   * @param  {Function} parent 要生成子類的父類構(gòu)造函數(shù)
   */
  "Extends": function(parent) {
    // 保存this的原型對(duì)象
    var existed = this.prototype
    // 創(chuàng)建一個(gè)以parent.prototype為原型的空對(duì)象
    var proto = createProto(parent.prototype)

    // Keep existed properties.
    // 在proto這個(gè)空對(duì)象上混入this的原型對(duì)象上的屬性
    mix(proto, existed)

    // Enforce the constructor to be what we expect.
    // proto的constructor指向this,為了構(gòu)造正確的原型鏈
    proto.constructor = this

    // Set the prototype chain to inherit from `parent`.
    // 將proto賦給this的prototype對(duì)象,這樣this的prototype上既有原有的屬性,又有Extend的類的原型對(duì)象上的屬性
    this.prototype = proto

    // Set a convenience property in case the parent"s prototype is
    // needed later.
    // 將父類的prototye保存為this的superclass屬性,可以通過superclass快速訪問
    this.superclass = parent.prototype
  },

  /**
   * 從某些類中混入屬性
   * @param  {Array|Function} items 包含提供屬性的類的數(shù)組
   */
  "Implements": function(items) {
    // 檢測參數(shù)類型,單個(gè)構(gòu)造函數(shù)用數(shù)組包裹
    isArray(items) || (items = [items])
    // 保存子類的原型對(duì)象
    var proto = this.prototype, item

    // 循環(huán)遍歷
    while (item = items.shift()) {
      // 將item原型對(duì)象中的屬性混入子類原型對(duì)象中,如item沒有原型對(duì)象,則item是包含需混入的屬性的對(duì)象,直接mix即可
      mix(proto, item.prototype || item)
    }
  },

  // 將屬性作為靜態(tài)屬性加入子類,這些屬性不會(huì)被繼續(xù)繼承
  "Statics": function(staticProperties) {
    mix(this, staticProperties)
  }
}


// Shared empty constructor function to aid in prototype-chain creation.
// 無constructor的空函數(shù),用于原型鏈的構(gòu)造。
function Ctor() {
}

// See: http://jsperf.com/object-create-vs-new-ctor
// 工具函數(shù),返回一個(gè)以proto為原型的空對(duì)象
var createProto = Object.__proto__ ?
    function(proto) {
      return { __proto__: proto }
    } :
    function(proto) {
      Ctor.prototype = proto
      return new Ctor()
    }


// Helpers
// 工具方法
// ------------

/**
 * 將s中的屬性混入r
 * @param  {Object} r  接受復(fù)制對(duì)象
 * @param  {Object} s  被復(fù)制對(duì)象
 * @param  {Array} wl  白名單,用于特別指定要復(fù)制的屬性
 */
function mix(r, s, wl) {
  // Copy "all" properties including inherited ones.
  // 將s對(duì)象的所有屬性,包括繼承的屬性,全部復(fù)制到新的r對(duì)象中
  for (var p in s) {
    if (s.hasOwnProperty(p)) {
      if (wl && indexOf(wl, p) === -1) continue

      // 在 iPhone 1 代等設(shè)備的 Safari 中,prototype 也會(huì)被枚舉出來,需排除
      if (p !== "prototype") {
        r[p] = s[p]
      }
    }
  }
}

// 對(duì)Object.prototype.toString方法的引用
var toString = Object.prototype.toString

// 檢測是否為數(shù)組方法
var isArray = Array.isArray || function(val) {
    return toString.call(val) === "[object Array]"
}

// 檢測是否為函數(shù)方法
var isFunction = function(val) {
  return toString.call(val) === "[object Function]"
}

// 查詢?cè)卦跀?shù)組中的索引值,如不存在則返回-1
var indexOf = Array.prototype.indexOf ?
    function(arr, item) {
      return arr.indexOf(item)
    } :
    function(arr, item) {
      for (var i = 0, len = arr.length; i < len; i++) {
        if (arr[i] === item) {
          return i
        }
      }
      return -1
    }

分析

Class類是整個(gè)Arale類庫的基礎(chǔ),所有在Arale中使用到的類都是由Class構(gòu)建的,因?yàn)槠錁?gòu)建的所有類都包含特定的方法,有特殊性,是根據(jù)Arale的需要定制的。所有基于Arale的開發(fā)都要遵循Class類的規(guī)定,可以說這個(gè)類是Arale生態(tài)圈的基石。

既然有官方文檔,具體使用方法就不用多說了,下面分析一下具體實(shí)現(xiàn)。

首先介紹一下模塊中的工具函數(shù),分別是:

mix() // 用于混入屬性的方法
toString() // 轉(zhuǎn)換為字符串類型的方法
isArray(), isFunction() 類型檢測方法
indexOf() // 計(jì)算元素在數(shù)組中索引值的方法

具體實(shí)現(xiàn)見源碼及注釋即可。

首先是Class函數(shù),這個(gè)函數(shù)是對(duì)外暴露的,所有方法都可以在它上面調(diào)用??稍贑lass上調(diào)用的方法只有兩個(gè),分別是Class.create()Class.extend()。先來看Class.create()

源碼中,首先是做的是參數(shù)的處理工作,針對(duì)某些參數(shù)未傳的情況作了調(diào)整,最后達(dá)到的效果是parent的值為傳入的父類構(gòu)造函數(shù),如果沒有,設(shè)為null。properties為需要混入屬性的對(duì)象,其中可能有些Arale規(guī)定的特殊的屬性會(huì)進(jìn)行特殊處理,這個(gè)后面會(huì)說。

下面一步,針對(duì)parentnull的情況,parentnull時(shí),如properties中有Entends屬性,則將該屬性值賦給parent,如果沒有Extends,則將Class賦給parent。意思就是,有Extends屬性時(shí),屬性值作為子類的父類,如果沒有,Class作為父類。然后將parent回頭賦給properties.Extends,這是針對(duì)parentClass的情況。

再往后聲明了子類的構(gòu)造函數(shù)雛形——SubClass函數(shù),在函數(shù)內(nèi)首先在this上調(diào)用parent的構(gòu)造函數(shù)。下一個(gè)if語句:

if (this.constructor === SubClass && this.initialize) {
  this.initialize.apply(this, arguments)
}

其作用是處理父類構(gòu)造函數(shù)沒有修改this的constructor屬性值并且有initialize方法的時(shí)候,在this上調(diào)用initialize方法。這個(gè)多數(shù)情況下不會(huì)執(zhí)行。下一步則是在parent不為Class時(shí)執(zhí)行,將parent的靜態(tài)屬性賦給SubClass,可以通過StaticWhiteList參數(shù)特別指定要復(fù)制的屬性。

接下來是關(guān)鍵一步,也是我認(rèn)為整個(gè)Class類中技巧最高的一步。在SubClass上調(diào)用implement方法,該方法中,對(duì)properties進(jìn)行遍歷,將properties中的每個(gè)屬性值和Class.Mutators中的屬性值進(jìn)行對(duì)比,Class.Mutators對(duì)象中保存的都是一些特殊的方法,這些方法可以以屬性的方式寫在properties參數(shù)中,當(dāng)遇到特定名稱的屬性時(shí),就會(huì)在SubClass上調(diào)用Class.Mutators中的同名方法,并且properties中對(duì)應(yīng)的屬性值會(huì)作為該方法的參數(shù)傳入。而不存在于Class.Mutators中的屬性,則會(huì)執(zhí)行一般的賦值操作賦給SubClass。這種方法巧妙地將預(yù)設(shè)的方法和需要混入的屬性通過同一種方式傳入,降低了API的復(fù)雜性,提高了方法的靈活度。同樣的技巧我在糖餅的artDialog源碼中也看到過,不知道是不是受了Arale的啟發(fā)。

最后返回“加工”后的SubClass,當(dāng)然最后執(zhí)行了一個(gè)classify()方法,作用就是在SubClass上加入extendimplement方法,讓子類也可以擁有這些方法。

Class.Mutators中的方法具體實(shí)現(xiàn)就不說了,看注釋即可,反正都是在SubClass上調(diào)用的。

至于Class.extend(每個(gè)子類都有的)方法,最后其實(shí)調(diào)用的還是Class.create,只是對(duì)properties做了一些處理,方便由子類直接調(diào)用再生成子類的一種簡化API,免得再寫一次類似Class.create(SubClass, properties)這么長的語句。

構(gòu)造過程中,對(duì)原型鏈的處理是比較重要的一個(gè)環(huán)節(jié),這是JavaScript的一大特色,注意一下就好。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/85357.html

相關(guān)文章

  • Arale源碼解析(3)——Base模塊和Aspect模塊

    摘要:本文同步自我的博客前言這個(gè)模塊實(shí)際上才是模塊系統(tǒng)中對(duì)外的模塊,它包含了之前介紹的類和類,以及自己內(nèi)部的模塊和模塊,因此模塊是真正的基礎(chǔ)類。這兩個(gè)方法的作用就是針對(duì)類上的某個(gè)方法,給這個(gè)方法綁定先于其執(zhí)行和后于其執(zhí)行的回調(diào)函數(shù)。 本文同步自我的GitHub博客 前言 Base這個(gè)模塊實(shí)際上才是Arale模塊系統(tǒng)中對(duì)外的模塊,它包含了之前介紹的Class類和Events類,以及自己內(nèi)部...

    stdying 評(píng)論0 收藏0
  • arale 源碼class

    摘要:擁有了和方法的三個(gè)變種屬性這三個(gè)屬性會(huì)做特殊處理繼承的方法,只支持單繼承建立原型鏈來實(shí)現(xiàn)繼承強(qiáng)制改變構(gòu)造函數(shù)提供語法糖,來調(diào)用父類屬性混入屬性,可以混入多個(gè)類的屬性將參數(shù)變成數(shù)組無論參數(shù)是類,還是對(duì)象,都混入。 更新:讀 arale 源碼之 attribute 篇 arale 是阿里、開源社區(qū)明星人物--玉伯,開發(fā)的一套組件,代碼相當(dāng)優(yōu)美,大贊玉伯的開源精神,我是您的粉絲。 這里分享下...

    firim 評(píng)論0 收藏0
  • Arale源碼解析(2)——Events

    摘要:帶注釋源碼用于分割事件名的正則,識(shí)別空格介紹使用方法,這個(gè)模塊可以混入任何對(duì)象之中,實(shí)現(xiàn)對(duì)自定義事件的資瓷將空格分割的事件綁定給對(duì)象,事件名為的話,事件回調(diào)函數(shù)在任何事件被觸發(fā)時(shí)都會(huì)調(diào)用。 帶注釋源碼 // Regular expression used to split event strings // 用于分割事件名的正則,識(shí)別空格 var eventSplitter = /s+...

    adie 評(píng)論0 收藏0
  • arale 源碼之 attribute 篇

    摘要:系列文章讀源碼之篇提供基本的屬性添加獲取移除等功能。判斷是否為等對(duì)象特性檢查閉包實(shí)現(xiàn)塊作用域,不污染全局變量。找這個(gè)屬性,若沒有則返回空對(duì)象執(zhí)行函數(shù),返回被修改的值。 系列文章:讀 arale 源碼之 class 篇 attributes 提供基本的屬性添加、獲取、移除等功能。它是與實(shí)例相關(guān)的狀態(tài)信息,可讀可寫,發(fā)生變化時(shí),會(huì)自動(dòng)觸發(fā)相關(guān)事件 先來了解一下 Attribute 模塊要實(shí)...

    Magicer 評(píng)論0 收藏0
  • js 支持 Aspect 切面編程

    摘要:在方法執(zhí)行后,再執(zhí)行函數(shù)函數(shù)在執(zhí)行時(shí),接收的參數(shù)第一個(gè)是的返回值,之后的參數(shù)和傳給相同。的返回值源碼定義兩個(gè)出口定義一個(gè)可柯里化的函數(shù),柯里化成函數(shù)指向基于生成的類的實(shí)例,如上例的如果該函數(shù)是第一次切面化綁定,則包裝該函數(shù)。 系列文章:讀 arale 源碼之 class 篇 使用 Aspect,可以允許你在指定方法執(zhí)行的前后插入特定函數(shù) before object.before(me...

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

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

0條評(píng)論

閱讀需要支付1元查看
<