Skip to content

5. 字面量对象

此处,我们将代码中直接定义的对象称为“字面量对象”。JavaScript 包含类和类实例对象的概念。因此,这并非我们当前讨论的对象类型。

Image

5.1. script [obj-01]

在此,我们将介绍字面量对象的基本特性。其主要特征在于,该对象是通过指针进行操作的。


'use strict';
// an empty object
const obj1={};
// object properties can be dynamically created
obj1.prop1="abcd";
console.log('obj1=',obj1);
// other property
obj1.prop2=[1,2,3];
console.log("obj1=",obj1);
// another property with a different notation
obj1['prop3']=true;
console.log("obj1=",obj1);
// obj1 is a reference to the object (pointer), not the object itself
const obj2=obj1;
// obj2 and obj1 point to the same object
obj2.prop1="xyzt";
console.log("obj1=",obj1);
console.log("obj2=",obj2);
// properties can be variables
const var1='prop1';
console.log('prop1=',obj1[var1]);

执行


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\objets\obj-01.js"
obj1=[object Object]
obj1= { prop1: 'abcd', prop2: [ 1, 2, 3 ] }
obj1= { prop1: 'abcd', prop2: [ 1, 2, 3 ], prop3: true }
obj1= { prop1: 'xyzt', prop2: [ 1, 2, 3 ], prop3: true }
obj2= { prop1: 'xyzt', prop2: [ 1, 2, 3 ], prop3: true }
prop1= xyzt

注释

  • 代码第3行:对象是通过指针进行操作的。因此,[obj1] 是一个指针。修改被指针指向的对象并不会修改指针 [obj1]。这就是为什么,就像数组一样,对象引用需要使用 [const] 关键字进行声明;
  • 代码第 6 行:与数组类似,[console.log] 可以显示对象;
  • 代码第 11 行:obj1.prop3 可以重写为 obj1.[‘prop3’]。当 ‘prop3’ 实际上是一个变量时(第 20–21 行),这种后一种写法非常有用;
  • 代码第 13–18 行:表明语句 [obj2=obj1] 是对对象引用的复制,而非对象本身的复制;

5.2. 脚本 [obj-02]

本脚本演示了对象的属性可以取对象作为其值。这将形成多层级对象。我们还介绍了全局对象 [JSON],它支持对象转字符串和字符串转对象的转换。


'use strict';
// a multi-level object
const personne = {
  prénom: "martin",
  âge: 12,
  père: {
    prénom: "paul",
    âge: 45
  },
  mère: {
    prénom: "micheline",
    âge: 42
  }
}
// access to properties
console.log("prénom personne=", personne.prénom);
console.log("prénom mère=", personne.mère.prénom);
personne.mère.âge = 40;
console.log("âge mère=", personne.mère.âge);
// console.log can display objects
console.log("personne=", personne);
console.log("mère=", personne.mère);
// you can also display the jSON string of the
let json = JSON.stringify(personne);
console.log("jSON=", json);
// you can reread the jSON
let personne2 = JSON.parse(json);
console.log("père=", personne2.père);

注释

  • 第 24 行:将 JavaScript 对象转换为 JSON 字符串;
  • 第 27 行:将 JSON 字符串转换为 JavaScript 对象;

执行


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\objets\obj-02.js"
prénom personne= martin
prénom mère= micheline
âge mère= 40
personne= { 'prénom': 'martin',
'âge': 12,
'père': { 'prénom': 'paul', 'âge': 45 },
'mère': { 'prénom': 'micheline', 'âge': 40 } }
mère= { 'prénom': 'micheline', 'âge': 40 }
jSON= {"prénom":"martin","âge":12,"père":{"prénom":"paul","âge":45},"mère":{"prénom":"micheline","âge":40}}
père= { 'prénom': 'paul', 'âge': 45 }

注释

  • 第 10 行:在 JSON 字符串中,属性必须用引号括起来,字符串值也必须如此;

5.3. 脚本 [obj-03]

本脚本介绍了对象属性的getter和setter概念:


'use strict';
// object getters and setters
const personne = {
  // getter
  get nom() {
    console.log("getter nom");
    return this._nom;
  },
  // setter
  set nom(unNom) {
    console.log("setter nom");
    this._nom = unNom;
  }
};
// setter
personne.nom = "Hercule";
// getter
console.log(personne.nom);
// the object itself
console.log("personne=", personne);
// this does not prevent direct access to property [_nom]
personne._nom = "xyz";
console.log("personne=", personne);

注释

  • 第 5–7 行:定义了一个 [getter],这通常是一个返回对象属性值的函数,但实际上可以返回任何内容。关键字 [function] 被关键字 [get] 替换;
  • 第 7 行:getter 返回 [_name] 属性。请注意,该属性无需声明;
  • 第 10–13 行:定义 [setter],这通常是一个将接收到的值赋给对象属性的函数,但实际上可以执行任何操作。关键字 [function] 被关键字 [set] 替换。可以使用 [setter] 来验证作为参数传递给 [setter] 的值;
  • 第 16 行:将隐式调用 [set name] 函数;
  • 第 18 行:将隐式调用 [get name] 函数;
  • 第 22 行:表明是否使用 getter/setter 取决于开发者的选择。如果开发者知道由其管理的属性名称,则可以直接访问该属性;

执行


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\objets\obj-03.js"
setter nom
getter nom
Hercule
personne= { nom: [Getter/Setter], _nom: 'Hercule' }
personne= { nom: [Getter/Setter], _nom: 'xyz' }

注意第 5–6 行:[console.log] 也会显示作为函数的属性。

5.4. 脚本 [obj-04]

本脚本展示了三种编写对象属性名称的方法以及两种访问这些属性的方法。


'use strict';
// object property names may be literal [name], surrounded by apostrophes ['name'], or may have a double quotation mark ['name']
// or quotation marks ["name"]
 
// literal
const obj1 = {
  nom: "martin",
  prénom: "jean"
};
console.log("prénom=", obj1.prénom);
 
// surrounded by apostrophes
const obj2 = {
  'nom': "martin",
  'prénom': "jean"
};
console.log("nom=", obj2.nom);
 
// surrounded by quotation marks
const obj3 = {
  "nom": "martin",
  "prénom": "jean"
};
 
// two possible syntaxes for accessing the [name] property
console.log("nom=", obj3.nom);
console.log("nom=", obj3['nom']);

执行结果


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\objets\obj-04.js"
prénom= jean
nom= martin
nom= martin
nom= martin

5.5. 脚本 [obj-05]

该脚本展示了字面量对象的属性可以是函数。这与具有属性和方法的类实例对象非常相似。


'use strict';
 
// an object can have properties of type [function]
const personne = {
  // properties
  prénom: "martin",
  âge: 12,
  père: {
    prénom: "paul",
    âge: 45
  },
  mère: {
    prénom: "micheline",
    âge: 42
  },
  // method
  toString: function () {
    return JSON.stringify(this);
  }
}
 
// use
console.log("personne=", personne);
console.log("personne.toString=", personne.toString());
  • 第 17–19 行:对象的内部方法。在此方法中,我们使用关键字 [this](第 18 行)访问对象的属性。[this] 指代对象本身,而 [this.firstName] 指代其 [firstName] 属性;

执行


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\objets\obj-05.js"
personne= { 'prénom': 'martin',
'âge': 12,
'père': { 'prénom': 'paul', 'âge': 45 },
'mère': { 'prénom': 'micheline', 'âge': 42 },
toString: [Function: toString] }
personne.toString= {"prénom":"martin","âge":12,"père":{"prénom":"paul","âge":45},"mère":{"prénom":"micheline","âge":42}}

5.6. 脚本 [obj-06]

本脚本演示了如何在未知对象属性名称的情况下访问这些属性。


'use strict';
 
// an object can have properties of type [function]
let personne = {
  // properties
  prénom: "martin",
  âge: 12,
  père: {
    prénom: "paul",
    âge: 45
  },
  mère: {
    prénom: "micheline",
    âge: 42
  },
  // method
  toString: function () {
    return JSON.stringify(this);
  }
}
 
// use
console.log(personne);
// properties
console.log("-----------------------");
for (const key in personne) {
  if (personne.hasOwnProperty(key)) {
    const element = personne[key];
    console.log(key, "=", element);
  }
}
// to escape the eslint warning (1)
console.log("-----------------------");
for (const key in personne) {
  if (Object.prototype.hasOwnProperty.call(personne, key)) {
    const element = personne[key];
    console.log(key, "=", element);
  }
}
// to escape the eslint warning (2)
console.log("-----------------------");
for (const key in personne) {
  // eslint-disable-next-line no-prototype-builtins
  if (personne.hasOwnProperty(key)) {
    const element = personne[key];
    console.log(key, "=", element);
  }
}

注释

  • 第 26–31 行:用于获取对象属性列表(不包括方法)的代码。这段代码会触发 ESLint 警告:

Image

  • 第 32–39 行:用于绕过 ESLint 警告的代码。我们使用了 [Object] 类的原型;
  • 第 41–47 行:或者我们可以直接禁用该警告(第 43 行);

5.7. 脚本 [obj-07]

[obj-07] 脚本演示了解构对象的功能:


'use strict';
// destructuring
 
// literal
const obj1 = {
  nom: "martin",
  prénom: "jean"
};
 
// destructuring obj1 into variables [n,p]
const { nom: n, prénom: p } = obj1;
console.log("n=", n, "p=", p);
 
// destructure obj1 in variables [n2,p2]
function f({ nom: n2, prénom: p2 }) {
  console.log("f-n2=", n2, "f-p2=", p2);
}
f(obj1);
 
// destructuring obj1 into variables [last name,first name]
function g({ nom: nom, prénom: prénom }) {
  console.log("g-nom=", nom, "g-prénom=", prénom);
}
g(obj1);
 
// destructuring obj1 into variables [last name,first name]
// with shortened notation equivalent to h({name:surname,firstname:firstname})
function h({ nom, prénom }) {
  console.log("h-nom=", nom, "h-prénom=", prénom);
}
h(obj1);

注释

  • 第 11 行:大括号 {} 支持解构。语法

const { nom: n, prénom: p } = obj1

会创建两个变量 [n] 和 [p],其等效于:


const n = obj1.nom
const p = obj1.prénom

该声明可以写成如下形式:


const { nom => n, prénom => p } = obj1

以表明属性 [lastName, firstName] 的值将赋给变量 [n, p];

  • 解构操作在第 15、21 和 28 行重复出现。每次出现大括号 {} 都表示将对一个对象进行解构并赋值给变量;
  • 第 28 行可能令人困惑。这是以下语法的简写形式:

function h({ nom : nom, prénom : prénom })

执行结果如下:

1
2
3
4
n= martin p= jean
f-n2= martin f-p2= jean
g-nom= martin g-prénom= jean
h-nom= martin h-prénom= jean

5.8. 脚本 [obj-08]

脚本 [obj-08] 演示了如何获取对象的副本:


'use strict'
 
// object cloning
const obj1 = {
  nom: "martin",
  prénom: "jean"
};
 
// clone (copy) of obj1 with the spread operator
const obj2 = { ...obj1 }
 
// checks
// obj2 points to a copy of obj1
console.log("obj2===obj1 :", obj1 === obj2)
console.log("obj2=", obj2)
  • 第 10 行:复制对象 [obj1] 的操作。... 运算符被称为展开运算符;

执行结果如下:

obj2===obj1 : false
obj2= { nom: 'martin', 'prénom': 'jean' }
  • 第 1 行:表明引用 [obj1] 和 [obj2] 指向的不是同一个对象;
  • 第 2 行:表明 [obj2] 所指向的对象是 [obj1] 所指向的对象的副本;

5.9. 结论

本节中的脚本表明,JavaScript 字面量对象类似于面向对象语言中的类实例对象。可以在其上定义属性、方法以及 getter/setter。它是一个动态对象,其属性可在运行时定义。此时,它的行为类似于一个字典,其元素可以是任何类型,包括 [function] 类型。