如果有人可以选择以某种方式设计东西,那么通常更好(通过性能,可维护性,可读性,功能等......)进行功能链接或使用对象属性访问器进行分层访问为什么?
它完全取决于用例,还是一般优越的?
示例:
var foo = bar.get('parent').get('child').get('grandChild')...
// vs
var foo = bar['parent']['child']['grandChild']...
// or
var foo = bar.parent.child.grandChild...
还是有更好的方法来完成它吗?
请注意,由于源缩小,使用不是有效JavaScript标识符的属性值等,点符号.
可能并不总是可行。
由于这太过于通用,那么更具体的例子呢......
考虑以下内容......
var animals = {
dogs: {
'Chloe': {
name: 'Chloe',
fetch: function() {},
rollover: function() {},
pups: {
'Charlie': {
name: 'Charlie',
fetch: function() {},
rollover: function() {}
},
'Lily': {
//...
}
}
},
'Toby': {
//...
}
},
cats: {
'Fido': {
name: 'Fido',
meow: function() {},
kittens: {
'Mia': {
name: 'Mia',
meow: function() {}
},
'Shadow': {
//...
}
}
}
}
}
请注意,这是尝试显示层次结构并且不显示任何原型继承,尽管它可能存在(并且可能在示例中)。
在如图所示的层次结构中,可以使用属性访问来获取某个小狗,如下所示
var myPup = animals.dogs['Chloe'].pups['Charlie'];
// or
var myPup = animals.dogs.Chloe.pups.Charlie;
// or
var myPup = animals['dogs']['Chloe']['pups']['Charlie'];
这是理想的吗?或者使用函数访问小狗有显着的好处
var myPup = animals.dogs('Chloe').pups('Charlie');
答案 0 :(得分:2)
我认为您使用错误的工具来处理错误的工作。像你这样对象的深度嵌套是数据建模的一个非常糟糕的选择。这是您的数据模型的样子:
+ animals
|
+--+ dogs
| |
| +--+ Chloe
| | |
| | +--+ Charlie
| | |
| | +--+ Lily
| |
| +--+ Toby
|
+--+ cats
|
+--+ Fido
|
+--+ Mia
|
+--+ Shadow
这种数据模型称为hierarchical model,因为数据以层次结构的形式排列。
分层数据模型不是一个好的数据模型,因为它没有提供access path independence。这仅仅意味着(由于数据的建模方式),在不知道其访问路径的情况下找不到给定的对象是不可能的。
例如,Lily
的访问路径为animals.dogs.Chloe.Lily
,Toby
的访问路径为animals.dogs.Toby
。访问路径独立性很重要,因为这意味着您不必担心对象在数据模型中的位置。这使编程更简单,并确保在相同的时间内访问每个对象。
在上面的示例中,访问Lily
所需的时间比访问Toby
所需的时间长,因为它更深一层。为了说明访问路径依赖如何使编程更加困难,请考虑以下代码:
function findParentOf(animal) {
var dogs = animals.dogs;
for (var dog in dogs)
if (dogs[dog].pups.hasOwnProperty(animal))
return dog;
var cats = animals.cats;
for (var cat in cats)
if (cats[cat].kittens.hasOwnProperty(animal))
return cat;
return null;
}
现在想象你有许多不同类型的动物,如狗,猫,兔子,仓鼠等。你能看到你会有多少代码吗?
事实上,您的数据模型也有很多冗余。例如,每个对象都有一个name
,即使它的键具有相同的值。此外,每只狗和小狗都有fetch
和rollover
功能,每只猫和小猫都有meow
功能。
使用正确的抽象可以很容易地概括所有这些。例如,这就是我要做的事情:
function animal(kind, parent, name) {
return {
kind: kind,
parent: parent,
name: name
};
}
var dog = animal.bind(null, "dog", null);
var pup = animal.bind(null, "dog");
var cat = animal.bind(null, "cat", null);
var kitten = animal.bind(null, "cat");
var animals = [
dog("Chloe"),
pup("Chloe", "Charlie"),
pup("Chloe", "Lily"),
dog("Toby"),
cat("Fido"),
kitten("Fido", "Mia"),
kitten("Fido", "Shadow")
];
这种数据建模方式称为relational model。关系模型最好的一点是它具有访问路径独立性。因此,您可以轻松找到对象并执行其他任务。例如:
function findAnimal(name) {
return animals.find(function (animal) {
return animal.name === name;
});
}
function findParentOf(name) {
var animal = findAnimal(name);
if (animal) {
var parent = animal.parent;
return parent && findAnimal(parent);
}
}
function findChildrenOf(name) {
return animals.filter(function (animal) {
return animal.parent === name;
});
}
现在我们有了访问路径独立性,我们可以轻松找到对象。例如:
var lily = findAnimal("Lily");
var toby = findAnimal("Toby");
var fido = findParentOf("Shadow");
var miaAndShadow = findChildrenOf("Fido");
最后,当谈到fetch
,rollover
和meow
函数时,您可以按如下方式定义它们:
function fetch(animal) {
if (animal.kind === "dog") {
// do something
}
}
function rollover(animal) {
if (animal.kind === "dog") {
// do something
}
}
function meow(animal) {
if (animal.kind === "cat") {
// do something
}
}
甚至更好,将它们放入命名空间。感谢Richard Simpson给了我这个想法:
dog.fetch = function (animal) {
if (animal.kind === "dog") {
// do something
}
};
dog.rollover = function (animal) {
if (animal.kind === "dog") {
// do something
}
};
cat.meow = function (animal) {
if (animal.kind === "cat") {
// do something
}
};
然后你可以这样做:
dog.rollover(findAnimal("Charlie"));
var rolloverDog = compose(dog.rollover, findAnimal);
function compose(f, g) {
return function (x) {
return f(g(x));
};
}
rolloverDog("Charlie");
只是我的两分钱。希望这会有所帮助。