Я создаю плагин, который принимает два параметра - высоту и ширину. Пользователи этого плагина могут иметь объект прямоугольника или квадратный объект или объект многоугольника и т.д. Имена их ширины/высоты могут быть разными:
var square = {
width: 200,
height: 200
}
var rectangle = {
Width: 200,
tall: 200
}
var polygon = {
w: 200,
h: 200
}
Я пытаюсь создать функцию, которая принимает параметры width/height и изменяет их, чтобы обновлялся родительский объект. Что-то вроде этого:
var alterStuff = function (width, height){
width = 200;
height = 200;
};
var obj = {width: "28", height: "34"};
alterStuff(obj.width, obj.height);
alert(obj.width);
Цель состоит в том, что потребитель может передавать два примитивных типа, а функция alterStuff
будет обновлять их на объекте.
Какой шаблон можно использовать для достижения этого? В настоящее время свойства obj
не обновляются - я вижу "28" в предупреждении, но мне бы хотелось увидеть "200" без передачи в объект, так как я не знаю, какие имена свойств будут на этом объекте в любом случае.
Короткий ответ: вы не можете!
Когда вы передаете что-то функции, вы передаете ее значение. Если это примитивное значение, например 5, вы передаете 5 функции. Если это объект, на самом деле это ссылка на объект, и вы передаете эту ссылку. Это означает, что когда вы передаете obj.width
который имеет значение, например 45px
вы передаете только эту строку функции, и нет абсолютно никакого соединения с obj
.
Единственный способ обновить свойства объекта - передать сам объект и имя свойства:
function change(obj, key, val) {
obj[key] = val;
}
var obj = { width : 5 };
change(obj, 'width', 10);
В вашей конкретной ситуации вы можете сделать все возможное, чтобы "угадать" имена свойств из ключей объекта. В следующем примере widthKey и heightKey являются необязательными, поэтому, если пользователь библиотечной функции имеет хорошо себя вести, ему не нужно передавать их. В противном случае он должен их пройти.
function updateSize(object, width, height, opt_widthKey, opt_heightKey) {
// potential width properties:
var widths = ['width', 'Width', 'w'];
// potential height properties:
var heights = ['height', 'Height', 'h'];
var widthKey = opt_widthKey || getPropertyName(object, widths);
if (!widthKey) throw new Error('Can not guess width property');
var heightKey = opt_heightKey || getPropertyName(object, heights);
if (!heightKey) throw new Error('Can not guess height property');
object[widthKey] = width;
object[heightKey] = height;
}
function getPropertyName(object, properties) {
for (var i=0; i<properties.length; i++) {
if (object.hasOwnProperty(properties[i]))
return properties[i];
}
}
// usage:
var obj = { width : 5, Height : 10 };
var notGood = { tall : 20, wide : 40 };
updateSize(obj, 100, 200);
updateSize(notGood, 100, 200, 'wide', 'tall');
Вам придется передать сам объект, а не его свойства:
var alterStuff = function (obj){
obj.width = 200;
obj.height = 200;
};
var obj = {width: "28", height: "34"};
alterStuff(obj);
Вы можете прочитать эту статью.
Я не думаю, что есть хороший способ сделать то, что вы хотите, не передавая объект. Возможно, вы могли бы вернуть массив из 2 элементов, на который вызывающий абонент будет отвечать за загрузку обратно в нужное место:
var alterStuff = function(width, height) {
return [+width * 2, +height * 2]; // for example
}
var obj = {width: "28", height: "34"};
var newValues = alterStuff(obj.width, obj.height);
obj.width = newValues[0];
obj.height = newValues[1];
Или вы можете заставить вызывающего абонента выполнить функцию обратного вызова:
var alterStuff = function(width, height, callback) {
// note: you may want to include some checks for undefined and that callback is a function
callback(+width *2, +height * 2);
}
alterStuff(obj.width, obj.height, function(width, height) {
obj.width = width;
obj.height = height;
});
Итак, теперь, если бы у меня было:
var rectangle = {
Width: 200,
tall: 200
}
Я мог бы вызвать alterStuff
следующим образом:
alterStuff(rectangle.Width, rectangle.tall, function(Width, tall) {
rectangle.Width = Width;
rectangle.tall = tall;
});
И какие имена я выбираю для свойств "ширина" и "высота", это выбор вызывающих.
Или ответ Тибоса - это еще одна альтернатива, когда вы передаете ключ (ы), когда вы вызываете функцию.