原文: Objects in JavaScript – A Beginner's Guide

如果你声明多个变量来保存不同的值,这会使你的程序变得混乱和笨拙。

例如,如果你需要为 10 个人分别存储三个特征,则单独声明 30 个变量会使你的程序看起来不那么有条理。

因此,你需要一种方法将具有相似特征的值组合在一起,以使你的代码更具可读性。在 JavaScript 中,对象可以很好地用于此目的。

与其他数据类型不同,对象能够存储复杂值。因此,JavaScript 严重依赖它们。在深入学习 JavaScript 之前,熟悉什么是对象、如何创建对象以及如何使用它非常重要。

本文将向你介绍对象的基础知识、对象语法、创建对象的不同方法、如何复制对象以及如何迭代对象。

为了充分理解本文,你至少需要对 JavaScript 有基本的了解,尤其是变量、函数和数据类型。

JavaScript 中的对象是什么

对象是一种可以接收键值对集合的数据类型。

对象与 JavaScript 中的字符串和数字等其他数据类型的主要区别在于,对象可以存储不同类型的数据作为其值。另一方面,原始数据类型(如数字和字符串)只能分别存储数字和字符串作为它们的值。

键,也称为属性名称,通常是一个字符串。如果任何其他数据类型用作字符串以外的属性名称,它将被转换为字符串。

你可以将对象可视化为一个多功能架子,其中包含用于放置小工具和装饰品的空间以及用于存放书籍和文件的空间。

shelf1-2
一个架子,里面有几件物品

对象最容易识别的特征是包含键值对的括号。

const emptyObject = {};
console.log(typeof emptyObject); //'object'

对象的内容可以由变量、函数或两者组成。对象中的变量是属性,而函数是方法。方法允许对象使用其中的属性来执行某种操作。

例如,在下面的示例代码中,object1.user、object1.nationality 和 object1.profession 都是 object1 的属性,而 object1.myBio() 是一个方法:

const object1 = {
    user: "alex",
    nationality: "Nigeria",
    profession: "Software Enginneer",
    myBio() {
        console.log(`My name is ${this.user}. I'm a               ${this.profession} from ${this.nationality}`)
    }
}
console.log(object1.user); //Alex 
console.log(object1.nationality); //Nigeria 
console.log(object1.profession); //Software Engineer 
console.log(object1.myBio()); //My name is alex. I'm a Software Engineer from Nigeria

上面示例代码中的键是用户、国籍和职业,而它们的值是冒号后面的字符串值。另外,请注意 this 关键字的使用。 this 关键字只是指对象本身。

如本文前面所述,属性的值可以是任何数据类型。在以下示例代码中,值既是数组又是对象:

 const object2 = { 
        users: ["Alex", "James", "Mohammed"], 
        professions: { 
            alex: "software engineer", 
            james: "lawyer", 
            mohammed: "technical writer" 
        } 
    }; 
    console.log(object2.users); //['Alex', 'James', 'Mohammed'] 
    console.log(object2.professions); //{alex: 'software engineer', james: 'lawyer', mohammed: 'technical writer'}

如何在 JavaScript 中访问对象并创建新的对象属性或方法

访问对象有两种方法:点表示法和方括号表示法。在前面的示例代码中,我们使用点符号来访问 object1 和 object2 中的属性和方法。

此外,要在声明对象后创建新的属性和方法,可以使用点表示法或方括号表示法。你只需声明新属性并为其赋值。

例如,我们可以像这样向 object2 添加新属性:

object2.ages = [30, 32, 40];
object2["summary"] = `Object2 has ${object2.users.length} users`;
console.log(object2);
/*
{
    "users": [
        "Alex",
        "James",
        "Mohammed"
    ],
    "professions": {
        "alex": "software engineer",
        "james": "lawyer",
        "mohammed": "technical writer"
    },
    "ages": [
        30,
        32,
        40
    ],
    "summary": "Object2 has 3 users"
}
*/

同样,你可以使用任何一种表示法来更改对象的值:

object2.users = ["jane", "Williams", "John"];
object2["age"] = [20, 25, 29]
console.log(object2.users); //['jane', 'Williams', 'John']
console.log(object2.ages) //[20, 25, 29

尽管点表示法是最常用于访问对象的属性和方法的方法,但它也有一些限制。现在让我们看看它们。

你不能将值用作带有点表示法的属性名称

如果要将变量的值用作对象中的属性名称,则必须使用括号表示法而不是点表示法,不管变量值是否在运行时定义。

运行时是计算机程序的一个阶段,其中程序在计算机系统上运行或执行。

例如:

const object3 = {};
const gadget = prompt("enter a gadget type"); 
object3[gadget] = ["jbl", "sony"]; 
console.log(object3) //(respose entered in prompt): ["jbl","sony"] notice that the property name is the value you enter in the reply to the prompt message

如果你在代码中定义变量值,并使用点表示法将该值设置为对象的属性名称,则点表示法将使用变量名称而不是变量值创建一个新属性。

const computer = "brands"
object3.computer = ["hp", "dell", "apple"]
console.log(object3.brands); //undefined
console.log(object3.computer)//['hp', 'dell', 'apple']

object3[computer] = ["hp", "dell", "apple"]
console.log(object3.brands) //['hp', 'dell', 'apple']

注意方括号中引号的省略。这是因为括号接受了一个变量。

你不能将多字属性与点表示法一起使用

如果属性名称是多字字符串,则点表示法是不够的,例如:

object3.users height = [5.6, 5.4, 6.0];
Console.log(object3.users height); //SyntaxError

由于 JavaScript 将命令读取为 object3.users,因此出现语法错误,但无法识别字符串 height,因此返回语法错误。

当使用点符号访问对象时,声明变量的通常规则适用。这意味着如果要使用点符号来访问对象或创建属性,属性名称不能以数字开头,不能包含任何空格,并且只能包含特殊字符 $_

为了避免这种错误,你必须使用括号表示法。例如,你可以像这样更正上面的示例代码:

object3["users height"] = [5.6, 5.4, 6.0];  
console.log(object3["users height"]); //[5.6, 5.4, 6]

如何在 JavaScript 中使用对象构造函数创建对象

有两种方法可以创建对象:对象字面量和对象构造函数。到目前为止,本文中用作示例的对象都是对象字面量。如果你想创建单个对象,可以使用对象字面量。

但是如果你想创建多个对象,最好使用对象构造函数。这使你可以避免代码中不必要的重复,也可以更轻松地更改对象的属性。

基本上,构造函数是名称通常大写的函数。构造函数名称的大写对对象没有任何影响。它只是一种识别手段。

你可以使用构造函数通过使用 new 关键字调用构造函数来创建新对象。 new 关键字将创建一个对象的实例并将 this 关键字绑定到新对象。

正如本文前面提到的,this 关键字是对对象本身的引用。

对象构造函数的一个例子是:

function Profile(name, age, nationality) { 
    this.name = name; 
    this.age = age; 
    this.nationality = nationality; 
    this.bio = function () { 
        console.log(`My name is ${this.name}. I'm ${this.age} years old. I'm from ${this.nationality}`) 
    } 
};

const oladele = new Profile("Oladele", 50, "Nigeria" );
console.log(oladele.bio()); //My name is Oladele. I'm 50 years old. I'm from Nigeria

如何在 JavaScript 中创建对象副本

与字符串和数字等原始数据类型不同,将现有对象分配给另一个变量不会产生原始数据的副本,而是在内存中产生引用。

这意味着原始对象和通过将原始对象分配为值而创建的后续对象都在引用内存中的同一项目。

这意味着任何对象的值的变化也会导致其他对象的变化,例如:

let x = 10;
let y = x;
x = 20;
console.log(x); //20
console.log(y); //10

let object4 = { 
    name: "Alex", 
    age: 40 
}; 
let object5 = object4; 
console.log(object5); //{name: 'Alex', age: 40} 
object4.name = "Jane"; 
console.log(object5); //{name: 'Jane', age: 40}
console.log(object4 === object5); //true

要创建对象的副本,你可以使用扩展运算符。

什么是扩展运算符

扩展运算符由三个点 ... 表示。你可以使用扩展运算符复制任何可迭代对象的值,包括对象。

可迭代对象是可以在 for... 循环的帮助下循环或迭代的对象。可迭代的示例包括对象、数组、集合、字符串等。

要使用扩展运算符,你必须将其添加到要复制的对象的前缀,例如:

let object6 = {...object5}; 
object5.name = "Willaims"; 
console.log(object5); //{name: 'Willaims', age: 40}
console.log(object6); //{name: 'Jane', age: 40}
console.log(object5 === object6); //false

如你所见,与前面的代码示例不同,object4 的变化导致 object5 的变化,object6 的变化并没有导致 object5 的变化。

如何使用 Object.assign() 方法

Object.assign() 方法将一个对象的所有可枚举属性复制到另一个对象中,然后返回修改后的对象。

该方法接受两个参数。第一个参数是接收复制属性的目标对象,第二个参数是具有要复制的属性的源对象,例如 :

let object7  = Object.assign({}, object6); 
console.log(object7); //{name: 'Jane', age: 40}
console.log(object7); //{name: 'Jane', age: 40}

console.log(object6 === object7); //false
object6.age = 60
console.log(object6); //{name: 'Jane', age: 60}
console.log(object7); //{name: 'Jane', age: 40

从上面的示例代码可以看出,object6 的 age 属性值的改变并没有引起 object7 的 age 属性值的改变。

请注意,扩展运算符和 Object.assign() 方法都只能制作对象的浅拷贝。

这意味着,如果你的源对象中有深度嵌套的对象或数组,则只有对此类对象的引用会被复制到目标对象中。因此,任何深度嵌套对象的值的变化都会导致另一个深度嵌套对象的值发生变化,例如:

let objectX = {
    name: 'Mary', 
    age: 40,
    gadgets: { 
        brand: ["apple", "sony"]
    }
};

let objectY = {...objectX};
objectY.name = "Bianca";
objectY.gadgets.brand[0] = "hp";
console.log(objectX);
/*
{
    "name": "Mary",
    "age": 40,
    "gadgets": {
        "brand": [
            "hp",
            "sony"
        ]
    }
}
*/ 

console.log(objectY);
/*
{
    "name": "Bianca",
    "age": 40,
    "gadgets": {
        "brand": [
            "hp",
            "sony"
        ]
    }
}
*/

上面的示例代码执行了以下操作:

  • 创建了一个名为 objectX 的对象
  • 为 objectX 赋予三个属性:name、age 和 gadgets
  • 给 objectX 的 gadgets 属性一个对象作为它的值
  • gadget 属性的对象值赋予 brand 属性
  • 给 brand 属性一个数组作为它的值
  • 使用扩展运算符将 objectX 中的属性复制到 objectY 中
  • 将 objectY 的 name 属性的值更改为 Mary
  • 将 brand 属性的数组值中的第一项从 apple 更改为 hp

在示例代码中,数组值是一个深度嵌套的对象。请注意,objectY 的 name 属性值的更改不会导致 objectX 的 name 属性值的更改。但是 objectY 的深层嵌套对象的变化导致 objectX 的深层嵌套对象发生类似的变化。

如何在 JavaScript 中迭代对象

使用 for...in 循环遍历对象并选择其属性,语法如下:

for(let key in object) {
    //perform action(s) for each key
}

上面语法中的 key 关键字是属性的参数。因此,你可以用你选择的任何单词替换它。将 object 关键字替换为要迭代的对象的名称,例如:

let objectZ = {
    name: "Ade",
    Pronuon: "he",
    age: 60
};
for(let property in objectZ) {
    console.log(`${property}: ${objectZ[property]}`)
}
/* 
name: Ade
Pronuon: he
age: 60
*/

请注意在循环中使用括号表示法来获取属性的值。使用点表示法而不是括号表示法将 undefined

总结

在 JavaScript 中,对象可能是最重要的数据类型。像面向对象编程这样的编程概念的工作原理是利用对象的灵活性来存储复杂的值以及它们与对象内的属性和方法交互的独特能力。

本文通过解释对象的基础知识,为你理解这些高级概念奠定了坚实的基础。