【问题标题】:Javascript creating objects - multiple approaches, any differences?Javascript 创建对象 - 多种方法,有什么区别吗?
【发布时间】:2013-04-13 02:40:59
【问题描述】:

我已经看到了几种在 javascript 中实例化对象的不同方法,想知道各种方法的优缺点以及为什么要使用其中一种方法。

方法 1

var obj = {
    prop: value,
    .
    .
    .
}

方法一是标准方法,没什么新意:)

方法 2

var obj = new function() {
    var prop1 = value1;
    var fn1 = function() {
    };
    .
    .
    .

    this.prop2 = value2;
    .
    .
    .
}();

函数方式,我想把这个方式和方式3比较一下。函数方式主要用于封装(对吗?)

方法 3

var obj = (function() {
    var prop1 = value1;
    var fn1 = function() {
    };
    .
    .
    .

    return {
        prop2: value2,
        .
        .
        .
    }
})();

使用这种方法,我不太明白其使用背后的原因。它与方法 2 有何不同?两者都可以用来封装逻辑。

这样我们可以传入参数,以便我们可以处理任何潜在的冲突吗?例如 jquery 的 $ 语法 - 但您也可以使用方法 2...

谢谢。


编辑:


我知道方法 1 和 3 是相似的(因为它们都返回对象)但是方法 3 也创建了一个闭包。哪种方法 2 也可以。

这确实是我的问题的基础,2 和 3 都会创建闭包,但它们之间有什么区别。

【问题讨论】:

  • 在方法 2 中不应出现 new 关键字。
  • @FritsvanCampen - 是的,应该。这会从(匿名)构造函数创建一个新对象。
  • 如果new 关键字不存在,它将是一个类。
  • 第二种方法应该有()操作符
  • @KamyarNazeri - 不,new 运算符负责调用函数。

标签: javascript javascript-objects


【解决方案1】:

我一直在使用 JS 并想发布一些答案,我希望它也可以帮助其他人:

1) Object Literal :您在创建对象时将其写出

var person = {
  name: ['Bob', 'Smith'],
  age: 32,
  gender: 'male',
  interests: ['music', 'skiing'],
  bio: function() {
    alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
  },
  greeting: function() {
    alert('Hi! I\'m ' + this.name[0] + '.');
  }
};

用途:当你想将数据传输到服务器时

2) 构造函数: 当你想创建多个相同的对象时,你可以使用构造函数。

function Vehicle(name, maker) {
  this.name = name;// Every function while executing has a reference         
            this.maker = maker;// to its current execution context called as this
}
let car1 = new Vehicle(’Fiesta’, 'Ford’);// New keyword with function turns function call into constructor call
let car2 = new Vehicle(’Santa Fe’, 'Hyundai’);

console.log(car1.name);    //Output: Fiesta
console.log(car2.name);    //Output: Santa Fe

3) 使用 create 方法创建 Javascript 对象

Object.create() 允许创建具有更多属性选项的对象,例如值、可配置、可枚举和可写。 创建一个新对象,扩展作为参数传递的原型对象

let car = Object.create(Object.prototype,{
   name:{
     value: 'Fiesta',
     configurable: true,
     writable: true,
     enumerable: false
   },
   maker:{
     value: 'Ford',
     configurable: true,
     writable: true,
     enumerable: true
   }});
console.log(car.name)    //Output: Fiesta

原型: 每个对象都是由构造函数构建的。 构造函数使对象链接到自己的原型 原型是构造函数和对象之间的任意链接。

4) 使用 ES6 类创建 Javascript

class Vehicle {
 constructor(name, maker, engine) {
   this.name = name;
   this.maker =  maker;
   this.engine = engine;
 }
}

let bike1 = new Vehicle('Hayabusa', 'Suzuki', '1340cc');
let bike2 = new Vehicle('Ninja', 'Kawasaki', '998cc');

console.log(bike1.name);    //Output: Hayabusa
console.log(bike2.maker);   //Output: Kawasaki

5) 使用对象构造函数

var d = new Object();

创建空对象的最佳方式。

注意:我已经编译了这个链接https://codeburst.io/various-ways-to-create-javascript-object-9563c6887a47的大部分内容

【讨论】:

    【解决方案2】:

    在 JavaScript 中创建对象的 7 种方法:

    1.对象构造函数

    创建对象最简单的方法是使用 Object 构造函数: 查看普通版?

    var person = new Object();  
    person.name = "Diego";  
    person.getName = function(){  
        return this.name;  
    }; 
    

    2。字面符号

    查看普通打印?

    var person = {  
        person.name : "Diego",  
        person.getName : function(){  
            return this.name;  
        }  
    } 
    

    3.工厂函数

    Factory 函数允许封装和重用创建类似对象的逻辑。它为此利用了任何先前的构造。 任何一个: 查看普通版?

    var newPerson=function(name){  
        var result = new Object();  
        result.name = name;  
        result.getName = function(){  
            return this.name;  
        };  
        return result;  
    };  
    var personOne = newPerson("Diego");  
    var personTwo = newPerson("Gangelo");  
    console.log(personOne.getName()); // prints Diego  
    console.log(personTwo.getName()); // prints Gangelo
    

    或者:

    view plainprint?
    var newPerson=function(name){  
        return {  
            person.name : name,  
            person.getName : function(){  
                return this.name;  
            };  
    };  
    var personOne = newPerson("Diego");  
    var personTwo = newPerson("Gangelo");  
    console.log(personOne.getName()); // prints Diego  
    console.log(personTwo.getName()); // prints Gangelo  
    

    4.函数构造器

    在 Javascript 中,可以调用前面带有 new 运算符的任何函数。 给定一个函数 F,对于 new F(): 创建了一个新的空对象 X。 X 被设置为 F 的上下文,在整个 F 中都指向 X。 X 作为 F 的结果返回 查看普通版?

    function Person(name){  
            this.name = name;  
            this.getName = function(){  
                return this.name;  
            };  
    };  
    var personOne = new Person("Diego");  
    console.log(personOne.getName()); // prints Diego  
    console.log(personOne instanceOf Person); // prints true  
    console.log(personOne.constructor === Person); // prints true  
    console.log(personOne instanceOf Object); // prints true  
    

    5.原型

    函数在 Javascript 中非常特殊。它们是对象,它们可以创建其他对象,并且它们会自动获得一个名为原型的字段。 原型是具有单个字段的普通对象,称为构造函数,指向函数本身。 它的特别之处在于,通过函数创建的每个对象都继承了函数的原型。 查看普通版?

    function Person(){};  
    Person.prototype.name = "Diego";  
    var personOne = new Person();  
    var personTwo = new Person();  
    console.log(personOne.constructor == Person); // prints true  
    console.log(personOne.name); // prints Diego  
    console.log(personTwo.constructor == Person); // prints true  
    console.log(personTwo.name); // prints Diego  
    

    6.功能/原型组合

    正如您想象的那样,功能/原型组合利用了这两种方法 :) 查看普通版?

    function Person(name){  
            this.name = name;  
    };  
    Person.prototype.getName = function(){  
                return this.name;  
            };  
    var personOne = new Person("Diego");  
    var personTwo = new Person("Filippo");  
    console.log(personOne.getName()); // prints Diego  
    console.log(personTwo.getName()); // prints Filippo  
    console.log(personOne.getName === personTwo.getName) //prints true 
    

    7.单身人士

    有时,您可能希望确保某个类只存在一个实例。 在 Javascript 中获取 Singleton 就像同时定义和调用构造函数一样简单: 查看普通版?

    var singleton = new function(){  
        this.name = "ApplicationName";  
    };  
    

    【讨论】:

    • “查看普通打印”是什么意思?甚至是什么意思?
    【解决方案3】:

    还有:

    var obj = Object.create({prop: ...});
    

    这是通过设置原型来实现的。如果要让多个对象共享属性或方法,使用原型会更有效。

    var proto = {foo: function() {}},
        obj1 = Object.create(proto),
        obj2 = Object.create(proto),
        obj3 = {foo: function() {}},
        obj4 = {foo: function() {}};
    

    在这个例子中,obj1 和 obj2 共享一个在“proto”中定义的“foo”函数。同时,obj3 和 obj4 都有自己的“foo”。如果您要创建具有大量属性的大量对象,这可能会对内存消耗甚至性能产生很大影响。

    如果您使用命名函数并在使用 new 之前将属性分配给函数的原型(例如:f.prototype.prop),则可以通过使用“new”关键字来共享此好处。

    【讨论】:

      【解决方案4】:

      在方法#2 和#3 中,结果对象的constructor 属性将不同。

      实际上,这意味着第二种方法允许您使用匿名构造函数实例化多个对象:

      x = new function() { alert(1) };
      y = new x.constructor; // shows the message too
      

      Module pattern vs. instance of an anonymous constructor 的最佳答案包括 Douglas Crockford 的一句话,他解释了为什么他认为方法 #3 优于 #2。

      【讨论】:

      • 不错。我没想到constructor 属性。
      【解决方案5】:

      第一种和第三种方法几乎相同,在某种程度上它们都创建了一个对象字面量,它是Object 类的直接子代。它们之间的区别在于,在第三种方法中,您可能对属性进行了某种封装:

      var obj = (function() {
          var prop = {};
      
          return {
              prop2: function(){ return prop };
          }
      })();
      

      就性能而言,您可能会认为第三种方法会创建闭包,而第一种则不会!

      但是,在第二种方法中,您只是从一个匿名类创建一个新对象,该类不是Object 类的直接子类。

      第二种方法的正确形式是这样的(至少这是 ecma 标准):

      var obj = new function() {
          var prop1 = value1;
      
          this.prop2 = value2;
      }();
      

      方法 2 和 3 的区别仅在于它们的继承链: (假设 obj2 来自第二种方法,obj3 来自第三种方法)

      obj2.__proto__ == Object.prototype;  // false
      obj3.__proto__ == Object.prototype;  // true
      

      obj2 是从一个匿名类本身创建的:

      obj2.__proto__.__proto__ == Object.prototype;  // true (there's 2 level of inheritance here)
      

      【讨论】:

      • “直子”是什么意思?
      • 任何对象字面量都直接从Object.prototype 继承,这使其成为Object 类的直接子级:obj.__proto__ == Object.prototype
      【解决方案6】:

      对于一次性对象,方法 2 和 3 之间没有太大区别。 (如果您要命名方法 2 中使用的函数,您将定义一个可重用的构造函数。)我的印象是方法 3 更常用于这些情况,但我看不出它们之间有很大的区别。

      需要注意的是,方法 2 和 3 都可以带参数:

      var approach2Obj = new function(formalArg) {
          var privateProp = ...;
          this.publicProp = ...;
          // more constructor logic
      )(actualArg);
      
      var approach3Obj = (function(formalArg) {
          var privateProp = ...;
          // more creation logic
          return {
              publicProp : ...;
          };
      }(actualArg));
      

      附:作为@Alexey Lebedev points out in his answer,两者之间的一个区别(也许是唯一的一个)是approach2Obj.constructorapproach3Obj.constructor 会有所不同。 approach3Obj.constructor 将等同于 Object,而 approach2Obj.constructor 将是匿名函数。

      【讨论】:

      • 对不起,prop1 是用来表示私有变量的。函数的逻辑可以继续并使用这些变量...我会更新以反映这一点
      • @Umair - 我认为我的答案没有改变。方法 2 和 3 基本上是等价的。
      【解决方案7】:

      您的问题应该是 2 种方法,因为 方法 3方法 1 完全一样,只是通过自我执行功能创建的方法。

      关于制作像 方法 1 这样的对象时的区别,您可以将其视为像 java 中只有静态函数的对象。所以它总是活着的,你不会用它来创建实例(类似于单例) - 所以当你创建这个对象时:

      var obj = {
          prop: value,
          func: function(){
           alert(this.prop);
          }
      };
      

      您可以立即调用它:

      obj.prop = 'something else';
      obj.func();
      

      方法 2(没有新的,就像您得到的评论一样)是一个经典对象,您可以创建实例 - 使继承(使用 js“技巧”)等等:

      function Person(firstName,lastName){ // or var Person = function(...
         this.firstName = firstName;
         this.lastName= lastName;
      
         this.getFullName = function(){
            return this.firstName + ' ' + this.lastName;
         }
      }
      
      //use
      var person1 = new Person('yair','lapid');
      var person2 = new Person('Naftali','Bennet');
      
      you can put it in an array etc...
      var arr = [person1,person2, new Person('shelly','yekimovits')];
      

      【讨论】:

      • 方法 3 创建一个闭包;方法1没有。这使它们完全不同。
      • 但这不是问题——你也可以调用返回对象的常规函数​​或返回对象的飞机——他询问创建对象的差异——这不是正确的定义顺便说一句……
      【解决方案8】:

      方法 1
      这是一个单一的对象,没有类,如果它很复杂,你不能定义更简单

      var obj = {
         prop: value
      }
      

      方法 2
      一个非匿名函数。它将从一个“类”中创建一个对象,通常该函数被保存为一个类名,并且可以轻松地创建多个相同类型的对象,如下所示:

      var Bycicle= function() {
          var prop1 = value1;
      
          this.prop2 = value2;
      }
      var obj1 = new Bycicle(),
          obj2 = new Bycicle();
      

      方法 3
      一个匿名函数,来自函数外部的变量不能干扰函数内部的变量:

      var a = 10;
      var obj = (function() {
          alert(a); // Alerts undefined
          var prop1 = value1;
          alert(prop1); // alerts the value of value1
          return {
              prop2: value2;
          }
      })(); // Within the () you can pass arguments to the anonymous function.
      

      关于匿名函数的更多信息:http://helephant.com/2008/08/23/javascript-anonymous-functions/

      其他方法
      还有一个Object.create() 和一个new Object() 来创建新的对象,它们都和方法一一样。

      结论
      最后,除了第 3 个对象之外,对象将始终相同,因为它是匿名的。

      【讨论】:

        【解决方案9】:

        为了理解方法 2,读者需要了解一些有关新关键字工作方式的技术性知识。具体来说,它实际上会将匿名函数作为构造函数调用,而不是实例化一个新的函数对象并将其转储到 obj 变量中。

        为了理解方法 3,读者只需要理解 IIFE 模式。在过去的两年中,这种模式在 javascript 代码中变得非常普遍,这可能就是该版本更常用的原因。

        两个版本都用于产生封装,并且两个版本都需要了解复杂的语言特征才能理解。然而,方法三所需的语言特征比理解方法二所需的语言特征更常见。这就是为什么方法三在野外更常用的原因。

        【讨论】:

        • 一位同事曾经从匿名构造函数中删除了new 关键字,因为他认为这是一个错字。
        猜你喜欢
        • 2017-05-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-14
        • 1970-01-01
        • 2019-08-16
        • 1970-01-01
        • 2021-03-25
        相关资源
        最近更新 更多