lodash的baseAssign方法

baseAssign

原本是寫_.clone這個系列,沒想到碰到了assign。想了想,仍是得扒皮這個方法。就特地從新開一章。寫這個方法。javascript

show me code

/**
     * The base implementation of `_.assign` without support for multiple sources
     * or `customizer` functions.
     *
     * @private
     * @param {Object} object The destination object.
     * @param {Object} source The source object.
     * @returns {Object} Returns `object`.
     */
function baseAssign(object, source) {
      return object && copyObject(source, keys(source), object);

baseAssign是_.assign的基礎實現。對lodash來講,它是一個private方法。priviate是私有方法,只在lodash這個庫內部調用。對應的是public方法 ,_.assign就是對外暴露使用的public方法。java

換言之,_.assign是在baseAssign這個方法上進一步封裝實現。git

在baseAssign中,使用到了copyObjectgithub

--
源碼copy多了,看着有點亂,讓我胡亂分析一下。數組

baseAssign中是copyObject(source, keys(source), object)使用的copyObject的,顯然source是一個期待被覆蓋的對象,咱們知道,咱們使用_.assign的時候,若是source上的屬性存在而且object上的同名屬性不存在,source的屬性會保持不變,object上若是存在同名屬性,那麼object上同名屬性的value會覆蓋到source的同名屬性上,代替原有的值。ide

咱們繼續看一下lodash的做者是如何實現這個功能的。ui

/**
     * Copies properties of `source` to `object`.
     * 複製屬性,從soure複製屬性到object
     * @private
     * @param {Object} source The object to copy properties from.  源對象
     * @param {Array} props The property identifiers to copy. 被copy的 對象屬性標識符,是個數組
     * @param {Object} [object={}] The object to copy properties to. 目標對象
     * @param {Function} [customizer] The function to customize copied values.
     * @returns {Object} Returns `object`.返回目標對象
     */
    function copyObject(source, props, object, customizer) { // props顯然是source上已有屬性的數組。
      var isNew = !object;// 若是object是一個對象,那麼isNew爲false
      object || (object = {}); // object不存在,默認一個空對象

      var index = -1,
          length = props.length;// 屬性數組的長度

      while (++index < length) {
        var key = props[index];// 

        var newValue = undefined;

        if (newValue === undefined) {
          newValue = source[key]; // 沒有customizer的狀況下,newValue爲undefined,到這一步,變成了source上key屬性的值。
        }
        // baseAssignValue和assignValue都是將newValue合併到object的key上。簡單粗暴點就是object[key] = newValue的功能,那是否會是屢次一舉呢,咱們還要往下看代碼。
        if (isNew) {
          baseAssignValue(object, key, newValue);
        } else {
          assignValue(object, key, newValue);// 
        }
      }
      return object;
    }

--es5

baseAssing源碼以下翻譯

/**
     * The base implementation of `assignValue` and `assignMergeValue` without
     *  `assignValue` and `assignMergeValue`的基礎實現
     * value checks.
     *
     * @private
     * @param {Object} object The object to modify.
     * 被修改的對象
     * @param {string} key The key of the property to assign.
     * 被合併的屬性名
     * @param {*} value The value to assign.
     * 被合併的值
     */
    function baseAssignValue(object, key, value) {
      if (key == '__proto__' && defineProperty) {
      // es5的defineProperty,這裏不展開介紹,
        defineProperty(object, key, {
          'configurable': true,//可配置
          'enumerable': true,// 可遍歷
          'value': value, // 值
          'writable': true  // 可寫
        });
      } else {
        object[key] = value; // 不解釋
      }
    }

簡單粗暴點的話,這個方法的做用就是object[key] = value;code

咱們在看

/**
     * Assigns `value` to `key` of `object` if the existing value is not equivalent。
     * 若是現有值不相等,則將`value`分配給`object`的`key`

     * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
     * for equality comparisons.
     *
     * @private
     * @param {Object} object The object to modify.
     * 被修改的對象
     * @param {string} key The key of the property to assign.
     * @param {*} value The value to assign.
     */
    function assignValue(object, key, value) {
      var objValue = object[key]; // 當前的key上的value
      // object自身沒有key這個屬性 好比object={c:[1,2,3,4]},key='c',
      if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
          (value === undefined && !(key in object))) {
        baseAssignValue(object, key, value);
      }
    }

這個if條件怎麼看怎麼糾結。他分爲兩個條件

  • 若是object自身屬性上不存在這個key,並且objvalue 等於value,想了想,object是有原型對象的,雖然他當前沒有,可是原型鏈上有這個屬性
  • (value === undefined && !(key in object)) 看issue,一個屬性值是能夠undefined,而且屬性是存在這個對象上的。這個分支是用來確保value是undefine而且屬性在對象上是不存在的。

eq: 執行 SameValueZero 比較二者的值,來肯定它們是否相等。

/**
 * _.eq(object, object);
 * // => true
 *
 * _.eq(object, other);
 * // => false
 *
 * _.eq('a', 'a');
 * // => true
 *
 * _.eq('a', Object('a'));
 * // => false
 *
 * _.eq(NaN, NaN);
*/

function eq(value, other) {
  return value === other || (value !== value && other !== other);
}

SameValueZero

The internal comparison abstract operation SameValueZero(x, y), where x and y are ECMAScript language values, produces true or false. Such a comparison is performed as follows:

這裏也不知道怎麼翻譯,大概意思就是,ECMAScript國際上的抽象比較操做規則,返回true或者false,遵循以下的規則。

1.If Type(x) is different from Type(y), return false.
2.若是x,y類型不一樣,直接返回false

If Type(x) is Number, then
若是x是number類型,那麼以下
If x is NaN and y is NaN, return true.
x,y是NaN,返回true,*這裏與咱們知道的NaN!==NaN有區別*
If x is +0 and y is -0, return true.
不解釋
If x is -0 and y is +0, return true.
不解釋
If x is the same Number value as y, return true.
不解釋
Return false.

3.Return SameValueNonNumber(x, y).

SameValueNonNumber (x, y)

  1. Assert: Type(x) is not Number.
  2. Assert: Type(x) is the same as Type(y).
  3. If Type(x) is Undefined, return true.
  4. If Type(x) is Null, return true.
  5. If Type(x) is String, then

If x and y are exactly the same sequence of code units (same length and same code units at corresponding indices), return true; otherwise, return false.

  1. If Type(x) is Boolean, then

If x and y are both true or both false, return true; otherwise, return false.

  1. If Type(x) is Symbol, then

If x and y are both the same Symbol value, return true; otherwise, return false.

  1. Return true if x and y are the same Object value. Otherwise, return false.
相關文章
相關標籤/搜索