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)
- Assert: Type(x) is not Number.
- Assert: Type(x) is the same as Type(y).
- If Type(x) is Undefined, return true.
- If Type(x) is Null, return true.
- 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.
- If Type(x) is Boolean, then
If x and y are both true or both false, return true; otherwise, return false.
- If Type(x) is Symbol, then
If x and y are both the same Symbol value, return true; otherwise, return false.
- Return true if x and y are the same Object value. Otherwise, return false.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。