[] 表达式

ES5中相关给对象新增一个属性可以通过.的方式来操作:

  1. var name = "张三";
  2. var person = {
  3. name: name
  4. };

ES6在对象属性名和变量同名的时候可以简写:

  1. var name = "张三";
  2. var person = {
  3. name
  4. };

对象方法也可以进行简写:

  1. var name = "张三";
  2. var person = {
  3. name,
  4. eat(){} // eat: function(){} 一样
  5. };

ES6容许定义对象属性的时候使用[]放入表达式:

  1. let name = "张三";
  2. var person = {
  3. ["na"+"me"]: name; // 和 name: name 一样
  4. };

使用[]表达式获取属性的时,可以通过变量来访问:

  1. let name = "n_a_m_e";
  2. let obj = {};
  3. obj[name] = 'zhangsan';
  4. console.log(obj); // {n_a_m_e: 'zhangsan'}
  5. console.log(obj[name]); // zhangsan

[]底层都是通过toString()方法进行转换:

  1. var myObject = {};
  2. myObject[true] = "foo";
  3. myObject[3] = "bar";
  4. myObject[myObject] = "baz";
  5. console.log(myObject["true"]); // foo
  6. console.log(myObject["3"]); // bar
  7. console.log(myObject["[object Object]"]); // baz
  8. consoloe.log(Object.prototype.toString.call(myObject)); // [object Object]

所以以下情况将会覆盖:

  1. const a = { a: 1 };
  2. const b = { b: 2 };
  3. const obj = {
  4. [a]: "valueA",
  5. [b]: "valueB",
  6. };
  7. console.log(obj); // {[object Object]: 'valueB'}

属性描述符

ES5通过Object.defineProperty()方法来对对象的属性进行描述定义,ES6新增了Object.getOwnPropertyDescriptor来获取属性的描述。
Object.defineProperty() / defineProperties()

  1. let obj = { a: 1 };
  2. console.log(Object.getOwnPropertyDescriptor(obj, "a"));
  3. // {value: 1, writable: true, enumerable: true, configurable: true}
  4. // writable可写 enumerable可枚举 configurable可配置(可删除) value值
  1. let obj = {};
  2. Object.defineProperty(obj, "a", {
  3. value: 10,
  4. writable: false,
  5. enumerable: true,
  6. configurable: false, // configurable 为false 的时候不能删除
  7. });
  8. // writable:false 且 configurable:false 的时候不能更改属性
  9. console.log(Object.getOwnPropertyDescriptor(obj, "a"));

新增方法

之前我们学习过ES5通过Object.defineProperty()可以对象的对象进行描述定义

  1. var obj = {};
  2. Object.defineProperty(obj, "name", {
  3. value: "张三",
  4. enumerable: false,
  5. writable: false,
  6. configurable: false,
  7. });
  8. console.log(obj); // {name: '张三'}
  9. obj.name = "李四";
  10. console.log(obj); // {name: '张三'}
  11. for (const key in obj) {
  12. console.log(key); // 空的,for 循环不会执行
  13. }
  14. delete obj.name;
  15. console.log(obj); // {name: '张三'}
  16. obj.age = 20;
  17. console.log(obj); // {age: 20, name: '张三'}

可以看到以上的代码,我们对objname属性进行了定义,这个时候name属性不能更改、枚举、删除,但是我们却可以为obj对象新增属性。

Object.preventExtensions(object) / Object.isExtensible(object)

:::info **Object.preventExtensions(object)**用来禁止对象拓展,使用该方法后对象不可新增属性,可以更改、删除和枚举属,返回当前对象。
Object.isExtensible(object)用来判断一个对象是否可以拓展,返回布尔值 :::

  1. let obj = { a: 10 };
  2. let res = Object.preventExtensions(obj);
  3. console.log(Object.isExtensible(obj)); // flase
  4. console.log(obj === res); // true
  5. console.log(obj); // { a: 10 }
  6. obj.a = 11;
  7. obj.b = 20;
  8. console.log(obj); // { a: 11 };
  9. // 使用 defineProperty 会报错!
  10. // Cannot define property c, object is not extensible
  11. Object.defineProperty(obj, "c", {
  12. value: 30,
  13. });

可以看到obj对象不能新增属性了。

  1. // 对数组进行包装
  2. var arr = [];
  3. Object.preventExtensions(arr);
  4. console.log(arr);
  5. arr.push(1); // Cannot add property 0, object is not extensible
  6. console.log(arr);

Object.seal(object) / Object.isSealed(object)

:::info **Object.seal(object)**用来密封对象,使用该方法后对象不可新增、删除属性,可以更改、枚举属性,返回当前对象。
Object.isSealed(object)用来判断一个对象是否被密封,返回布尔值 :::

  1. let obj = { name: "李四" };
  2. let res = Object.seal(obj);
  3. console.log(Object.isSealed(obj)); // true
  4. console.log(obj === res); // true
  5. obj.age = "30";
  6. console.log(obj); // {name: '李四'}
  7. obj.name = "王五";
  8. console.log(obj); // {name: '王五'}
  9. delete obj.name;
  10. console.log(obj); // {name: '王五'}
  11. for (const key in obj) {
  12. console.log(obj[key]); // 王五
  13. }

Object.freeze(object) / Object.isFrozen(object)

:::info **Object.freeze(object)**用来冻结对象,使用该方法后对象不可新增、更改、删除属性,可以枚举属性,返回当前对象。
Object.isFrozen(object)用来判断一个对象是否被冻结,返回布尔值 :::

  1. let obj = { name: "李四" };
  2. let res = Object.freeze(obj);
  3. console.log(Object.isFrozen(obj)); // true
  4. console.log(obj === res); // true
  5. obj.age = "30";
  6. console.log(obj); // {name: '李四'}
  7. obj.name = "王五";
  8. console.log(obj); // {name: '李四'}
  9. delete obj.name;
  10. console.log(obj); // {name: '李四'}
  11. for (const key in obj) {
  12. console.log(obj[key]); // 李四
  13. }

:::danger ⚠️ 注意
以上三个方法都是浅拷贝!!!需要自己进行封装递归。 :::

  1. var obj = {
  2. name: "张三",
  3. age: 40,
  4. son: {
  5. name: "李四",
  6. },
  7. };
  8. Object.freeze(obj);
  9. obj.age = 50;
  10. obj.son.age = 20;
  11. console.log(obj); // {name: '张三', age: 40, son: {name: '李四', age: 20}}

封装一个简单的冻结方法:

  1. function myFreeze(obj) {
  2. Object.freeze(obj);
  3. for (const key in object) {
  4. if (Object.hasOwnProperty.call(object, key)) {
  5. if (typeof obj[key] === "object" && obj[key] !== null) {
  6. myFreeze(obj[key]);
  7. }
  8. }
  9. }
  10. }

Object.is(param, param)

ES5的时候值比较的时候有两个bug
1、NaN不和任何值相等,包括自己
2、-0+0相比返回真值
Object.is()方法就是用来比较两个值是否相等。

  1. console.log(Object.is(NaN, NaN)); // true
  2. console.log(Object.is(-0, +0)); // false
  3. console.log(Object.is({}, {})); // false
  4. console.log(Object.is(false, 0)); // false
  5. console.log(Object.is(undefind, null)); // false

Object.assign(target,sources)

:::info Object.assign用于将多个对象进行合并,返回目标对象。 :::

target合并到哪里,sourses把谁进行合并

  1. let target = {};
  2. let obj = { a: 1 };
  3. let ob2 = { b: 2 };
  4. let res = Object.assign(target, obj, ob2);
  5. console.log(target); // { a: 1; b: 2 };
  6. console.log(target === res); // true

同名的属性,后面的属性会覆盖前面的属性:

  1. const tar = { a: 1, b: 1 };
  2. const tar2 = { b: 2, c: 2 };
  3. const tar3 = { c: 3 };
  4. Object.assign(tar, tar2, tar3);
  5. console.log(tar); // {a: 1, b: 2, c: 3}

targetundefindnull的时候,无法进行合并

  1. Object.assign(undefined, { a: 1 });
  2. // Cannot convert undefined or null to object

target是基本数据的时候,会进行将数据进行包装类

  1. let res = Object.assign(1, { a: 1 });
  2. console.log(res); // { 1 , a: 1 }
  3. let res1 = Object.assign(true, { a: 1 });
  4. console.log(res1); // { true , a: 1 }

sourceundefindnull的时候会静默失败

  1. let res = Object.assign({}, undefined, null, { a: 1 });
  2. console.log(res); // {a: 1}

source不能进行枚举遍历的时候,也会静默失败

  1. let res = Object.assign({}, 1);
  2. let res1 = Object.assign({}, "123");
  3. console.log(res); // {}
  4. console.log(res1); // {0: '1', 1: '2', 2: '3'}
  1. var obj = { a: 3 };
  2. Object.defineProperty(obj, "b", {
  3. value: 4,
  4. });
  5. let res = Object.assign({}, obj);
  6. console.log(res); // {a: 3}

不能克隆原型上的属性

Object.create的第二个参数也是对属性进行描述定义

  1. var obj = Object.create(
  2. { foo: 1 },
  3. {
  4. bar: {
  5. value: 2,
  6. },
  7. baz: {
  8. value: 3,
  9. enumerable: true,
  10. },
  11. }
  12. );
  13. console.log(obj); // {baz: 3, bar: 2}
  14. console.log(obj.foo); // 1
  15. let res = Object.assign({}, obj);
  16. console.log(res); // {baz: 3}
  17. console.log(res.foo); // undefined

Symbol数据类型也可以进行合并

  1. let res = Object.assign({ a: 1 }, { [Symbol("b")]: 2 });
  2. console.log(res); // {a: 1, Symbol(b): 2}

⚠️ 注意:合并的数据都是浅拷贝

  1. const obj1 = { a: { b: 2 } };
  2. const obj2 = Object.assign({}, obj1);
  3. obj1.a.b = 20;
  4. console.log(obj2); // {a: {b: 20}}

⚠️ 注意:当合并数组的时候,是根据数组的下标进行合并,因为数组是一种特殊的对象,下标就是数组元素的key

  1. let res = Object.assign([1, 2, 3], [4, 5]);
  2. console.log(res); // [4, 5, 3]

Object.assign设置默认值:

  1. function test(option) {
  2. let defaultObj = {
  3. url: "www.baidu.com",
  4. method: "post",
  5. };
  6. option = Object.assign({}, defaultObj, option);
  7. return option;
  8. }
  9. let res = test({
  10. url: "www.zhidao.com",
  11. method: "get",
  12. });
  13. console.log(res); // {url: 'www.zhidao.com', method: 'get'}

Object.setPrototypeOf() / Object.getPrototypeOf()

:::info 用于设置/获取对象的原型 ::: 在ES5的时候想要获取对象的原型需要使用隐式属性__proto____proto__有一下几个缺点:
1、不够语义化
2、访问速度比较慢
3、当修改原型的时候所有继承自该原型的对象都会受到影响
所以ES6新增了Object.getPrototypeOf()用来获取对象的原型。

  1. let obj = {};
  2. let res = Object.getPrototypeOf(obj);
  3. console.log(res)

image.png

Object.setPrototypeOf()用来设置一个对象的原型,返回原对象。

  1. let obj = {};
  2. let res = Object.setPrototypeOf(obj, { b: 20 });
  3. console.log(obj, res, obj === res); // true

image.png

当目标不是对象的时候,会进行包装类进行转换,然后静默失败:

  1. let num = 1;
  2. let res = Object.setPrototypeOf(num, { b: 20 });
  3. console.log(Object.getPrototypeOf(num));

image.png

stringboolean都会如number数据类型一样静默失败,但是当目标是undefindnull的时候,会抛出异常:

  1. Object.setPrototypeOf(undefined, { b: 20 });
  2. // Object.setPrototypeOf called on null or undefined

然后就是对象遍历相关的方法:

Object.keys() / Object.values() / Object.entries()

:::info Object.keys()以数组的形式返回对象的key
Object.values()以数组的形式返回对象的value
Object.entries()以二维数组的形式返回对象的keyvalue

⚠️ 注意
以上三个方法只返回可枚举的属性、非原型上的属性 :::

  1. const foo = {
  2. a: 10,
  3. b: 20,
  4. c: 30,
  5. };
  6. Object.defineProperty(foo, "d", { value: 40 });
  7. Object.setPrototypeOf(foo, {j: 100, z: 200 });
  8. console.log(foo);

image.png
不会返回原型上的属性,也不会返回不可枚举的属性。

  1. console.log(Object.keys(foo)); // ['a', 'b', 'c']
  2. console.log(Object.values(foo)); // [10, 20, 30]
  3. console.log(Object.entries(foo)); // [['a', 10], ['b', 20], ['c', 30]]

方法也可以用于其他数据类型:

  1. console.log(Object.keys([1, 2, 3])); // ['0', '1', '2'],数组的下标
  2. console.log(Object.keys(1)); // []
  3. console.log(Object.keys(true)); // []
  4. console.log(Object.keys("abc")); // ['0', '1', '2']

super

:::info superthis类似,但是「指向」不同。
super指向对象的原型对象,this的指向之前说过很多次,这里不再赘述。

⚠️ 注意
使用super有以下限制:
1、必须是对象的方法
2、方法必须是简写的形式 :::

  1. let proto = {
  2. b: 20,
  3. bar() {
  4. console.log("this is proto: " + this.b);
  5. },
  6. };
  7. let obj = {
  8. a: 10,
  9. // foo: super.y, // 属性不行
  10. // 普通函数不能使用
  11. // foo: function() {
  12. // console.log(super.b); // 报错
  13. // },
  14. // 箭头函数不能使用
  15. // foo: () => {
  16. // console.log(super.b); // 报错
  17. // },
  18. // 必须是对象的方法,方法必须是简写的方式才能使用 super
  19. foo() {
  20. console.log(super.b);
  21. super.bar();
  22. },
  23. };
  24. Object.setPrototypeOf(obj, proto);
  25. console.log(obj);
  26. obj.foo();

更多细节: