javascript

时间:2015-08-13 01:45:35

标签: javascript

在此代码中,

obj1 = { // this is a car object
    make:  "Eagle"
    model: "Talon TSi"
    year:  1993
}

f = function(make, model, year){
    this.make = make;
    this.model = model;
    this.year = year;
}

如果我需要覆盖functionwindow['Object']['toString]的{​​{1}}类型对象obj1,那么我会说,

f

 obj1.toString = 'something';

在此,我看到,此处 f.prototype.toString = 'something'; //and then 'new f()' to create car object obj1是同一f类型对象(function)的子项,但window['Object']属性仅针对prototype类型对象Function引入,但不针对f类型对象Object

为什么引入/要求obj1属性覆盖使用prototype类型对象而不是Function类型对象?

注意:Javascript中的初学者

1 个答案:

答案 0 :(得分:1)

  

为什么要引入/需要使用原型属性来覆盖使用   函数类型对象但不是对象类型对象?

原型就像一个模板,将用于将来创建对象。它与构造函数一起使用,它将使用new运算符创建新对象。因此,如果要修改从特定构造函数创建的所有对象,则修改该构造函数的prototype

这与仅修改已创建的现有对象不同。要仅修改该对象,您可以直接修改对象本身,而不是原型。

因此,是否修改原型的对象本身取决于您希望发生什么类型的更改。要修改已创建的对象的单个实例,只需直接修改该对象,而不是原型。要修改从给定构造函数创建的所有对象,请修改原型。

您可以修改原型以更改对象,但是当您这样做时,您将修改所有对象,而不仅仅是一个实例。修改像Object原型这样的通用原型通常被认为是有风险的,除非您只是为已经标准化的方法添加polyfill。无论是仅修改实例还是创建自己的具有所需功能的派生对象都会更安全。

此外,toString()是一个函数,而不是一个被称为函数并返回字符串的字符串。为了与现有设计兼容,您需要遵循相同的方案。

您的obj对象是对象的特定实例。要修改它,您可以直接修改该对象。它在内部有一个原型,但是如果你修改它,你将修改从同一个原型制作的所有对象,而不仅仅是修改这个对象。有时这是你的目的,但在这种情况下,你似乎只是试图修改obj1,而不是其他对象。



    var obj1 = { // this is a car object
        make:  "Eagle",
        model: "Talon TSi",
        year:  1993
    }

    obj1.toString = function() {return "something";}

    document.write(obj1.toString());




而且,对于你的函数f,因为它是一个构造函数,你可以在原型上设置.toString方法,它将影响用该构造函数创建的所有对象。



f = function(make, model, year){
    this.make = make;
    this.model = model;
    this.year = year;
}

f.prototype.toString = function() {return "something else"}


document.write(new f("ford", "f", 2015).toString());




请记住,修改将从中创建新对象的构造函数的原型和修改已创建的对象的现有实例之间存在差异。你必须知道哪种类型的oepration是合适的,并且取决于它。

由于您似乎仍然对定义属性的位置感到困惑,因此这里有一些指导原则:

  1. 如果它是一个单独运行的函数,并且不需要任何操作的实例(类似Date.now()),那么这就是一个静态函数(它没有& #39; t对某种类型的对象的实例进行操作,并且不要求任何人先前创建了某个对象,然后才能使用它),然后它是静态的,它应该以静态方式定义或者作为其自身的全局函数,例如parseInt()或命名空间的全局函数,例如Date.now()

  2. 如果它是一个在对象实例上运行的函数,并且它应该像obj.func1()一样被调用,那么你可以在原型上定义它,也可以分配它它到构造函数中的对象。通常的方案是在原型上定义它,因为这提供了一些优点。使用原型和在构造函数中分配方法之间的争论是一个完全不同的主题,它是主题或许多其他帖子和线程。我对这次辩论的看法是使用prototype,除非你有特殊的理由不这样做(这种理由很少见)。

  3. 如果它是一个不属于任何特定对象实例的静态数据值(例如用于自动递增ID值的计数器),那么它应该被定义为变量在私有闭包中或作为静态对象的属性,而不是在任何原型上。

  4. 如果它是一个实例数据变量,只存在于特定类型对象的实例上,则在构造函数中为其分配初始值。您通常不希望将其放在原型上,因为原型上的属性由所有实例共享,而不是您想要的"实例"变量

  5. 如果它是未分配给此类型的所有对象的实例数据变量,但有时仅分配给该对象,则可以在该对象的某个方法中指定它与this.someProp = "foo";中一样,或者可以在obj1.someProp = "foo";中的任何方法之外分配。不是,这种一次性财产不像其他类型那么常见。通常,给定类型的所有对象都有一个共同的属性和方法列表。

  6. 所以,这是一个总体的例子:

    // constructor function
    function myObj(parm1) {
        // initialize a couple properties of instance data
        this.data = parm1;
        this.status = "closed";
    }
    
    // define static properties
    myObj.openCounter = 0;
    myObj.debug = false;
    
    // define a static method
    myObj.log = function(msg) {
        if (myObj.debug) {
            console.log.apply(console, arguments);
        }
    };
    
    // define instance methods on the prototype
    myObj.prototype = {
        isOpen: function() {
           return this.status === "open";
        },
        open: function() {
            // do something to open the object
            ++myObj.openCounter;
            this.status = "open";
            myObj.log("opening: ", this);
        },
        close: function() {
            // do something to close the object
            this.status = "closed";
            myObj.close("closing: ", this);
        }
    
    };