简体   繁体   English

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

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

I know a little bit Java and I like this whole classes and OO programming style. 我知道一点点Java,我喜欢这整个类和OO编程风格。 Well Im reading about JavaScript and I see there is no "classical" OO Style like in Java and C++ , not even a simple constructor. 好吧我正在阅读JavaScript,我发现没有像Java和C ++那样的“经典”OO风格,甚至不是简单的构造函数。 The programmer has a lot of choice. 程序员有很多选择。 Well I made this, what do you think about it. 好吧,我做了这个,你怎么看待它。 It is ok to code a constructor like that? 可以像这样编写构造函数吗?

//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());

Its working, so I think it could be ok. 它的工作,所以我认为它可以。 But there is a problem: I have other options too. 但是有一个问题:我也有其他选择。 Like to use these "object literals" or what theyr called. 喜欢使用这些“对象文字”或他们称之为。 I could do this: 我能做到这一点:

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

Well this one is faster is it? 那么这个更快呢? And after I got this written, there is an "object" of Human, the other one I have to initialize. 在我写完之后,有一个人类的“对象”,另一个我必须初始化。 But I like the other one more. 但我更喜欢另一个。 Its easier for me to overlook my code. 我更容易忽略我的代码。 But the first example is NOT typical JavaScript-like right? 但是第一个例子不是典型的JavaScript吗? So I have to forget everything about Java and use the special JavaScript style? 所以我必须忘记Java的一切并使用特殊的JavaScript风格? Or can I keep my Java Code style? 或者我可以保留我的Java代码风格吗? What do you think? 你怎么看?

PS: One other question to the first example. PS:第一个例子的另一个问题。 It drives me crazy that I cannot force the programmer if hes initializing the constructor to use only boolean if hes at the "married" variable. 它让我疯狂,我不能强迫程序员,如果他初始化构造函数只使用布尔值,如果他在“已婚”变量。 But i really want to force him. 但我真的想强迫他。 The same for Age: sould be only Integer... Any ideas? 年龄相同:只能是整数...任何想法?

Thank You! 谢谢!

The two approaches you describe are actually totally equivalent (other then the syntax) and are mostly ok from a Javascript point of view. 您描述的两种方法实际上完全等效 (除了语法之外),从Javascript的角度来看大多数都可以。 That said, you probably shouldn't choose what to do just based on what you are comfortable with now - in the long term you will need to get used to working with the language instead of against it. 也就是说,您可能不应该根据您现在所熟悉的内容选择做什么 - 从长远来看,您需要习惯使用语言而不是使用语言。 Moving on... 继续...

What if I want to force my fields to be a certain type, as in Java? 如果我想强制我的字段成为某种类型,如在Java中,该怎么办?

Javascript is dynamically typed so you will have a hard time trying trying to apply the same static typing paradigm. Javascript是动态类型的,因此您将很难尝试应用相同的静态类型范例。 You could try doing runtime checks (with typeof) during object constructor but that usually isn't worth the trouble since checking would still be at runtime, not checking would likely cause a similar error anyway and typeof is very limited (its tricky to check if something is an array, its annoying to check for interfaces and lets not get started on the "alien" browser objects...) 您可以尝试在对象构造函数中执行运行时检查(使用typeof),但这通常不值得,因为检查仍然在运行时,不检查可能会导致类似的错误,而且typeof非常有限(检查是否很棘手)东西是一个数组,它很烦人检查接口,让我们不要开始使用“外来”浏览器对象......)

In the end, don't get too stressed about the dynamic typing - you will get used to it soon enough. 最后, 不要过于强调动态类型 - 你会很快习惯它。

If you said that the object literal approach and the constructor function approach returned the same result, whats the difference then? 如果你说对象文字方法和构造函数方法返回相同的结果,那么差异是什么呢?

First of all, while object literals are a very neat piece of syntax, there are some things that need to be split over multiple statements so you kinda need a function for them: 首先,虽然对象文字是一个非常简洁的语法,但有些事情需要在多个语句中分开,所以你需要一个函数来实现它们:

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

Note that object literals can still be very useful here and it is very popular to use them to provide named and default parameters in cases that would normaly have large parameter lists: 请注意,对象文字在这里仍然非常有用,并且在通常具有大型参数列表的情况下使用它们来提供命名和默认参数非常受欢迎:

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

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

Remember: Up to this point, using a function to build the object vs an object literal is just a matter of style and organization and the best approach will generally depend on what particular case you are dealing with. 记住:到目前为止,使用函数来构建对象与对象文字只是风格和组织的问题,最好的方法通常取决于你正在处理的具体情况。 In my expirience, object literals are very nice for creating singletons and configuration dictionaries while functions are very useful for enforcing invariants in complex objects of offering a shorthand for common ones. 在我的经验中, 对象文字对于创建单例和配置字典非常有用,而函数对于在复杂对象中强制执行不变量非常有用,这些对象提供了常用的简写。

So what is the deal with "real" constructor functions, new and this then? 那么什么是“真正的”构造函数, 新的这个呢?

A disadvantage of explicitly contructing objects by hand is that we miss some of the OO goodness we are used to. 手工明确地构造对象的缺点是我们错过了我们习惯的一些OO善良。 By giving each object a copy of its methods not only do we waste space (in a classical language those would be stored in the class) but we lose differential inheritance (since everything is static). 通过给每个对象提供其方法的副本,我们不仅浪费空间(用经典语言存储在类中),而且我们失去差异继承(因为一切都是静态的)。 The way Javascript deals with this is with Prototypes . Javascript处理这个的方式是使用Prototypes All objects have a prototype and when looking for a property (or method) it is recursively searched for in the prototype in case it is not immediately found. 所有对象都有一个原型,当查找属性(或方法)时,如果没有立即找到它,则在原型中递归搜索。

A common use case of prototypes is making so that a class of objects keep their instance variables by themselves but share the methods: 原型的一个常见用例是使一类对象自己保留实例变量但共享方法:

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

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

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

This way we can access lenny.printInformation without even noticing that this method is being shared with Glenda. 这样我们就可以访问lenny.printInformation,甚至没有注意到这个方法正在与Glenda共享。

To create an object with a prototype you can either use Object.create (on newer browsers, at least) or the old way with constructor functions and the new operator: 要使用原型创建对象,您可以使用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);

Summing up 加起来

Use constructor functions and the new operator if you want to use the prototypal features of the language. 如果要使用该语言的原型功能,请使用构造函数和new运算符。

Use normal functions or object literals otherwise. 否则使用普通函数或对象文字。

You should read about prototypical inheritance from this book . 您应该从本书中了解原型继承。

    //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());

So, printInformation is a good candidate to throw on the prototype of Human to create a shared method between instances of Human . 因此, printInformation是一个很好的候选者,可以使用Human的原型来创建Human实例之间的共享方法。 When you defined Human , all of the references to this will be an object literal set to an empty object behind the scenes. 当您定义Humanthis所有引用都将是一个对象文字,设置为幕后的空对象。 Also, behind the scenes, a hidden _proto_ property is being assigned to the object that literally is an object reference to Human.prototype. 此外,在幕后,隐藏的_proto_属性被分配给对象,该对象实际上是对Human.prototype的对象引用。 Therefore, as long as you don't make Human.prototype a reference to a new object, then all instances of Human will have the same function pointer to Human.protoype . 因此,只要您不使Human.prototype成为对新对象的引用,那么Human所有实例都将具有与Human.protoype相同的函数指针。 So, here's the standard example of what you want for efficiency. 所以,这是您想要提高效率的标准示例。

    //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());

At runtime, the interpreter will try to find printInformation on the instance itself, and will not find it in this case. 在运行时,解释器将尝试在实例本身上找到printInformation ,在这种情况下将无法找到它。 So, it will follow the _proto_ link. 因此,它将遵循_proto_链接。 It finds it there, because Human.prototype.printInformation is a function. 它在那里找到它,因为Human.prototype.printInformation是一个函数。

The reason this is efficient is because all instances are pointing to the same object: Human.prototype ; 这是有效的原因是因为所有实例都指向同一个对象: Human.prototype ; whereas, when you say this.method = function() {} inside a constructor, each instance is getting a new function assigned to it. 然而,当你在this.method = function() {}this.method = function() {} ,每个实例都会获得一个分配给它的新函数。

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

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