图解 JavaScript 对象(上)

简介: 图解 JavaScript 对象

640.png


对象


正如我们在 数据类型[1] 一章学到的,JavaScript 中有七种数据类型。有六种原始类型,因为他们的值只包含一种东西(字符串,数字或者其他)。


相反,对象则用来存储键值对和更复杂的实体。在 JavaScript 中,对象几乎渗透到了这门编程语言的方方面面。所以,在我们深入理解这门语言之前,必须先理解对象。

我们可以通过使用带有可选 属性列表 的花括号 {…} 来创建对象。一个属性就是一个键值对("key: value"),其中键(key)是一个字符串(也叫做属性名),值(value)可以是任何值。


我们可以把对象想象成一个带有签名文件的文件柜。每一条数据都基于键(key)存储在文件中。这样我们就可以很容易根据文件名(也就是“键”)查找文件或添加/删除文件了。

640.png

我们可以用下面两种语法中的任一种来创建一个空的对象(“空柜子”):


let user = newObject(); // “构造函数” 的语法
let user = {};  // “字面量” 的语法

640.png

通常,我们用花括号。这种方式我们叫做字面量


文本和属性


我们可以在创建对象的时候,立即将一些属性以键值对的形式放到 {...} 中。


let user = {     // 一个对象
  name: "John",  // 键 "name",值 "John"
  age: 30// 键 "age",值 30
};


属性有键(或者也可以叫做“名字”或“标识符”),位于冒号 ":" 的前面,值在冒号的右边。


user 对象中,有两个属性:

  1. 第一个的键是 "name",值是 "John"
  2. 第二个的键是 "age",值是 30

生成的 user 对象可以被想象为一个放置着两个标记有 "name" 和 "age" 的文件的柜子。

640.png

我们可以随时添加、删除和读取文件。


可以使用点符号访问属性值:


// 读取文件的属性:
alert( user.name ); // John
alert( user.age ); // 30


属性的值可以是任意类型,让我们加个布尔类型:


user.isAdmin = true;

640.png

我们可以用 delete 操作符移除属性:


delete user.age;

640.png

我们也可以用多字词语来作为属性名,但必须给它们加上引号:


let user = {
  name: "John",
  age: 30,
  "likes birds": true// 多词属性名必须加引号
};

640.png

列表中的最后一个属性应以逗号结尾:


let user = {
  name: "John",
  age: 30,
}


这叫做尾随(trailing)或悬挂(hanging)逗号。这样便于我们添加、删除和移动属性,因为所有的行都是相似的。


方括号


对于多词属性,点操作就不能用了:


// 这将提示有语法错误
user.likes birds = true


这是因为点操作需要的键是一个有效的标识符,不能有空格和其他的一些限制。

有另一种方法,就是使用方括号,可用于任何字符串:


let user = {};
// 设置
user["likes birds"] = true;
// 读取
alert(user["likes birds"]); // true
// 删除
delete user["likes birds"];


现在一切都可行了。请注意方括号中的字符串要放在引号中,单引号或双引号都可以。

方括号同样提供了一种可以通过任意表达式来获取属性名的方法 —— 跟语义上的字符串不同 —— 比如像类似于下面的变量:


let key = "likes birds";
// 跟 user["likes birds"] = true; 一样
user[key] = true;


在这里,变量 key 可以是程序运行时计算得到的,也可以是根据用户的输入得到的。然后我们可以用它来访问属性。这给了我们很大的灵活性。

例如:


let user = {
  name: "John",
  age: 30
};
let key = prompt("What do you want to know about the user?", "name");
// 访问变量
alert( user[key] ); // John(如果输入 "name")


点符号不能以类似的方式使用:


let user = {
  name: "John",
  age: 30
};
let key = "name";
alert( user.key ) // undefined


计算属性


我们可以在对象字面量中使用方括号。这叫做 计算属性

例如:


let fruit = prompt("Which fruit to buy?", "apple");
let bag = {
  [fruit]: 5, // 属性名是从 fruit 变量中得到的
};
alert( bag.apple ); // 5 如果 fruit="apple"


计算属性的含义很简单:[fruit] 含义是属性名应该从 fruit 变量中获取。

所以,如果一个用户输入 "apple"bag 将变为 {apple: 5}

本质上,这跟下面的语法效果相同:


let fruit = prompt("Which fruit to buy?", "apple");
let bag = {};
// 从 fruit 变量中获取值
bag[fruit] = 5;


……但是看起来更好。

我们可以在方括号中使用更复杂的表达式:


let fruit = 'apple';
let bag = {
  [fruit + 'Computers']: 5// bag.appleComputers = 5
};


方括号比点符号更强大。它允许任何属性名和变量,但写起来也更加麻烦。

所以大部分时间里,当属性名是已知且简单的时候,就是用点符号。如果我们需要一些更复杂的内容,那么就用方括号。


保留字段可以用作属性名


像 "for"、"let" 和 "return" 等保留字段不能用作变量名。

对于对象的属性,没有这些限制。任何名字都可以:


let obj = {
  for: 1,
  let: 2,
  return: 3
}
alert( obj.for + obj.let + obj.return );  // 6


一般来说,任何名字都可以,只有一个特殊的:"__proto__" 因为历史原因要特别对待。比如,我们不能把它设置为非对象的值:


let obj = {};
obj.__proto__ = 5;
alert(obj.__proto__); // [object Object],这样无法获得预期效果


我们从代码中可以看出来,把它赋值为 5 的操作被忽略了。


如果我们打算在一个对象中存储任意的键值对,并允许访问者指定键,那么这可能会成为 bug 甚至漏洞的来源。


比如,访问者可能选择 __proto__ 作为键,这个赋值的逻辑就失败了(像上面那样)。


有一种让对象把 __proto__ 作为常规属性进行对待的方法,在后面章节会讲到,但现在我们需要先来学习更多对象的相关知识。


还有另外一种数据结构 Map[2],我们会在后面的 Map and Set(映射和集合)[3] 这章节学习它,它支持任意的键。


属性值简写


在实际开发中,我们通常用已存在的变量当做属性名。

例如:


function makeUser(name, age) {
  return {
    name: name,
    age: age
    // ……其他的属性
  };
}
let user = makeUser("John", 30);
alert(user.name); // John


在上面的例子中,属性名跟变量名一样。这种通过变量生成属性的应用场景很常见,在这有一种特殊的 属性值缩写 方法,使属性名变得更短。


可以用 name 来代替 name:name 像下面那样:


function makeUser(name, age) {
  return {
    name, // 与 name: name 相同
    age   // 与 age: age 相同
    // ...
  };
}


我们可以把属性名简写方式和正常方式混用:


let user = {
  name,  // 与 name:name 相同
  age: 30
};


存在性检查


对象的一个显著的特点就是其所有的属性都是可访问的。如果某个属性不存在也不会报错!访问一个不存在的属性只是会返回 undefined。这提供了一种普遍的用于检查属性是否存在的方法 —— 获取值来与 undefined 比较:


let user = {};
alert( user.noSuchProperty === undefined ); // true 意思是没有这个属性


这里同样也有一个特别的操作符 "in" 来检查属性是否存在。

语法是:


"key"in object


例如:


let user = { name: "John", age: 30 };
alert( "age"in user ); // true,user.age 存在
alert( "blabla"in user ); // false,user.blabla 不存在。


请注意,in 的左边必须是 属性名。通常是一个带引号的字符串。

如果我们省略引号,则意味着将测试包含实际名称的变量。例如:


let user = { age: 30 };
let key = "age";
alert( key in user ); // true,从 key 获取属性名并检查这个属性


对存储值为 undefined 的属性使用 "in"


通常,检查属性是否存在时,使用严格比较 "=== undefined" 就够了。但在一种特殊情况下,这种方式会失败,而 "in" 却可以正常工作。


那就是属性存在,但是存储值为 undefined


let obj = {
  test: undefined
};
alert( obj.test ); // 显示 undefined,所以属性不存在?
alert( "test"in obj ); // true,属性存在!


在上面的代码中,属性 obj.test 事实上是存在的,所以 in 操作符检查通过。

这种情况很少发生,因为通常情况下是不会给对象赋值 undefined 的,我们经常会用 null 来表示未知的或者空的值。


目录
相关文章
|
5天前
|
JSON JavaScript 前端开发
JavaScript实现字符串转json对象的方法
JavaScript实现字符串转json对象的方法
|
8天前
|
JavaScript 前端开发
js之DOM 文档对象模型
js之DOM 文档对象模型
8 1
js之DOM 文档对象模型
|
1天前
|
JavaScript 前端开发 索引
JS遍历数组里数组下的对象,根据数组中对象的某些值,组合成新的数组对象
这篇文章介绍了如何在JavaScript中遍历数组里数组下的对象,并根据对象的某些属性值组合成一个新的数组对象。主要内容包括使用ES6的`for...of`循环来遍历数组对象,然后根据需要提取对象中的属性值,并将它们放入新的对象中,最终形成一个新的对象数组以供使用。
|
1天前
|
JSON JavaScript 前端开发
如何检查 JavaScript 对象是否为空
【8月更文挑战第18天】
18 0
如何检查 JavaScript 对象是否为空
|
5天前
|
JavaScript 前端开发
JavaScript BOM 的概念(浏览器对象模型)
JavaScript BOM 的概念(浏览器对象模型)
12 1
|
5天前
|
JavaScript 前端开发
JavaScript基础&实战(5)js中的数组、forEach遍历、Date对象、Math、String对象
这篇文章介绍了JavaScript中的数组、Date对象、Math对象以及包装类(String、Number、Boolean),并详细讲解了数组的创建、方法(如forEach、push、pop、unshift、slice、splice)和遍历操作,以及工厂方法创建对象和原型对象的概念。
JavaScript基础&实战(5)js中的数组、forEach遍历、Date对象、Math、String对象
|
5天前
|
JavaScript 前端开发
JavaScript基础&实战(4)js中的对象、函数、全局作用域和局部作用域
这篇文章介绍了JavaScript中对象的基本概念和操作,包括对象属性和方法的使用、对象字面量的创建、函数的定义和作用域的概念,以及全局作用域和局部作用域的区别和特性。
JavaScript基础&实战(4)js中的对象、函数、全局作用域和局部作用域
|
11天前
|
JavaScript 数据处理
如何使用 Vue.js 将数据对象的值放入另一个数据对象中?
如何使用 Vue.js 将数据对象的值放入另一个数据对象中?
|
17天前
|
JavaScript 前端开发 Java
什么是JavaScript原型对象
【8月更文挑战第2天】什么是JavaScript原型对象
39 9
|
5天前
|
JavaScript 前端开发
js之DOM 文档对象模型
js之DOM 文档对象模型

热门文章

最新文章