baseAssign

本来是写_.clone这个系列,没想到碰到了assign。想了想,还是得扒皮这个方法。就特意重新开一章。写这个方法。

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方法。

换言之,_.assign是在baseAssign这个方法上进一步封装实现。

在baseAssign中,使用到了copyObject

--
源码copy多了,看着有点乱,让我胡乱分析一下。

baseAssign中是copyObject(source, keys(source), object)使用的copyObject的,显然source是一个期待被覆盖的对象,我们知道,我们使用_.assign的时候,如果source上的属性存在并且object上的同名属性不存在,source的属性会保持不变,object上如果存在同名属性,那么object上同名属性的value会覆盖到source的同名属性上,代替原有的值。

我们继续看一下lodash的作者是如何实现这个功能的。

 /**
     * 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;
    }

--

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;

我们在看

   /**
     * 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.

最普通的一个
301 声望41 粉丝

永远不要做你擅长的事。


引用和评论

0 条评论