天天看点

4种用JavaScript创建对象的方法

4种用JavaScript创建对象的方法

英文 | https://medium.com/programming-essentials/4-ways-to-create-objects-in-javascript-ccb88772a61b

翻译 | 小爱

本文将介绍4种使用JavaScript构建对象的方法。具体方法如下:

  • Object literals
  • Object.create()
  • Classes
  • Factory Functions

1、Object literals

创建对象的最简单方法之一是创建对象文字语法。

示例如下:

const product = {
  name: 'apple',
  category: 'fruits',
  price: 1.99
}


console.log(product);      

JavaScript中的对象是键值对的动态集合。密钥始终是字符串,并且在集合中必须是唯一。该值可以是基元、对象甚至函数。

这是一个值是另一个对象的示例:

const product = {
  name: 'apple',
  category: 'fruits',
  price: 1.99,
  nutrients : {
   carbs: 0.95,
   fats: 0.3,
   protein: 0.2
 }
}      

该carbs属性的值是一个新对象。接下来检查我们如何访问该carbs属性。

console.log(product.nutrients.carbs);
//0.95      

简写属性名称​

考虑将属性值存储在变量中的情况。

const name = 'apple';
const category = 'fruits';
const price = 1.99;
const product = {
  name: name,
  category: category,
  price: price
}      

JavaScript支持速记属性名称。它允许我们仅使用变量名来创建对象。它将创建一个具有相同名称的属性。下一个对象文字与上一个相同。

const name = 'apple';
const category = 'fruits';
const price = 1.99;
const product = {
  name,
  category,
  price
}      

2、对象创建

JavaScript具有所谓的原型系统,该系统允许在对象之间共享行为。主要思想是创建一个具有常见行为的原型对象,然后在创建新对象时使用它。

原型系统允许创建从其他对象继承行为的对象。

原型通常用于存储方法,而不是数据。让我们创建一个原型对象,使我们可以添加产品并从购物车中获得总价。

const cartPrototype = {
  addProduct: function(product){
    if(!this.products){
     this.products = [product]
    } else {
     this.products.push(product);
    }
  },
  getTotalPrice: function(){
    return this.products.reduce((total, p) => total + p.price, 0);
  }
}      

请注意,这次属性的值 ddProduct是一个函数。我们还可以使用一种称为“简写方法”语法的较短形式来编写先前的对象。

const cartPrototype = {
  addProduct(product){ },
  getTotalPrice(){ }
}      

该cartPrototype是原型对象,保持在两种方法addProduct和getTotalPrice的共同行为。它可用于构建继承此行为的其他对象。

const cart = Object.create(cartPrototype);
cart.addProduct({name: 'orange', price: 1.25});
cart.addProduct({name: 'lemon', price: 1.75});
console.log(cart.getTotalPrice());
//3      

cartPrototype对象是原型cart的对象。cart有一个称为 __proto__该原型对象的隐藏属性。

cart.__proto__ === cartPrototype;
//true      

当我们在对象上使用该方法时,首先在对象本身而不是原型上搜索该方法。

this​

请注意,我们使用特殊的关键字来访问和修改名为this对象上的数据。

请记住,函数是JavaScript中行为的独立单元。它们不一定是对象的一部分。

当函数是对象的一部分时,它们将成为方法,并且它们需要一种方法来访问同一对象上的其他成员。this是函数上下文,并提供对同一对象的其他属性的访问。

Data

你可能想知道为什么我们没有在products原型对象本身上定义和初始化属性。

因为我们不应该那样做。原型应该用于共享行为,而不是数据。共享数据将导致在多个购物车对象上拥有相同的产品。请看下面的代码。

const cartPrototype = {
  products:[],
  addProduct: function(product){
      this.products.push(product);
  },
  getTotalPrice: function(){}
}
const cart1 = Object.create(cartPrototype);
cart1.addProduct({name: 'orange', price: 1.25});
cart1.addProduct({name: 'lemon', price: 1.75});
console.log(cart1.getTotalPrice());
//3
const cart2 = Object.create(cartPrototype);
console.log(cart2.getTotalPrice());
//3      

从cart1和cart2继承相同行为的cartPrototype对象,它们都共享相同的数据。如果我们不想要那个的话,这样就会导致出错。所以原型应该用于共享行为,而不是共享数据。

Classes

原型系统不是构建对象的常用方法。开发人员更熟悉在类之外构建对象。

类语法允许使用更熟悉的方式来创建共享共同行为的对象。它仍然在幕后创建相同的原型,但是语法更加清晰,我们还避免了先前与数据相关的问题。

该类提供了一个特殊的函数来定义每个对象(称为构造函数)所不同的数据。

这是使用sugar类语法创建的同一对象。

class Cart{
  constructor(){
    this.products = [];
  }


  addProduct(product){
    this.products.push(product);
  }


  getTotalPrice(){
    return this.products.reduce((total, p) => total + p.price, 0);
  }
}
const cart = new Cart();
cart.addProduct({name: 'orange', price: 1.25});
cart.addProduct({name: 'lemon', price: 1.75});
console.log(cart.getTotalPrice());
//3
const cart2 = new Cart();
console.log(cart2.getTotalPrice());
//0      

请注意,该类具有一个构造函数方法,该方法为每个新对象初始化了不同的数据。实例之间不共享构造函数中的数据。为了创建一个新实例,我们使用new关键字。

我认为大多数开发人员都应该清楚和熟悉该类语法。但是,它做类似的事情,它使用所有方法创建一个原型,并使用它来定义新对象。可以使用访问原型Cart.prototype。

cart.__proto__ === Cart.prototype;
//true      

事实证明,原型系统足够灵活,可以使用类语法。因此,可以使用原型系统对类系统进行仿真。

Private Properties

唯一的事情是products新对象的属性默认情况下是公共的。

console.log(cart.products);
//[{name: "orange", price: 1.25}
// {name: "lemon", price: 1.75}]      

我们可以使用哈希#前缀将其设为私有。

私有属性使用#name语法声明。#是属性名称本身的一部分,应用于声明和访问属性。这是一个声明products为私有财产的示例。

class Cart{
  #products
constructor(){
    this.#products = [];
  }


  addProduct(product){
    this.#products.push(product);
  }


  getTotalPrice(){
    return this.#products.reduce((total, p) => total + p.price, 0);
  }
}
console.log(cart.#products);
//Uncaught SyntaxError: Private field '#products' must be declared in an enclosing class      

Factory Functions

另一种选择是将对象创建为闭包的集合。

闭包是函数即使在外部函数执行后也可以从外部函数访问变量和参数的能力。看一下cart使用工厂功能构建的下一个对象。

function Cart() {
  const products = [];


  function addProduct(product){
    products.push(product);
  }


  function getTotalPrice(){
    return products.reduce((total, p) => total + p.price, 0);
  }


  return {
   addProduct,
   getTotalPrice
  }
}
const cart = Cart();
cart.addProduct({name: 'orange', price: 1.25});
cart.addProduct({name: 'lemon', price: 1.75});
console.log(cart.getTotalPrice());
//3      

addProduct和getTotalPrice是两个内部函数products从其父级访问变量。products父级Cart执行后,他们可以访问变量事件。addProduct和getTotalPrice两个关闭共享同一个私有变量。

Cart 是Factory 函数。

cart使用Factory函数创建的新对象具有products变量private。不能从外部访问它。

console.log(cart.products);
//undefined      

Factory 函数​不需要new关键字,但是你可以根据需要使用它。无论是否使用new运算符,它都将返回相同的对象。

最后的总结​

使用对象文字语法可以轻松地构建对象。

JavaScript提供了两种创新的方式来创建面向对象的对象。一种是使用原型对象共享常见行为。对象从其他对象继承。类提供了一种很好的语法来创建此类对象。

继续阅读