JavaScript语法:({})是函数还是对象?

4
作为一名具有面向对象编程背景(C#,Java)的开发人员,OOP JavaScript 对我来说就像狂野的马。我正在尝试学习语言的基础知识,然后再进入库(我错了吗?);
所以,我查阅了许多关于对象、函数等方面的书籍/教程...学习了几种创建对象的方法,但几乎每个 JS 库中使用的语法都使我感到困惑,即...
var Person = Backbone.extend.Model({
 //pretty complex staff
 })

在幕后,Model是什么?对象?函数?


那不应该是 Backbone.Model.extend 吗? - mu is too short
3个回答

14

那不是正确的骨干语法。实际上应该是:

Backbone.Model.extend({

});

在这种情况下,extend是一个函数。请注意,您正在使用()调用它。然而,在JavaScript中,函数也是对象(稍后详细介绍)。您可能会对其中的{}感到困惑。那是因为您将该对象作为参数传递给函数。

如果extend是一个期望字符串作为参数/参数的函数,它将如下所示:extend('some string')。在这种情况下,它正在使用一个对象。例如:

var someObject = {
  someProperty: 'someValue'
}
var Person = Backbone.Model.extend(someObject);

与以下内容相同:

var Person = Backbone.Model.extend({
  someProperty: 'someValue'
});

以下只是演示该函数可能的样子:

Backbone.Model.extend = function(obj) {
  console.log(obj.someProperty); //logs "someValue"
}

就像我说的,在JavaScript中,函数也是对象。实际上,大多数东西都是对象。我建议你在这方面多学习。由于这不是你问题的重点,所以我只会简要演示:

var someObj = {
  someProperty: '123'
};
console.log(someObj.someProperty); //logs "123"

var someFunction = function() {

};
someFunction.someProperty = '123';
console.log(someFunction.someProperty); //logs "123"

虽然,最好将原型添加到其中,这样继承将以如下方式工作:

someFunction.prototype.someProperty = '123';
var foo = new someFunction();
console.log(foo.someProperty); //logs "123"

这里有一个小的演示可以让你随意调整(点击)。

总而言之,JavaScript 真是太赞了。


1
为了添加一些可能澄清事情的东西,作为extend()参数的对象{}在函数调用之前被评估。因此,您基本上是将一组键/值作为参数传递给extend函数。 - GameAlchemist

2
你确定输入正确吗?我认为你颠倒了Modelextend的顺序。我现在正在查看文档,其中写到:

模型是任何JavaScript应用程序的核心,包含交互式数据以及围绕其的大部分逻辑:转换、验证、计算属性和访问控制。您可以使用特定于域的方法扩展Backbone.Model,而Model提供了一组基本功能来管理更改。

extend函数在许多JavaScript库中都有实现:Backbone、Underscore和jQuery等。它的作用是将一个对象添加方法和实例变量。毕竟在JavaScript中,对象只是散列。这将创建一个具有一些方法和数据的对象。
var counter = {};
counter.count = 0;
counter.increment = function() {
    this.count++;
}
counter.decrement = function() {
    this.count--;
}

如果您想要继承,可以使用对象或其构造函数的prototype属性。而extend方法是模拟这个过程的一种方式。下面是更多的Backbone文档:

extendBackbone.Model.extend(properties, [classProperties])

如果您想创建自己的Model类,可以扩展Backbone.Model并提供实例属性,以及可选的classProperties直接附加到构造函数中。

extend正确地设置原型链,因此使用extend创建的子类可以进一步扩展和派生。

var Note = Backbone.Model.extend({

    initialize: function() { ... },

    author: function() { ... },

    coordinates: function() { ... },

    allowedToEdit: function(account) {
        return true;
    }

});

在传统的JavaScript中,您需要编写以下代码:
function Note() {
    this.initialize  = function() {...};
    this.author      = function() {...};
    this.coordinates = function() {...};
    this.allowedToEdit = function(account) {
        return true;
    };
}

Note.prototype = new Model();  // Inheritance.

在JavaScript中的继承让我想起了Perl的格言:“做事情的方式不止一种。”

1

欢迎来到stackoverflow,

我强烈建议您查看Douglas Crockford的网站,还有YUI Theater中深入的视频 - 先从Douglas的视频开始。他是发现JavaScript优秀部分的人。我也发现John Resig的JavaScript Ninja秘密对理解该语言非常有帮助(John是万能的jQuery库的创建者)。我进一步建议您查看一些库(及其代码 - 这就是我学习的方法 - 从jQuery开始)。有大量其他库可用,但要一步一步来 :-).

现在回答您的问题: Backbone.Model是一个构造函数,通常情况下您可以像Java一样使用它:new Backbone.Model({ configOption: true, ... })。但JavaScript非常强大,它允许您在幕后做出疯狂的事情。例如,您可以实现自己的面向对象类实现,或者像在Scheme或Lisp中所做的那样以函数式风格编程。您在这里看到的是Backbone自己的子类型包装器在起作用(几乎任何体面的JS库都提供一些方法来实现此操作)。 代码实际上正在执行类似于以下内容的操作:
// Creating a sub type of the Backbone.Model *class* - it's not really 
// a class like in Java or C# but rather a (constructor) function.
var Person = Backbone.Model.extend({ 
    defaults: {
        hasTheOneRing: true
    },
    initialize: function (hasTheOneRing) {
        // Note that Backbone is implementing getters/setters
        // under the hood so you can listen for change events later
        this.set('hasTheOneRing', hasTheOneRing);
    }
    // More configuration ...
});

// Person now is a constructor function that creates instances
// of it's *class* when you create an object with it
var frodo = new Person(true),
    sam = new Person(); // Note that you can supply as many arguments as you wish

// Frodo has the ring
console.log(frodo.get('hasTheOneRing')); 

// Sam doesn't have the ring (well not all the time)
console.log(sam.get('hasTheOneRing')); 

// In plain old JavaScript the sub typing mechanism works a little bit like this:

// A constructor function is just a function
function Person() {
    // JS doesn't have the notion of *super* or *base* but you
    // can emulate the behavior as many libraries do in the wild
    Backbone.Model.call(this);
}

// The prototype of a person is based on that of a Backbone.Model
Person.prototype = Object.create(Backbone.Model.prototype);

// Object.create has not been there since the beginning. After
// Douglas Crockford discovered the good parts this function
// has been adapted into the standard portfolio of every modern browser
// what it does is essentially just:
function create(object) {
    // There's actually more going on in here but you get the idea
    function F() {}
    F.prototype = object;
    return new F();
}

// So this means almost the same
Person.prototype = new Backbone.Model();

我的学习JS的方法是阅读库代码,Backbone是开源的,所以请阅读并惊叹于其令人惊叹的魅力g。我认为JS只是通过网络发送的纯文本对语言在生态系统中变得强大产生了很大影响,即使微软也无法阻止它。
试试这种语言,当你理解它时,你很可能会真正开始喜欢它:-)。
愉快的编码!

是的,我真的很喜欢它。它既不同又可爱。 - brocode

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接