Javascript 通过引用扩展对象
我有一个Javascript 通过引用扩展对象,javascript,Javascript,我有一个extend方法,它可以像您期望的那样在JavaScript中扩展对象: var objA = {a: true}; var objB = extend({b:false}, objA); console.log(objB); // {a: true, b: false} var objA = {a: false}; var objB = Object.create(objA); objB.b = false; console.log(objB.a, objB.b); // true
extend
方法,它可以像您期望的那样在JavaScript中扩展对象:
var objA = {a: true};
var objB = extend({b:false}, objA);
console.log(objB); // {a: true, b: false}
var objA = {a: false};
var objB = Object.create(objA);
objB.b = false;
console.log(objB.a, objB.b); // true,
objA.a = false;
console.log(objB.a, objB.b); // false, false
但是,我希望通过引用将源(objA
)属性扩展到目标(objB
)对象上,以便在事后将对源所做的任何更改反映到目标中,如下所示:
var objA = {a: true};
var objB = extend({b: false}, objA);
console.log(objB); // {a: true, b:false}
objA.a = false;
console.log(objB); // {a: false, b:false}
例如,当您修改一个对象(始终通过引用指定)时,事情会按照我希望的方式进行:
var objA = {A:{a: true}};
var objB = _.extend({b: false}, objA);
console.log(objB) // {A:{a:true}, b:false};
objA.A.a = false;
console.log(objB); // {A:{a:false}, b:false};
因此,换句话说,当对objA
的非对象文字属性(或任何未通过引用指定的值)进行更改时,我希望这些更改反映在objB
中
我相当肯定,如果没有一个附加的helper方法,这是不可能的,该方法依赖于某种对象监视方法,每当对象发生变化时就会触发该方法
想法
我的extend
方法中的代码:
(l).extend = (l).merge = function () {
var args = (l).fn.__args(arguments, [{
deep: 'bool'
}, {
'*': 'obj:object'
}
]),
target = (l)._object || args.obj,
keys = [],
obj, objs, copy, key, i, o;
// Collect potential objects to merge
objs = (l).filter(args, function (value, index) {
if (index !== "obj" &&
(l).isPlainObject(value) && !((l).isEqual(target, value))) {
return value;
}
});
// When target object is not selected globally
if (!args.obj) {
target = objs.shift();
}
// When target object is not selected globally and only a single object
// is passed extend the library itself
if (!(l)._global && !objs.length) {
target = this;
objs[0] = args.obj;
}
// When a boolean is passed go deep
if (args.deep) {
// Build property reference used to prevent never ending loops
(l).each(objs, function (index, value) {
keys.push((l).keys(value));
keys = (l).flatten(keys);
});
// Add properties to all nested objects
(l).deep(target, function (depth, index, obj, ref) {
if ((l).indexOf(keys, index) === -1) {
for (i = 0; i < objs.length; i++) {
for (key in objs[i]) {
if ((l).isPlainObject(obj)) {
copy = objs[i][key];
obj[key] = copy;
}
}
}
}
}, "*");
}
// Merge first level properties after going deep
for (i = 0; i < objs.length; i++) {
if ((obj = objs[i]) !== null) {
for (key in obj) {
copy = obj[key];
if (target === copy) {
continue;
}
target[key] = copy;
}
}
}
return (l).fn.__chain(target);
};
(l).extend=(l).merge=函数(){
变量args=(l).fn.\u args(参数[{
深:“布尔”
}, {
“*”:“对象:对象”
}
]),
目标=(l)。_对象| | args.obj,
键=[],
obj,objs,copy,key,i,o;
//收集要合并的潜在对象
objs=(l).filter(参数,函数(值,索引){
如果(索引!=“obj”&&
(l) .isPlainObject(value)和&!((l).isEqual(target,value))){
返回值;
}
});
//未全局选择目标对象时
如果(!args.obj){
target=objs.shift();
}
//未全局选择目标对象且仅选择单个对象时
//是否通过扩展库本身
如果(!(l)。_全局和对象长度){
目标=这个;
objs[0]=args.obj;
}
//当一个布尔值被传递时,进入深度
if(args.deep){
//用于防止永无止境循环的生成属性引用
(l) .每个(对象、函数(索引、值){
按键。按键((l)。按键(值));
键=(l)。展平(键);
});
//向所有嵌套对象添加特性
(l) .deep(目标、功能(深度、索引、目标、参考){
if((l).indexOf(键,索引)=-1){
对于(i=0;i
您在这里提到的正是JavaScript的原型继承:
var objA = {a: true};
var objB = extend({b:false}, objA);
console.log(objB); // {a: true, b: false}
var objA = {a: false};
var objB = Object.create(objA);
objB.b = false;
console.log(objB.a, objB.b); // true,
objA.a = false;
console.log(objB.a, objB.b); // false, false
当然,如果objB
覆盖a
属性,您将丢失该链接,因为JavaScript将在对象objB
中找到属性a
,因此不会在原型链中查找
使用ECMAScript 5方法,您可以像这样扩展函数:
function extend(properties, proto) {
var object = Object.create(proto);
var descriptor = {};
Object.getOwnPropertyNames(properties).forEach(function(name) {
descriptor[name] = Object.getOwnPropertyDescriptor(properties, name);
});
return Object.defineProperties(object, descriptor);
}
var objA = {a: true};
var objB = extend({b: false}, objA);
console.log(objB.a, objB.b); // true, false
objA.a = false;
console.log(objB.a, objB.b); // false, false
你能在你的扩展方法中发布代码吗?仅仅使用普通的原型继承怎么样<代码>objB.prototype=objA代码>要产生这种级联效果,您必须使用Mattias提到的原型。这应该是可行的,但要注意它是一个真正的引用,即,如果您更改objA上的属性,您将在objB上看到更改,但反之亦然。