对象是引用类型(传址类型)

声明定义

new Object()

  1. var obj = new Object();
  2. obj.name = "zhangsan";

字面量 👍

  1. var obj = {
  2. name: "zhangsan"
  3. };


工厂函数

* 返回对象的函数称为工厂函数

  1. function human(name) {
  2. return {
  3. name,
  4. run: function() {
  5. console.log("run");
  6. }
  7. };
  8. }
  9. var male = human("zhangsan");
  10. male.run(); // "run"

构造函数

*构造函数**类似工厂函数,用于创建对象
* 构造函数每个单词首字母最好大写
*构造函数 this 指向对象实例
*
构造函数不能是箭头函数
*
**构造函数默认返回 this,且修改无效
*构造函数函数需要使用 new 关键字创建对象实例**

  1. function Human(name) {
  2. this.name = name;
  3. this.run = function() {
  4. console.log("run");
  5. }
  6. }
  7. var human = new Human("zhangsan");
  8. human.run(); // "run"

Class

* 详见 类章节

Object.create()

* 详见 原型与继承章节

Object.defineProperties()

* 详见 本章节- 属性特征 - Object.defineProperties(obj, description)

属性管理

obj.property

* 点语法
* property 必须是无任何符号连接的单个单词

**_desc_** 添加、读取、修改属性值 **params** { object } obj **params** { object } property 属性名称 **return** { any } 属性值

  1. var obj = {
  2. name: "zhangsan"
  3. };
  4. obj.age = 18; // 添加
  5. var name = obj.name; // 读取
  6. obj.name = "lisi"; // 修改

obj[property]

* 中括号语法
* property 可以进行计算属性操作

**_desc_** 添加、读取、修改属性值 **params** { object } obj **params** { object } property 属性名称 **return** { any } 属性值

  1. var obj = {
  2. ["my-name"]: "zhangsan"
  3. };
  4. obj["my-name"] = 18; // 添加
  5. var name = obj["my-name"]; // 读取
  6. obj["my-name"] = "lisi"; // 修改

delete obj.property/obj[property]**

* 当属性特征 configurable 为 false 时,无法删除

**_desc_** 删除属性 **params** { object } obj **params** { object } property 属性名称 **return** { boolean }

  1. var obj = {
  2. name: "zhangsan"
  3. };
  4. var bool = delete obj.name;
  5. console.log(obj); // {}
  6. console.log(bool); // true

Object.assign(...obj)

* 参数至少两个
* 传入对象存在相同的属性时,后传入的对象会覆盖前面对象该属性的值
* 传入对象存在其他不同的属性时,会在返回对象中添加该属性
* 返回值是第一个传入的参数

**_desc_** 合并对象 **params** { object } 多个对象 **return**_ { object } 返回第一个传入的参数

  1. "use strict";
  2. var obj1 = { name: "zhangsan" };
  3. var obj2 = { name: "lisi" };
  4. var obj3 = { age: 18 };
  5. var _obj = Object.assign(obj1, obj2, obj3);
  6. console.log(_obj); // { name: "lisi", age: 18 }
  7. console.log(_obj === obj1); // true

计算属性

* 对象的属性名称需要计算或存在连接符号

  1. var obj = {
  2. [`name-${ 1 + 1}`]: "zhangsan",
  3. ["age-18"]: 18
  4. };
  5. console.log(obj); // { "name-2": "zhangsan, "age-18": 18 }

this

* 对象中的 this 始终指向对象自己

属性访问器

* Javascript 提供的存取器特性,即使用函数来管理属性
* 常用于保护内部私有属性,防止外部直接访问,或读取设置时进行统一处理
* 访问器优先级更高,普通属性和访问器同时存在时,普通属性无效

getter**

**_desc_** 获取属性值 **return** { any } 返回属性值

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan",
  4. _name: "lisi",
  5. get name() {
  6. return this._name;
  7. }
  8. };
  9. console.log(obj.name); // "lisi"

**

setter**

**_desc_** 设置属性值 **params** { any } value **return** { void }

  1. var obj = {
  2. _name: "zhangsan",
  3. get name() {
  4. return this._name;
  5. },
  6. set name(value) {
  7. this._name = value;
  8. }
  9. };
  10. obj.name = "lisi";
  11. console.log(obj.name); // "lisi"

枚举遍历

Object.keys(obj)

* 只能获取字符串类型的属性名称,无法获取 Symbol 类型的属性名称

**_desc_** 获取对象中可枚举的属性名称 **params** { object } obj **return** { array } 可枚举的属性名称组成的数组

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan",
  4. age: 18
  5. };
  6. var keys = Object.keys(obj);
  7. console.log(keys); // ["name", "age"]

Object.values(obj)**

**_desc_** 获取对象中可枚举的属性值 **params** { object } obj **return** { array } 可枚举的属性值组成的数组

  1. var obj = {
  2. name: "zhangsan",
  3. age: 18
  4. };
  5. var values = Object.values(obj);
  6. console.log(values); // ["zhangsan", 18]

Object.entries(obj)

只能获取字符串类型的属性名称,无法获取 Symbol 类型的属性名称*

**_desc_** 获取对象中可枚举的属性名称和属性值 **params** { object } obj **return** { array } 可枚举的属性名称数组和属性值数组组成的二维数组

  1. var obj = {
  2. name: "zhangsan",
  3. age: 18
  4. };
  5. var entries = Object.entries(obj);
  6. console.log(entries); // [ ["name", "age"], ["zhangsan", 18] ]

Object.fromEntries(arr)**

**_desc_** 将属性名数组和属性值数组组成的二维数组转换为对象 **params** { array } arr **return** { object }

  1. var arr = [["name", "age"], ["zhangsan", 18]];
  2. var obj = Object.fromEntries(arr);
  3. console.log(obj); // { name: "zhangsan", age: 18 }

Object.getOwnPropertyNames(obj)**

* 既可以获取可枚举的属性名称,也可以获取不可枚举的属性名称
* 只能获取字符串类型的属性名称,无法获取 Symbol 类型的属性名称

**_desc_** 获取对象中所有的属性名称 **params** { object } obj **return** { array } 所有属性名称数组和属性值数组组成的二维数组

  1. "use strict";
  2. var obj = Object.defineProperties({}, {
  3. name: {
  4. value: "zhangsan",
  5. enumerable: true
  6. },
  7. age: {
  8. value: 18,
  9. enumerable: false
  10. }
  11. });
  12. var keys1 = Object.keys(obj);
  13. console.log(keys1); // ["name"]
  14. var keys2 = Object.getOwnPropertyNames(obj);
  15. console.log(keys2); // ["name", "age"]

Object.getOwnPropertySymbols(obj)

* 只能获取 Symbol 类型的属性名称,无法获取其他类型的属性名称

**_desc_** 获取对象中所有 Symbol 类型的属性名称 **params** { object } obj **return** { array } 所有 Symbol 类型的属性名称组成的数组

  1. var obj = {
  2. [Symbol("name")]: "zhangsan",
  3. age: 18
  4. }
  5. console.log(obj); // { Symbol(name): "zhangsan", age: 18 }
  6. var symbols = Object.getOwnPropertySymbols(obj);
  7. console.log(symbols); // [ Symbol(name) ]

Reflect.ownKeys(obj)

*可以获取**任意类型的属性名称
* 既可以获取可枚举的属性名称,也可以获取不可枚举的属性名称

**_desc_** 获取对象中所有属性名称 **params** { object } obj **return** { array } 所有属性名称组成的数组

  1. var obj = {
  2. [Symbol("name")]: "zhangsan",
  3. age: 18,
  4. [Symbol("sex")]: "male"
  5. };
  6. console.log(Reflect.ownKeys(obj)); // ["age", Symbol(name), Symbol(sex)]

for in**

**_desc_** 遍历属性名称 **params** { object } obj **params** { string } key 属性名称 **return** { void }

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan",
  4. age: 18
  5. };
  6. for (let key in obj) {
  7. console.log(key); // "name" ---> "age"
  8. }

for of

* 循环遍历的对象必须是可迭代的,一般通过 Object.keys | Object.values | Object.entries 将对象转换为数组再遍历

**_desc_** 遍历属性值 **params** { array } obj **params** { any } value 属性值 **return** { void }

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan",
  4. age: 18
  5. };
  6. for (let value of Object.values(obj)) {
  7. console.log(value); // "zhangsan" ---> 18
  8. }

属性特征

四大属性特征**

特征 说明 默认值
value 对象属性的值 undefined
writable 对象属性是否可修改 true
enumerable 对象属性是否可枚举(是否可通过循环、Object.keys()等读取对象属性) true
configurable 能否使用 delete、能否修改属性特征、能否修改访问器属性 true

* 设置属性特征 writable 为 false,即禁止修改时,普通模式修改对象属性不会报错,但修改不生效,严格模式会报错:Cannot assign to read only property ‘xxx’ of object ‘<#Object>’
设置*属性特征** configurable 为 false,即禁止配置时,普通模式删除对象属性不会报错,但删除不生效,严格模式会报错:Cannot delete property ‘sex’ of #
*设置属性特征 configurable 为 false,即禁止配置时,无法再次设置该属性的属性特征(writable 例外,cofigurable 为 false 时,writable 仍能重复配置无论哪种模式都会报错:Cannot redefine property: xxx**

Object.getOwnPropertyDescriptor(obj, property)

**_desc_** 获取对象中某个属性的特征 **params** { object } obj **params** { string } property 属性名称 **return** { object } 该属性的特征描述

  1. var obj = {
  2. name: "zhangsan"
  3. };
  4. var descriptor = Object.getOwnPropertyDescriptor(obj, "name");
  5. console.log(descriptor);
  6. /**
  7. * {
  8. * value: "zhangsan",
  9. * writable: true,
  10. * enumerable: true,
  11. * configurable: true
  12. * }
  13. */

Object.getOwnPropertyDescriptors(obj)**

**_desc_** 获取对象中所有属性的特征 **params** { object } obj **return** { object } 所有属性的特征描述

  1. var obj = {
  2. name: "zhangsan",
  3. age: 27
  4. };
  5. var descriptors = Object.getOwnPropertyDescriptors(obj);
  6. console.log(descriptors);
  7. /**
  8. * {
  9. * name: { value: "zhangsan", writable: true, enumerable: true, configurable: true },
  10. * age: { value: 27, writable: true, enumerable: true, configurable: true }
  11. * }
  12. */

Object.defineProperty(obj, property, description)**

**_desc_** 设置、修改对象中某个属性的特征 **params** { object } obj **params** { object } property 设置、修改的属性名称 **params** { object } description 属性特征描述 **return** { object } 原对象

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan",
  4. age: 27,
  5. sex: "male"
  6. };
  7. // 禁止修改
  8. var _obj = Object.defineProperty(obj, "name", {
  9. writable: false
  10. });
  11. console.log(_obj === obj) // true
  12. obj.name = "lisi"; // 普通模式:不报错,但不生效;严格模式:报错
  13. console.log(obj); // { name: "zhangsan", age: 27 }
  14. // 禁止枚举
  15. Object.defineProperty(obj, "age", {
  16. enumerable: false
  17. });
  18. var properties = Object.keys(obj);
  19. console.log(properties); // ["name"],禁止 age 枚举后,无法遍历 age 属性
  20. // 禁止配置
  21. Object.defineProperty(obj, "sex", {
  22. configurable: false
  23. });
  24. delete obj.sex; // 普通模式:不报错,但返回 false 不生效;严格模式:报错
  25. Object.defineProperty(obj, "sex", {
  26. configurable: true
  27. }); // 无论哪种模式都报错,configurable 为 false 时禁止重复设置 configurable
  28. Object.defineProperty(obj, "sex", {
  29. value: "female",
  30. writable: false,
  31. enumerable: false
  32. }); // 正常执行,configurable 为 false 时,不影响设置其他三个属性特征

Object.defineProperties(obj, description)**

**_desc_** 设置、修改对象中所有属性的特征 **params** { object } obj **params** { object } description 属性特征 **return** { object } 原对象

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan",
  4. age: 27
  5. };
  6. var _obj = Object.defineProperties(obj, {
  7. name: {
  8. value: "lisi",
  9. enumerable: false
  10. },
  11. age: {
  12. writable: false
  13. }
  14. });
  15. console.log(_obj === obj); // true
  16. var properties = Object.keys(obj);
  17. console.log(properties); // ["age"]
  18. obj.age = 30; // error
  19. /**
  20. * 通过 Object.definePrperties 声明定义对象
  21. */
  22. var newObj = Object.defineProperties({}, {
  23. name: {
  24. value: "wangwu"
  25. },
  26. age: {
  27. value: 18
  28. }
  29. })
  30. console.log(newObj); // { name: "wangwu", age: 18 }

Object.preventExtensions(obj)

* 设置禁止添加属性后,向对象中添加属性时,普通模式不报错,但添加不生效,严格模式报错:Cannot add property age, object is not extensible

**_desc_** 禁止对象添加属性 **params** { object } obj **return**_ { object } 原对象

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan"
  4. };
  5. var _obj = Object.preventExtensions(obj);
  6. console.log(_obj === obj); // true
  7. a.age = 18; // error

Object.seal(obj)

* 设置对象禁止添加属性
* 设置对象中所有属性的 configurable 特征为 false

**_desc_** 封闭对象属性 **params** { object } obj **return**_ { object } 原对象

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan"
  4. };
  5. var description_before = Object.getOwnPropertyDescriptors(obj);
  6. console.log(description_before); // configurable: true
  7. obj.age = 18; // ok
  8. var _obj = Object.seal(obj);
  9. console.log(_obj === obj); // true
  10. var description_after = Object.getOwnPropertyDescriptors(obj);
  11. console.log(description_after); // configurable: false
  12. obj.sex = "male"; // error

Object.freeze(obj)

* 设置对象禁止添加属性
* 设置对象中所有属性的 writable 特征为 false
* 设置对象中所有属性的 configurable 特征为 false

**_desc_** 冻结对象属性 **params** { object } obj **return**_ { object } 原对象

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan"
  4. };
  5. var description_before = Object.getOwnPropertyDescriptors(obj);
  6. console.log(description_before); // writable: true, configurable: true
  7. obj.name = "lisi"; // ok
  8. obj.age = 18; // ok
  9. var _obj = Object.freeze(obj);
  10. console.log(_obj === obj); // true
  11. var description_afert = Object.getOwnPropertyDescriptors(obj);
  12. console.log(description_afert); // writavble: false, configurable: false
  13. obj.name = "wangwu"; // error
  14. obj.sex = "male"; // error

属性检测

obj.hasOwnProperty(property)**

**_desc_** 检测对象是否存在某个属性 **params** { object } obj **params** { object } property 属性名称 **return** { boolean }

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan"
  4. };
  5. var bool1 = obj.hasOwnProperty("name");
  6. var bool2 = obj.hasOwnProperty("age");
  7. console.log(bool1); // true
  8. console.log(bool2); // false

property in obj**

**_desc_** 检测对象及其原型链中是否存在某个属性 **params** { object } obj **params** { object } property 属性名称 **return** { boolean }

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan"
  4. };
  5. console.log("name" in obj); // true, obj 中存在
  6. console.log("toString" in obj); // true, obj 的原型链中存在 toString 属性

obj.propertyIsEnumerable(property)

* 本质是获取对象某个属性的 enumerable 特征的值

**_desc_** 检测对象某个属性是否可枚举 **params** { object } obj **params** { object } property 属性名称 **return** { boolean }

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan",
  4. age: 18
  5. };
  6. Object.defineProperty(obj, "age", {
  7. enumerable: false
  8. });
  9. var bool1 = obj.propertyIsEnumerable("name");
  10. var bool2 = obj.propertyIsEnumerable("age");
  11. console.log(bool1); // true
  12. console.log(bool2); // false

Object.isExtensible(obj)**

**_desc_** 检测对象是否可以添加属性 **params** { object } obj **return**_ { boolean }

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan"
  4. };
  5. var bool1 = Object.isExtensible(obj);
  6. console.log(bool1); // true
  7. Object.preventExtensions(obj);
  8. var bool2 = Object.isExtensible(obj);
  9. console.log(bool2); // false

Object.isSealed(obj)**

**_desc_** 检测对象是否封闭 **params** { object } obj **return**_ { boolean }

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan"
  4. };
  5. var bool1 = Object.isSealed(obj);
  6. console.log(bool1); // false
  7. Object.seal(obj);
  8. var bool2 = Object.isSealed(obj);
  9. console.log(bool2); // true

**

Object.isFrozen(obj)**

**_desc_** 检测对象是否冻结 **params** { object } obj **return**_ { boolean }

  1. var obj = {
  2. name: "zhangsan"
  3. };
  4. var bool1 = Object.isFrozen(obj);
  5. console.log(bool1); // false
  6. Object.freeze(obj);
  7. var bool2 = Object.isFrozen(obj);
  8. console.log(bool2); // true

浅拷贝

* 只复制第一层对象的属性
* 复制和被复制的对象指向不同的内存地址,即复制后的对象与被复制的对象不是同一值
* 复制和被复制的对象的引入类型属性指向相同的内存地址,即复制后的对象和被复制的对象中的引入类型属性依旧是同一个属性值

循环遍历赋值

  1. var obj = {
  2. name: "zhangsan",
  3. role: [1, 2, 3, 4, 5]
  4. };
  5. var _obj = {};
  6. for (let key in obj) {
  7. _obj[key] = obj[key];
  8. }
  9. console.log(_obj === obj); // false
  10. console.log(_obj.role === obj.role); // true

**

Object.assign({}, ...obj)

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan",
  4. role: [1, 2, 3, 4, 5]
  5. };
  6. var _obj = Object.assign({}, obj);
  7. console.log(_obj === obj); // false
  8. console.log(_obj.role === obj.role); // true

展开表达式赋值**

  1. "use strict";
  2. var obj = {
  3. name: "zhangsan",
  4. role: [1, 2, 3, 4, 5]
  5. };
  6. var _obj = { ...obj };
  7. console.log(_obj === obj); // false
  8. console.log(_obj.role === obj.role); // true

深拷贝

* 递归复制所有层级对象的属性
* 复制和被复制的对象指向不同的内存地址,即复制后的对象与被复制的对象不是同一值
* 复制和被复制的对象的引入类型属性指向不同的内存地址,即复制后的对象和被复制的对象中的引入类型属性不是同一个属性值

递归 👍

  1. "use strict";
  2. function deepCopy(obj) {
  3. let res = obj instanceof Array ? [] : {};
  4. for (const [k, v] in Object.entries(obj)) {
  5. res[k] = typeof v === "object" ? deepCopy(v) : v;
  6. }
  7. return res;
  8. }
  9. // <----------------- demo ----------------->
  10. var obj = {
  11. name: "zhangsan",
  12. role: [1, 2, 3, 4, 5]
  13. };
  14. var _obj = deepCopy(obj);
  15. console.log(_obj === obj); // false
  16. console.log(_obj.role === obj.role); // false

序列化对象

JSON.parse(JSON.stringify(obj))
* 序列化对象实现深拷贝存在的弊端

  1. Date 对象序列化后会被转换为字符串形式
  2. RegExp、Error 对象序列化后会被转换为空对象 {}
  3. 函数序列化后会被转换为 undefined
  4. undefined 序列化后会丢失该属性
  5. NaN、Infinity、-Infinity 序列化后会被转换为 null
  6. 只能够序列化对象的可枚举的自由属性,深拷贝构造函数的实例时,会丢失构造方法 constructor | 属性值 - 深拷贝前 | 属性值 - 深拷贝后 | 说明 | | :—-: | :—-: | :—-: | | Date 对象 | String | | | RegExp、Error 对象 | {} | | | 函数、undefined | undefined 或丢失该属性 | | | NaN、Infinity、-Infinity | null | |
  1. "use strict";
  2. var obj = {
  3. name: "zhangsan",
  4. role: [1, 2, 3, 4, 5]
  5. };
  6. var _obj = JSON.parse(JSON.stringify(obj));
  7. console.log(_obj === obj); // false
  8. console.log(_obj.role === obj.role); // false
  9. // <----------------- 弊端 demo ----------------->
  10. var demo = {
  11. date: new Date(),
  12. reg: new RegExp(),
  13. error: new Error(),
  14. fn: function() {},
  15. und: undefined,
  16. nan: NaN
  17. }
  18. var _demo = JSON.parse(JSON.stringify(demo));
  19. console.log(_demo); // { date: "...", reg: {}, error: {}, nan: null }
  20. // <----------------- 构造函数弊端 demo ----------------->
  21. function Human(name) {
  22. this.name = name;
  23. }
  24. var human = new Human("zhangsan");
  25. var _human = JSON.parse(JSON.stringify(human));
  26. console.log(human instanceof Human); // true
  27. console.log(_human instanceof Human); // false

**

JSON

* json 是轻量级的数据交换格式,易于阅读和编写
* json 标准要求使用双引号包裹属性

  1. {
  2. "name": "zhangsan",
  3. "age": 18,
  4. "sex": "male"
  5. }

JSON.stringify(obj, propertyList, length)

* 一般用于向其他语言传输数据
* 可以在对象内部定义 toJSON 方法,返回需要序列化的对象,用于替代 propertyList 的作用

**_desc_** 序列化 **params** { any } obj **params** { array|null } propertyList 保存的属性数组,全部保存填 null,默认值:null **params** { number|string } length 为缩进的数量,string 为前导字符,默认值:0 **return** { string }

  1. var obj1 = {
  2. name: "zhangsan",
  3. age: 18
  4. };
  5. var obj2 = {
  6. name: "zhangsan",
  7. age: 18,
  8. toJSON: function() {
  9. return {
  10. name: this.name
  11. }
  12. }
  13. };
  14. console.log(JSON.stringify(obj1)); // '{ "name": "zhangsan", "age": 18 }'
  15. console.log(JSON.stringify(obj1, ["name"])); // '{ "name": "zhangsan" }'
  16. console.log(JSON.stringify(obj2)); // '{ "name": "zhangsan" }', 内置 toJSON 方法,实现部分属性序列化
  17. console.log(JSON.stringify(obj1, null, 4));
  18. /**
  19. * '{
  20. * "name": "zhangsan",
  21. * "age": 18
  22. * }'
  23. */
  24. console.log(JSON.stringify(obj1, null, "1234"));
  25. /**
  26. * '{
  27. * 1234"name": "zhangsan",
  28. * 1234"age": 18
  29. * }'
  30. */

JSON.parse(jsonStr)

* 反序列化返回值类型存在不确定性,应确定类型后再执行后续操作

**_desc_** 反序列化 **params** { object } obj **params** { string } jsonStr json 字符串 **return** { object } 除 string 外的其他类型

  1. var obj = {
  2. name: "zhangsan"
  3. };
  4. var jsonStr = JSON.stringify(obj);
  5. var json = JSON.parse(jsonStr);
  6. console.log(json); // { name: "zhangsan" }