了解到这个库是在object-is中看到使用。顺便发现其文档事例的错误提了PR。
用于对对象一次性定义多个不可枚举属性。并且支持自定义predicate来决定是否对重名key进行重写。
可以看到默认情况下对于同名key是不会进行覆盖重写。
var test = { a: 1, b: 2 }
var test2 = {
a: 10,
b: 20,
c: 30
}
defineProperties(test, test2);
console.log(Object.getOwnPropertyDescriptors(test))
//
{
a: { value: 1, writable: true, enumerable: true, configurable: true },
b: { value: 2, writable: true, enumerable: true, configurable: true },
c: { value: 30, writable: true, enumerable: false, configurable: true }
}
使用自定义predicate,predicate()为true则进行重写覆盖。
var test = { a: 1, b: 2 }
var test2 = {
a: 10,
b: 20,
c: 30
}
defineProperties(test, test2,{
a: function () { return false; },
b: function () { return true; }
});
console.log(Object.getOwnPropertyDescriptors(test))
//
{
a: { value: 1, writable: true, enumerable: true, configurable: true },
b: { value: 2, writable: true, enumerable: true, configurable: true },
c: { value: 30, writable: true, enumerable: false, configurable: true }
}
源码
'use strict';
// Object.keys的垫片
var keys = require('object-keys');
// 判断是否支持Symbol
var hasSymbols = typeof Symbol === 'function' && typeof Symbol('foo') === 'symbol';
// 缓存、快捷定义
var toStr = Object.prototype.toString;
var concat = Array.prototype.concat;
var origDefineProperty = Object.defineProperty;
// 判断是否是函数
var isFunction = function (fn) {
return typeof fn === 'function' && toStr.call(fn) === '[object Function]';
};
// 判罚是否支持属性描述符
// 很多时候我们使用嗅探法判罚API支持与否 使用 try-catch
var arePropertyDescriptorsSupported = function () {
var obj = {};
try {
// 定义为不可枚举、并且value为自身
origDefineProperty(obj, 'x', { enumerable: false, value: obj });
// eslint-disable-next-line no-restricted-syntax, no-unreachable-loop
for (var _ in obj) {
// 如果可以被for-in遍历 说明origDefineProperty失效、不支持
return false;
}
// 判断
return obj.x === obj;
} catch (e) { /* this is IE 8. */
// fallback
return false;
}
};
// 是否支持对象属性描述符
var supportsDescriptors = origDefineProperty && arePropertyDescriptorsSupported();
// 通过Object.defineProperty方式定义对象属性描述符
var defineProperty = function (object, name, value, predicate) {
// 如果存在同名key,默认不覆盖、或者predicate()返回false不覆盖
if (name in object && (!isFunction(predicate) || !predicate())) {
return;
}
// 如果支持属性描述符
if (supportsDescriptors) {
// 定义
origDefineProperty(object, name, {
configurable: true,
enumerable: false,
value: value,
writable: true
});
} else {
// 优雅降级
object[name] = value; // eslint-disable-line no-param-reassign
}
};
var defineProperties = function (object, map) {
// 获取自定义的predicates对象
var predicates = arguments.length > 2 ? arguments[2] : {};
// 类似 Object.keys(map)
var props = keys(map);
// 如果支持Symbol、需要通过Object.getOwnPropertySymbols处理Symbol属性
// 因为 Object.getOwnPropertyNames()获取对象所有自身属性的属性名数组,
// 但是它不会包括:不可枚举属性、Symbol值作为名称的属性
if (hasSymbols) {
props = concat.call(props, Object.getOwnPropertySymbols(map));
}
for (var i = 0; i < props.length; i += 1) {
// 遍历处理。
// 因此可见 predicates 是有格式要求的、因此你可以理解defineProperty中对predicates有类型判断
defineProperty(object, props[i], map[props[i]], predicates[props[i]]);
}
};
defineProperties.supportsDescriptors = !!supportsDescriptors;
module.exports = defineProperties;
好了,今天就到这结束了,下期见。
ps:如果你对node也有兴趣,欢迎关注我公众号:xyz编程日记。