【问题标题】:What is the difference between an object and an object from a class in JavaScript?JavaScript中的对象和类中的对象有什么区别?
【发布时间】:2020-02-06 13:59:04
【问题描述】:

我在工作和学校学习 JavaScript 和 Java。据我所知,在 Java 中,您总是有一个类,并且您可以从该类创建对象。在 JavaScript 中同样有效,但是:在 JavaScript 中,可以创建没有类的对象。

所以我的问题是:这两种对象在 JavaScript 中有什么区别?

class Test {
    say() {
        console.log("I'm a test.");
    }
}

let TestFromClass = new Test();

let TestFromObject = {
    say() {
        console.log("I'm also a test.");
    }
};


TestFromClass.say();    // Output: I'm a test.
TestFromObject.say();   // Output: I'm also a test.

现在我想知道它们是否有区别,或者我们是否真的需要 JavaScript 中的类。

【问题讨论】:

  • 只是语法糖
  • 与其说它们之间的区别,不如说在什么情况下应该使用哪一个。如果您要创建一堆实例,则使用类很有用。第二个,对象字面量,基本上是一个单例,用于将东西组合在一起。

标签: javascript class inheritance javascript-objects


【解决方案1】:

当您使用new 时,您构造了一个新对象,其内部原型是类的原型。例如:

class Test {
    say() {
        console.log("I'm a test.");
    }
}

let TestFromClass = new Test();
console.log(Object.getPrototypeOf(TestFromClass) === Test.prototype);

这在您需要创建多个对象时很有用。通常,创建此类对象是因为它们将具有与每个单独对象关联的某种状态,通常以对象属性的形式(例如,一个人对象可能有一个nameage 属性)。

但是,如果您没有与实例关联的任何数据(在您的示例中为 TestFromClass 对象),那么拥有实例根本没有多大意义。

如果您只想将命名函数收集到数据结构中,您的TestFromObject 比类更有意义。

也就是说,您可能希望拥有一个与其相关联的函数(如 say)的类,这些函数与其数据的实例没有任何关系,同时能够创建一个实例,也许可以使用原型上的其他方法。这并不少见,是通过制作与实例无关的函数static

class Person {
  static canEat() {
    return ['apples', 'bananas', 'carrots'];
  }
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}
const p = new Person('Bob', 99);
console.log(p.name);
console.log(Person.canEat());

【讨论】:

  • 感谢您的详细回答!你知道TestFromObject的UML怎么写吗?既然没有继承?
  • @Dop4miN - TestFromObject 确实有继承。正如我在回答中所描述的,它继承自 Object.prototype。创建没有继承的对象的唯一方法是var thisHasNoPrototype = Object.create(null);
  • @T.J.Crowder - 老实说,我之前不太明白你的回答,抱歉。
  • @Dop4miN - :-) 不用担心,我可能推断出你对 JS 的了解比你还多(或者我可能错了)。 this search 中列出的各种问题和答案可能会有所帮助。编码愉快!
  • @T.J.Crowder - 你说得对,我实际上对 OOP 还是很陌生。感谢您的清单! :)
【解决方案2】:

JavaScript 中的对象和类中的对象有什么区别?

实际上没有一般意义上的。不过,有些事情可能看起来有点像差异:

  • 当您使用文字语法创建对象时,除非您使用特殊的__proto__ 属性(仅限官方浏览器),否则其原型将始终为Object.prototype。当您使用new X 创建它时,如果X 是使用class 语法创建的构造函数,则结果将具有原型X.prototype
  • 在对象字面量中定义的方法直接放在对象上。 class X 中的方法继续对象继承X.prototype(非static)。

【讨论】:

  • 好的,我已经阅读了一些关于 JavaScript 原型的内容。那么当它在__proto__property 内部而不是在对象本身内部时,方法的使用有什么不同吗?
  • @Dop4miN 明确一点:您的意思是当它们在原型中时,而不是在对象本身中。 (你最好假装__proto__ 属性不存在。想想对象的原型。)大多数时候在使用上没有任何真正的区别。当然,原型上的那些是与其他实例共享的,但这通常没有任何区别。
【解决方案3】:

首先,类(几乎)只是原型的语法糖:

// The class way
class Test {
  say() {
    console.log("I'm a test.");
  }
}


// The old fashioned way
function Test() {

}

Test.prototype.say = function () {
  console.log("I'm a test.");
};

这两种情况下直接创建对象的区别在于方法属于原型,而不是直接属于对象。

当您使用TestFromClass.say() 时,它会通过原型链找到say 方法,而TestFromObject 直接拥有该方法。

除此之外,没有区别。

【讨论】:

  • 那么TestFromObject.say() 更快吗?
  • 我做了一个小测试,看起来是这样的。不过,您可能应该忽略这个事实。应该没关系。另一方面,如果你实例化数千个对象,原型方式将更节省内存,因为只有函数说而不是一千个
  • 确实如此。感谢您的测试和您的回答!
【解决方案4】:

对象有两种形式:声明(文字)形式和构造形式。

对象的文字语法如下所示:

var myObj = {
    key: value
    // ...
};

构造的表单如下所示:

var myObj = new Object();
myObj.key = value;

构造形式和文字形式产生完全相同的对象。唯一的区别是您可以在字面量声明中添加一个或多个键/值对,而对于构造形式的对象,您必须一个接一个地添加属性。

注意:使用“构造形式”来创建刚刚显示的对象是非常罕见的。您几乎总是希望使用文字语法形式。大多数内置对象也是如此。

P.S. 要了解更多详细信息,请访问 https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/this-object-prototypes/ch3.md

【讨论】:

    【解决方案5】:

    所以您创建了一个名为Test 的类,它是基类。您添加了一个名为 say() {} 的方法。

    class Test {
        say() {
            console.log("I'm a test.");
        }
    }
    

    然后您在下面创建了Test 类的实例:

    let TestFromClass = new Test();
    

    在下面,您创建了一个名为 TestFromObject 的纯 JavaScript 对象:

    let TestFromObject = {
        say() {
            console.log("I'm also a test.");
        }
    };
    

    是的,他们都会打印出你对他们方法的输出:

    TestFromClass.say();    // Output: I'm a test.
    TestFromObject.say();   // Output: I'm also a test.
    

    在您充分利用所创建类的全部功能之前,差异不会开始,例如,像这样利用 cconstructor() 函数:

    class Test {
        constructor() {
    
        }
        say() {
            console.log("I'm a test.");
        }
    }
    

    现在,当我们使用 new 关键字作为类名时,会自动为我们调用构造函数。使用您知道的构造函数也可以访问this,如下所示:

    class Test {
        constructor() {
          this.type = 'test';
        }
        say() {
            console.log("I'm a test.");
        }
    }
    

    这允许您这样做:

    TestFromClass.say();    // Output: I'm a test.
    TestFromObject.say();   // Output: I'm also a test.
    TestFromClass.type;     // Output: test
    

    构造函数传统上用于在类或类的特定实例中进行一些初始设置。

    构造函数通常在创建类的新实例时使用一些参数。也许您想指定您创建的 Test 类有 50 个问题。您可以像这样将一个对象传递给新的 Test 实例:

    let TestFromClass = new Test({ questions: 50 });
    

    您可以随意调用此对象,我们只需调用对象examination,您可以将问题数设置为此examination 对象。

    所以现在你将该对象传递给构造函数并调用该对象,examination,如下所示:

    class Test {
        constructor(examination) {
          this.questions = examination.questions;
          this.type = 'test';
        }
        say() {
            console.log("I'm a test.");
        }
    }
    
    let TestFromClass = new Test({ questions: 50 });
    
    TestFromClass.say();    // Output: I'm a test.
    TestFromClass.type;     // Output: test
    TestFromClass.questions; // 50
    

    您可以对类对象做的另一件事是创建一个可以扩展基类功能的子类,然后您还可以向它添加一些自定义功能。

    class Test {
        constructor(examination) {
          this.questions = examination.questions;
          this.type = 'test';
        }
        say() {
            console.log("I'm a test.");
        }
    }
    
    class Quiz extends Test {
    
    }
    

    所以现在您的测验继承了 Test 类中的所有方法、函数、属性等,并在其中定义了其他方法。

    class Test {
        constructor(examination) {
          this.questions = examination.questions;
          this.type = 'test';
        }
        say() {
            console.log("I'm a test.");
        }
    }
    
    class Quiz extends Test {
        constructor(examination) {
        this.topic = examination.topic;
      }
    }
    

    所以现在为了确保父类的构造函数也被调用,我可以在构造函数中使用super()关键字:

    class Test {
        constructor(examination) {
          this.questions = examination.questions;
          this.type = 'test';
        }
        say() {
            console.log("I'm a test.");
        }
    }
    
    class Quiz extends Test {
        constructor(examination) {
        super(examination)
        this.topic = examination.topic;
      }
    }
    

    然后你可以像这样实例化那个子类:

    const javascript = new Quiz({topic: 'javascript', questions: 50 });
    

    最后打印出来:

    javascript.questions; // Output: 50
    

    【讨论】:

      猜你喜欢
      • 2011-09-23
      • 2016-10-27
      • 2020-09-28
      • 2010-10-01
      • 1970-01-01
      • 2021-07-27
      • 1970-01-01
      • 2011-03-27
      相关资源
      最近更新 更多