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

Gol*_*lem 4 javascript oop constructor

我知道一点点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());
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

谢谢!

hug*_*omg 5

您描述的两种方法实际上完全等效(除了语法之外),从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);
Run Code Online (Sandbox Code Playgroud)

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

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

var x  = create_human({
    name: 'Lenny',
    age: 42,
    //...
});
Run Code Online (Sandbox Code Playgroud)

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

那么,什么是"真实"的构造函数,处理新的这个呢?

手工明确地构造对象的缺点是我们错过了我们习惯的一些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: ...
Run Code Online (Sandbox Code Playgroud)

这样我们就可以访问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);
Run Code Online (Sandbox Code Playgroud)

加起来

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

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