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

資訊專欄INFORMATION COLUMN

讀 arale 源碼之 attribute 篇

Magicer / 2786人閱讀

摘要:系列文章讀源碼之篇提供基本的屬性添加獲取移除等功能。判斷是否為等對象特性檢查閉包實現塊作用域,不污染全局變量。找這個屬性,若沒有則返回空對象執行函數,返回被修改的值。

系列文章:讀 arale 源碼之 class 篇

attributes 提供基本的屬性添加、獲取、移除等功能。它是與實例相關的狀態信息,可讀可寫,發生變化時,會自動觸發相關事件

先來了解一下 Attribute 模塊要實現的功能:

設置屬性值

{
  attr1: "hello1",

  // 相當于 attr1 的方式
  attr2: {
    value: "hello2"
  }
}

在屬性設置和獲取前,觸發一個函數來先處理屬性

{
  attr3: {
    value: "hello3",
    setter: function(v) {
      return v + "";
    },
    getter: function(v) {
      return v * 6;
    }
  }
}

只讀屬性

{
  attr4: {
    value: 1,
    readOnly: true
  }
}

屬性發生改變時自動觸發相關事件

{
  _onChangeAttr1: function(val) {
    console.log("attr1 changed by" + val);
  }
}

設置屬性時,多了兩個狀態

// {silent: true} 綁定的 _onChangeAttr1 不執行
instance.set("attr1", 2, {silent: true});

// {override: true} 默認 false,對象混合,為 true 時,直接覆蓋對象。
instance.set("attr2", {w: 12, h: 33}, {override: true});

接下來再去看看源碼怎么實現的!

initAttrs 初始化屬性

initAttrs 將在實例化對象時調用。

exports.initAttrs = function(config) {
  // initAttrs 是在初始化時調用的,默認情況下實例上肯定沒有 attrs,不存在覆蓋問題
  var attrs = this.attrs = {};
  // 得到所有繼承的屬性
  var specialProps = this.propsInAttrs || [];
  // 合并和克隆父類的 attrs 值到實例的 attrs 上
  mergeInheritedAttrs(attrs, this, specialProps);
  // 從 config 中合并屬性
  if (config) {
    mergeInheritedAttrs(atts, config);
  }
  // 對于有 setter 的屬性,要用初始值 set 一下,以保證關聯屬性也一同初始化
  setSetterAttrs(this, attrs, config);
  // Convert `on/before/afterXxx` config to event handler.
  parseEventsFromAttrs(this, attrs);
  // 將 this.attrs 上的 special properties 放回 this 上
  copySpecialProps(specialProps, this, attrs, true);
}
來看看 initAttrs 中用到的幾個方法
1. merge 合并屬性
function merge(receiver, supplier) {
  var key, value;
  for (key in supplier) {
    if (supplier.hasOwnPrototype(key)) {
      value = supplier[key];
      // 只 clone 數組和 簡單對象,其他保持不變
      if (isArray(value)) {
        // 重新返回一個數組,不會占用同一個內存地址
        value = value.slice();
      } else if (isPlainObject(value)) {
        // 接收者合并之前的值不是簡單對象的話,將其設置為空對象,即覆蓋之前的值。
        var prev = receiver[key];
        isPlainObject(prev) || (prev = {});
        // 如果是簡單對象的話,混合他們的值
        value = merge(prev, value);
      }
      receiver[key] = value;
    }
  }
  return receiver;
}
1.1 isPlainObject 判斷是否為簡單對象
// 什么是簡單對象? 使用 {} 或者 new Object 創建。for-in 遍歷時只包含自身屬性的對象。
function isPlainObject(o) {
  // 首先必須是對象,然后要排除 DOM 對象和 Window 對象
  if (!o || toString.call(o) != "[object Object]" || o.nodeType || isWindow(o)) {
    return false;
  }
  try {
    // Object 沒有屬于自己的 constructor
    if (o.constructor && !hasOwn.call(o, "constructor") && !hasOwn.call(o.constructor.prototype, "isPrototypeOf")) {
      return false;
    }
  } catch (e) {
    // IE8,9 會拋出異常
    return false;
  }

  var key;

  // 如果是 IE9 以下. iteratesOwnLast 是特性檢查。
  if (iteratesOwnLast) {
    // ie9 以下,遍歷時不會優先遍歷自身屬性,如果第一個屬性是自身的,說明所有屬性都是自身的。
    for (key in o) {
     return hasOwn.call(o, key);
    }
  }

  // 自身屬性會優先遍歷,然后才是原型鏈上的,如果最后一個屬性都是自身的,說明所有屬性都是自身的。
  for (key in o) {}
  // 除了 IE9 以下的瀏覽器,其它瀏覽器都不允許修改 undefined 關鍵字,所以這樣直接用也沒問題。
  return key === undefined || hasOwn.call(o, key);
}

// 判斷是否為 window top self 等對象
function isWindow(o) {
  return o != null && o == o.window;
}

// ie < 9 特性檢查, 閉包實現塊作用域,不污染全局變量。
(function() {
  var props = [];
  function Ctor() {
    this.x = 1;
  }
  Ctor.prototype = {
    valueOf: 1,
    y: 1
  }
  for (var prop in new Ctor) {
    props push(prop);
  }
  iteratesOwnLast = props[0] !== "x";
})();
2. copySpecialProps
/*
 * supplier: 提供者; receiver: 接收者; specialProps: 指定提供者身上的屬性,相當于白名單
 */
function copySpecialProps(specialProps, receiver, supplier, isAttr2Prop) {
  for (var i = 0, len = specialProps.length; i < len; i++) {
    var key = specialProps[i];
    if (supplier.hasOwnPrototype(key)) {
      receiver[key] = isAttr2Prop ? receiver.get(key) : supplier[key];
    }
  }
}
3. mergeInheritedAttrs 遍歷原型鏈,將繼承的 attrs 上定義的屬性,合并到 this.attrs 上,方便后續處理這些屬性。
// 遍歷實例的原型鏈,將 attrs 屬性合并
function mergeInheritedAttrs(attrs, instance, specialProps) {
  var inherited = [];
  var proto = instance.constructor.prototype;
  // 遍歷實例的原型鏈, 查找 attrs 屬性。并將其添加到 inherited 數組中。
  while (proto) {
    // 原型鏈上若是沒有 attrs 屬性的話,將其設為空對象
    if (!proto.hasOwnPrototype("attrs")) {
      proto.attrs = {};
    }
    // 將 proto 上的特殊 properties 放到 proto.attrs 上,以便合并
    copySpecialProps(specialProps, proto.attrs, proto);
    // 為空時不添加
    if (!isEmptyObject(proto.attrs)) {
      // 將 proto.attrs 添加到 inherited 數組中,從頭部放。類似 stack(棧)的結構,后進先出
      inherited.unshift(proto.attrs);
    }
    // 繼續查找原型鏈,直至 Class.superclass 時,為 undefined 值終止循環
    proto = proto.constructor.superclass;
  }

  // 合并和克隆繼承的值到實例上
  for (var i = 0, len = inherited.length; i < len; i++) {
    merge(attrs, normalize(inherited[i]));
  }
}
4. setSetterAttrs

對于有 setter 的屬性,要用初始值 set 一下,以保證關聯屬性也一同初始化

function setSetterAttrs(host, attrs, config) {
  var options = {
    silent: true
  };
  host.__initializeingAttrs = true;
  for (var key in config) {
    if (config.hasOwnPrototype(key)) {
      if (attrs[key].setter) {
        // 如果屬性有 setter (繼承的也可以),那么用初始值設置一下。
        host.set(key, config[key], options);
      }
    }
  }
  delete host.__initializingAttrs;
}
5. parseEventsFromAttrs 解析 attrs 上的事件

綁定 on|before|after 事件

var EVENT_PATTERN = /^(on|before|after)([A-Z].*)$/;
var EVENT_NAME_PATTERN = /^(Change)?([A-Z])(.*)/;
function parseEventsFromAttrs(host, attrs) {
  for (var key in attrs) {
    if (attrs.hasOwnPrototype(key)) {
      var value = attrs[key].value, m;
      if (isFunction(value) && (m = key.match(EVENT_PATTERN))) {
        host[m[1]](getEventName(m[2]), value);
        delete attrs[key];
      }
    }
  }
}

// 將 Show 變成 show ,ChangeTitle 變成 change:title
function getEventName(name) {
  var m = name.match(EVENT_NAME_PATTERN);
  var ret = m[1] ? "change:" : "";
  ret += m[2].toLowerCase() + m[3];
  return ret;
}
get 獲取屬性的值

配置 getter 的話,調用 getter。

exports.get = function(key) {
  var attr = this.attrs[key] || {};
  var val = attr.value;
  return attr.getter ? attr.getter.call(this, val, key) : val;
}
set 設置屬性的值

并且觸發 change 綁定事件,除非 silent 為 true

exports.set = function(key, val, options) {
  var attrs = {};
  // 像這樣調用 set("key", val, options)
  if (isString(key)) {
    attrs[key] = val;

  // 像這樣調用 set({key: val}, options)
  } else {
    attrs = key;
    options = val;
  }

  options || (options = {});
  var silent = options.silent;
  var override = options.override;
  // 全局的 attrs 變量用局部變量 now 調用
  var now = this.attrs;
  // 全局的 __changedAttrs 變量用局部變量 changed 來使用。
  var changed = this.__changedAttrs || (this.__changedAttrs = {});
  for (key in attrs) {
    if (!attrs.hasOwnPrototype(key)) continue;
    // 找這個屬性,若沒有則返回空對象
    var attr = now[key] || (now[key] = {});
    val = attrs[key];
    if (attr.readOnly) {
      throw new Error("This attribute is readOnly:" + key);
    }
    // 執行 setter 函數,返回被修改的值。
    if (attr.setter) {
      val = attr.setter.call(this, val, key);
    }
    // 獲取設置前的 prev 值
    var prev = this.get(key);
    // 如果設置了 override 為 true,表示要強制覆蓋,就不去 merge 了
    // 都為對象時,做 merge 操作,以保留 prev 上沒有覆蓋的值
    if (!override && isPlainObject(prev) && isPlainObject(val)) {
      val = merge(merge({}, prev), val);
    }
    // 執行賦值
    now[key].value = val;
    // 執行 change 事件,初始化是調用 set 不觸發任何事件
    if (!this.__intializingAttrs && !isEqual(prev, val)) {
      if (silent) {
        changed[key] = [val, prev];
      } else {
        this.trigger("change:" + key, val, prev, key);
      }
    }
  }
  return this;
}
change

手動觸發所有 change:attribute 事件

exports.change = function() {
  var changed = this.__changedAttrs;
  if (changed) {
    for (var key in changed) {
      if (changed.hasOwnPrototype(key)) {
        var args = changed[key];
        this.trigger("change:" + key, args[0], args[1], key);
      }
    }
    delete this.__changedAttrs;
  }
  return this;
}

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/86012.html

相關文章

  • arale 源碼 class

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

    firim 評論0 收藏0
  • Arale源碼解析(3)——Base模塊和Aspect模塊

    摘要:本文同步自我的博客前言這個模塊實際上才是模塊系統中對外的模塊,它包含了之前介紹的類和類,以及自己內部的模塊和模塊,因此模塊是真正的基礎類。這兩個方法的作用就是針對類上的某個方法,給這個方法綁定先于其執行和后于其執行的回調函數。 本文同步自我的GitHub博客 前言 Base這個模塊實際上才是Arale模塊系統中對外的模塊,它包含了之前介紹的Class類和Events類,以及自己內部...

    stdying 評論0 收藏0
  • js 支持 Aspect 切面編程

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

    zhaot 評論0 收藏0
  • Arale源碼解析(1)——Class

    摘要:先來看源碼中,首先是做的是參數的處理工作,針對某些參數未傳的情況作了調整,最后達到的效果是的值為傳入的父類構造函數,如果沒有,設為。下一個語句其作用是處理父類構造函數沒有修改的屬性值并且有方法的時候,在上調用方法。 本文同步自我的GitHub 概述 Arale是支付寶開發的一套基礎類庫,提供了一整套前端模塊架構,基于CMD規范,所有模塊均是以sea.js的標準進行開發。其開發過程借...

    _ivan 評論0 收藏0
  • 2015 Hackathon 杭州站回顧BugLife

    摘要:今天我偷偷的去上喵了幾眼,發現我捉出來的,還沒被消滅掉,看來有必要發個郵件給高陽了。還得到了高陽的飯約,因為我們捉了好幾個的,高陽你別忘啊下面就上幾張我們的的靚照吧的獲獎自之后,我們還是很有自信能得個獎的。 BugLife的誕生記 先自我介紹下我們團隊,Wellming、Bell orchid、Retamia,三枚程序員,主要技能點PHP,目前在一家棒棒的做開源網校系統(EduSoho...

    SmallBoyO 評論0 收藏0

發表評論

0條評論

Magicer

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<