>问题:如何在不创建新的对象引用的情况下"就地"扩展对象。
剧情简介:JQuery extend按照它在锡上所说的去做。
但是,如果使用返回新对象的jquery.extend版本,那么新对象就是一个新对象。一切都很好,但是如果我在一个函数中进行扩展,我将对要扩展的对象的引用传递到其中,则原始对象保持不变。一个不错的陷阱等待着粗心的人(我(。您知道对象是通过引用传递的 - 对吗?
示例代码:假设我有一个对象
myObject = {
fontFamily : 'Tahoma',
fontSize: '12',
color : '000000'
}
和默认选项
myDefaults = {
fontFamily : 'Tahoma',
fontSize: '15',
color : 'FF0000',
weight : 'bold',
decoration : 'underline'
}
我的预期结果是:
myObject = {
fontFamily : 'Tahoma',
fontSize: '12',
color : '000000',
weight : 'bold',
decoration : 'underline'
}
所以这是代码:
var myObject = {
fontFamily : 'Tahoma',
fontSize: '12',
color : '000000'
}
$('#myObjectIn').html(JSON.stringify(myObject));
extenderoony(myObject);
$('#myObjectOut').html(JSON.stringify(myObject));
function extenderoony(obj){
var myDefaults = {
fontFamily : 'Tahoma',
fontSize: '15',
color : 'FF0000',
weight : 'bold',
decoration : 'underline'
}
obj = $.extend({}, obj, myDefaults); // << Changes the object reference of obj to a new object leaving the original object passed in as the parameter unchanged.
$('#obj').html(JSON.stringify(obj));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >Before the extend func</div>
<div id='myObjectIn'></div>
<hr>
<div >Inside the extend func</div>
<div id='obj'></div>
<hr>
<div >After the extend func</div>
<div id='myObjectOut'></div>
我的回答感觉很笨拙 - 我会在下面发布它。
将选项扩展到默认值会导致 myDefaults 采用您显式给出的值。 然后,将 myDefaults 扩展到选项中会导致您更新传入的原始对象,而不是将其分配给全新的对象。
var myObject = {
fontFamily : 'Tahoma',
fontSize: '12',
color : '000000'
};
function extend ( options ) {
let myDefaults = {
fontFamily : 'Tahoma',
fontSize: '15',
color : 'FF0000',
weight : 'bold',
decoration : 'underline'
}
let temp = $.extend( myDefaults, options );
$.extend( options, myDefaults );
}
extend( myObject );
let expectedObject = {
fontFamily : 'Tahoma'
, fontSize: '12'
, color : '000000'
, weight : 'bold'
, decoration : 'underline'
};
Object.keys( expectedObject ).forEach( key => {
console.log( `Does ${key} match expected value?`, myObject[ key ] === expectedObject[ key ] );
} );
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
如果要跳过双扩展,可以自己复制密钥。
var myObject = {
fontFamily : 'Tahoma',
fontSize: '12',
color : '000000'
};
function extend ( options ) {
let myDefaults = {
fontFamily : 'Tahoma',
fontSize: '15',
color : 'FF0000',
weight : 'bold',
decoration : 'underline'
}
Object.keys( myDefaults ).forEach( key => {
if ( options[ key ] === undefined ) options[ key ] = myDefaults[ key ];
} );
}
extend( myObject );
let expectedObject = {
fontFamily : 'Tahoma'
, fontSize: '12'
, color : '000000'
, weight : 'bold'
, decoration : 'underline'
};
Object.keys( expectedObject ).forEach( key => {
console.log( `Does ${key} match expected value?`, myObject[ key ] === expectedObject[ key ] );
} );
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
这是我的答案 - 与问题相同的基本片段代码,并
添加了注释。
var myObject = {
fontFamily : 'Tahoma',
fontSize: '12',
color : '000000'
}
$('#myObjectIn').html(JSON.stringify(myObject));
// Attempt #1
// myObject = extenderoony(myObject); // this fails, I think because the param reference overwrites the returned value
// Attempt 2
var a = extenderoony(myObject); // introduce the additional variable to receive the object ref
myObject = a; // And pass this reference on to the original. Phew, hacky.
$('#myObjectOut').html(JSON.stringify(myObject));
function extenderoony(obj){
var myDefaults = {
fontFamily : 'Tahoma',
fontSize: '15',
color : 'FF0000',
weight : 'bold',
decoration : 'underline'
}
obj = $.extend({}, obj, myDefaults); // << Changes the object reference of obj to a new object leaving the original object passed in as the parameter unchanged.
$('#obj').html(JSON.stringify(obj));
return obj; // have to send back the 'new' object reference cos we used that extend format !
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >Before the extend func</div>
<div id='myObjectIn'></div>
<hr>
<div >Inside the extend func</div>
<div id='obj'></div>
<hr>
<div >After the extend func</div>
<div id='myObjectOut'></div>