繁体   English   中英

面向对象编程:我应该使用函数还是对象文字

[英]OO programming: Should I use functions or object literals

我知道一点点Java,我喜欢这整个类和OO编程风格。 好吧我正在阅读JavaScript,我发现没有像Java和C ++那样的“经典”OO风格,甚至不是简单的构造函数。 程序员有很多选择。 好吧,我做了这个,你怎么看待它。 可以像这样编写构造函数吗?

//constructor of Human
function Human(name, age, size, married) {
    this.n = name;
    this.a = age;
    this.s = size;
    this.m = married
    this.printInformation = function() {
        return "Name: " + this.n + ", Age: " + this.a + ", Size: " + this.s + ", Married: " + this.m;
    };
}

var human1 = new Human("Lenny Linux", 42, "142cm", false);
window.alert(human1.printInformation());

它的工作,所以我认为它可以。 但是有一个问题:我也有其他选择。 喜欢使用这些“对象文字”或他们称之为。 我能做到这一点:

var human1 = {
    name: "Lenny Linux",
    age: 42,
    size: "142cm",
    married: false,
    printInformation: function() {
        //...
    }
}

那么这个更快呢? 在我写完之后,有一个人类的“对象”,另一个我必须初始化。 但我更喜欢另一个。 我更容易忽略我的代码。 但是第一个例子不是典型的JavaScript吗? 所以我必须忘记Java的一切并使用特殊的JavaScript风格? 或者我可以保留我的Java代码风格吗? 你怎么看?

PS:第一个例子的另一个问题。 它让我疯狂,我不能强迫程序员,如果他初始化构造函数只使用布尔值,如果他在“已婚”变量。 但我真的想强迫他。 年龄相同:只能是整数...任何想法?

谢谢!

您描述的两种方法实际上完全等效 (除了语法之外),从Javascript的角度来看大多数都可以。 也就是说,您可能不应该根据您现在所熟悉的内容选择做什么 - 从长远来看,您需要习惯使用语言而不是使用语言。 继续...

如果我想强制我的字段成为某种类型,如在Java中,该怎么办?

Javascript是动态类型的,因此您将很难尝试应用相同的静态类型范例。 您可以尝试在对象构造函数中执行运行时检查(使用typeof),但这通常不值得,因为检查仍然在运行时,不检查可能会导致类似的错误,而且typeof非常有限(检查是否很棘手)东西是一个数组,它很烦人检查接口,让我们不要开始使用“外来”浏览器对象......)

最后, 不要过于强调动态类型 - 你会很快习惯它。

如果你说对象文字方法和构造函数方法返回相同的结果,那么差异是什么呢?

首先,虽然对象文字是一个非常简洁的语法,但有些事情需要在多个语句中分开,所以你需要一个函数来实现它们:

//Note: lowercase name since I won't be using 'new here...
//there is a good convention for only using capital names on 
// "real" constructors
function create_human(name, age){
    var obj = {};
    obj.name = name;
    obj.age = age;

    //this needs to be on a separate statement
    //since it involves the other fields
    obj.isAdult = (obj.age >= 21);

    return obj;
}

//not using 'new ...yet
var that_penguin = create_human("Lenny", 42);

请注意,对象文字在这里仍然非常有用,并且在通常具有大型参数列表的情况下使用它们来提供命名和默认参数非常受欢迎:

function  create_human(args){
    var obj;
    obj.name = args.name;
    //...
}

var x  = create_human({
    name: 'Lenny',
    age: 42,
    //...
});

记住:到目前为止,使用函数来构建对象与对象文字只是风格和组织的问题,最好的方法通常取决于你正在处理的具体情况。 在我的经验中, 对象文字对于创建单例和配置字典非常有用,而函数对于在复杂对象中强制执行不变量非常有用,这些对象提供了常用的简写。

那么什么是“真正的”构造函数, 新的这个呢?

手工明确地构造对象的缺点是我们错过了我们习惯的一些OO善良。 通过给每个对象提供其方法的副本,我们不仅浪费空间(用经典语言存储在类中),而且我们失去差异继承(因为一切都是静态的)。 Javascript处理这个的方式是使用Prototypes 所有对象都有一个原型,当查找属性(或方法)时,如果没有立即找到它,则在原型中递归搜索。

原型的一个常见用例是使一类对象自己保留实例变量但共享方法:

lenny:
    name: "Lenny"
    age: 42
    __proto__: Person.prototype

glenda:
    name: "Glenda"
    age: 19
    __proto__: Person.prototype

Person.prototype:
    printInformation: ...
    tons of methods: ...

这样我们就可以访问lenny.printInformation,甚至没有注意到这个方法正在与Glenda共享。

要使用原型创建对象,您可以使用Object.create (至少在较新的浏览器上)或使用构造函数和new运算符的旧方法:

function Person(name, age){
    //The 'new operator provides an empty
    // 'this' object with a suitable prototype.
    // The constructor function just needs to fill in the 
    // instance variables.

    this.name = name;
    this.age = age;

    //note: no return statement!

    //and no methods as well
    //(unless they need to be closures but thats another thing)...
}

//Methods in Person.prototype, will be shared by all Person instances:
Person.prototype = {
    printInformation: function(){
        console.log('my age is', this.age);
    }
};

var lenny = new Person("Lenny", 42);

加起来

如果要使用该语言的原型功能,请使用构造函数和new运算符。

否则使用普通函数或对象文字。

您应该从本书中了解原型继承。

    //constructor of Human
    function Human(name, age, size, married) {
        this.n = name;
        this.a = age;
        this.s = size;
        this.m = married;
        this.printInformation = function() {
            return "Name: " + this.n + ", Age: " + this.a + ", Size: " + this.s +
                 ", Married: " + this.m;
        };
    }

    var human1 = new Human("Lenny Linux", 42, "142cm", false);
    window.alert(human1.printInformation());

因此, printInformation是一个很好的候选者,可以使用Human的原型来创建Human实例之间的共享方法。 当您定义Humanthis所有引用都将是一个对象文字,设置为幕后的空对象。 此外,在幕后,隐藏的_proto_属性被分配给对象,该对象实际上是对Human.prototype的对象引用。 因此,只要您不使Human.prototype成为对新对象的引用,那么Human所有实例都将具有与Human.protoype相同的函数指针。 所以,这是您想要提高效率的标准示例。

    //constructor of Human
    function Human(name, age, size, married) {
        this.n = name;
        this.a = age;
        this.s = size;
        this.m = married;
    };
    Human.prototype.printInformation = function() {
        return "Name: " + this.n + ", Age: " + this.a + ", Size: " + this.s +
            ", Married: " + this.m;
    };
    var human1 = new Human("Lenny Linux", 42, "142cm", false);
    window.alert(human1.printInformation());

在运行时,解释器将尝试在实例本身上找到printInformation ,在这种情况下将无法找到它。 因此,它将遵循_proto_链接。 它在那里找到它,因为Human.prototype.printInformation是一个函数。

这是有效的原因是因为所有实例都指向同一个对象: Human.prototype ; 然而,当你在this.method = function() {}this.method = function() {} ,每个实例都会获得一个分配给它的新函数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM