# defaults
# Description
分配来源对象的可枚举属性到目标对象所有解析为 undefined 的属性上。 来源对象从左到右应用。 一旦设置了相同属性的值,后续的将被忽略掉。
# Params
(object, ...sources)
# Return
object
# Depend
import eq from './eq.js'
# Code
/** Used for built-in method references. */
const objectProto = Object.prototype
/** Used to check objects for own properties. */
const hasOwnProperty = objectProto.hasOwnProperty
function defaults(object, ...sources) {
object = Object(object)
sources.forEach((source) => {
if (source != null) {
source = Object(source)
for (const key in source) {
const value = object[key]
if (value === undefined ||
(eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))) {
object[key] = source[key]
}
}
}
})
return object
}
# Analyze
sources
forEach
遍历,拿到每个source
- 如果
source
不为undefined
或者 不为null
- 则遍历
source
, 判断object
上对应的key
是否为undefined
,如果为undefined
,则将source[key]
设置给object[key]
- 如果
object[key]
不为undefined
,则判断是不是Object
原型上的值,如果是其原型上的值,默认也会认为object
本身是没有该属性的,也是可以设置的 - 但是只判断
prototype
是不够的,defaults
规则有一条说后续的值不能覆盖已有的值,所以要判断当前的key
不在object
上!hasOwnProperty.call(object, key)
- 满足3 或者 4,5 会将 source[key] 设置给 object[key]
- 使用
Object
构造函数是为了 避免基本类型出错
# Remark
- Object.prototype.hasOwnProperty() MDN (opens new window) 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)
- Object () 构造函数 (opens new window)
# Example
defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }) // => { 'a': 1, 'b': 2 }