JavaScript:函数链接还是属性访问?

标签 javascript function object

如果一个人可以选择以一种或另一种方式设计事物,通常情况下(通过性能、可维护性、可读性、功能性等方式)进行函数链接或使用对象属性访问器进行分层访问更好吗? ,为什么?

它是完全取决于用例,还是通常更优越?

例子:

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': {
                    //...
                }
            }
        }
    }
}

请注意,这是展示层次结构的尝试,并未展示任何原型(prototype)继承,尽管它可能存在(并且可能会出现在示例中)。

在如图所示的层次结构中,可以使用属性访问权限来访问某个 pup,如下所示

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');

最佳答案

我认为您为错误的工作使用了错误的工具。像你那样深度嵌套对象是数据建模的一个非常糟糕的选择。您的数据模型如下所示:

+ animals
|
+--+ dogs
|  |
|  +--+ Chloe
|  |  |
|  |  +--+ Charlie
|  |  |
|  |  +--+ Lily
|  |
|  +--+ Toby
|
+--+ cats
   |
   +--+ Fido
      |
      +--+ Mia
      |
      +--+ Shadow

这种数据模型称为 hierarchical model因为数据是以层级的形式排列的。

分层数据模型不是一个好的数据模型,因为它不提供 access path independence .这仅仅意味着(由于数据建模的方式)不可能在不知道其访问路径的情况下找到给定的对象。

例如Lily的访问路径是animals.dogs.Chloe.LilyToby的访问路径是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,即使它的键具有相同的值。此外,每只狗和小狗都有 fetchrollover 功能,每只猫和小猫都有 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");

最后说到fetchrollovermeow函数,可以这样定义:

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"));

或用function composition :

var rolloverDog = compose(dog.rollover, findAnimal);

function compose(f, g) {
    return function (x) {
        return f(g(x));
    };
}

rolloverDog("Charlie");

只是我的两分钱。希望这会有所帮助。

关于JavaScript:函数链接还是属性访问?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26149964/

相关文章:

javascript - 我需要在对象数组中找到一个键并将其与正则表达式匹配

PHP 对象索引作为字符串?

javascript - 我的上下文是在构造函数中定义的,而不是在函数中定义的。无法读取 HTMLCanvasElement.draw 处未定义的属性 'beginPath'

javascript - 将JSON对象转换为javascript中的数组数组

javascript - nodeJS Winston 模块示例未记录到控制台

javascript - 如何从跨域 iframe 捕获(初始化)错误?

javascript - 如何理解 Angular 服务调用?

c - C 函数中的 malloc 和自由指针

sql-server - T-SQL 中的 CASE 语句或函数具有更好的性能

swift - 类内的变异函数