ES6对象知识扩展(ECMAScript 6 入门笔记)
来源:互联网 发布:互联网数据 编辑:程序博客网 时间:2024/05/17 22:02
1.属性的简洁表示法:
ES6允许直接写入变量和函数:
let birth = '2000/01/01';const Person = { name: '张三', //等同于birth: birth birth, // 等同于hello: function ()... hello() { console.log('我的名字是', this.name); }};
如果某个方法的值是一个Generator函数,前面需要加上*号:const obj = { * m() { yield 'hello world'; }};
2.属性名表达式:
JS定义对象的属性,有两种方式:
// 方法一obj.foo = true;// 方法二obj['a' + 'bc'] = 123;
但是,如果使用字面量方式定义对象(使用大括号),在 ES5 中只能使用方法一(标识符)定义属性。
var obj = { foo: true, abc: 123};
ES6 允许字面量定义对象时,用方法二(表达式)作为对象的属性名,即把表达式放在方括号内。
let propKey = 'foo';let obj = { [propKey]: true, ['a' + 'bc']: 123};
注意,属性名表达式与简洁表示法,不能同时使用,会报错。
// 报错const foo = 'bar';const bar = 'abc';const baz = { [foo] };// 正确const foo = 'bar';const baz = { [foo]: 'abc'};
注意,属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串[object Object]
,这一点要特别小心。
const keyA = {a: 1};const keyB = {b: 2};const myObject = { [keyA]: 'valueA', [keyB]: 'valueB'};myObject // Object {[object Object]: "valueB"}
上面代码中,[keyA]
和[keyB]
得到的都是[object Object]
,所以[keyB]
会把[keyA]
覆盖掉,而myObject
最后只有一个[object Object]
属性。
3.方法的name属性:
返回函数名(即方法名):
如果对象的方法使用了取值函数(getter
)和存值函数(setter
),则name
属性不是在该方法上面,而是该方法的属性的描述对象的get
和set
属性上面,返回值是方法名前加上get
和set:
const obj = { get foo() {}, set foo(x) {}};obj.foo.name// TypeError: Cannot read property 'name' of undefinedconst descriptor = Object.getOwnPropertyDescriptor(obj, 'foo');descriptor.get.name // "get foo"descriptor.set.name // "set foo"
有两种特殊情况:bind
方法创造的函数,name
属性返回bound
加上原函数的名字;Function
构造函数创造的函数,name
属性返回anonymous
(new Function()).name // "anonymous"var doSomething = function() { // ...};doSomething.bind().name // "bound doSomething"
如果对象的方法是一个 Symbol 值,那么name
属性返回的是这个 Symbol 值的描述
const key1 = Symbol('description');const key2 = Symbol();let obj = { [key1]() {}, [key2]() {},};obj[key1].name // "[description]"obj[key2].name // ""
4.Object.is();
ES5 比较两个值是否相等,只有两个运算符:相等运算符(==
)和严格相等运算符(===
)。它们都有缺点,前者会自动转换数据类型,后者的NaN
不等于自身,以及+0
等于-0
。
ES6 提出同值相等算法,用来解决这个问题。Object.is
就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。不同之处只有两个:一是+0
不等于-0
,二是NaN
等于自身。
Object.is('foo', 'foo')// trueObject.is({}, {})// false
+0 === -0 //trueNaN === NaN // falseObject.is(+0, -0) // falseObject.is(NaN, NaN) // true
5.Object.assign();
Object.assign
方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。方法的第一个参数是目标对象,后面的参数都是源对象。
注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
const target = { a: 1, b: 1 };const source1 = { b: 2, c: 2 };const source2 = { c: 3 };Object.assign(target, source1, source2);target // {a:1, b:2, c:3}
除了字符串会以数组形式,拷贝入目标对象,其他值都不会产生效果。只拷贝源对象的自身属性(不拷贝继承属性)
布尔值、数值、字符串分别转成对应的包装对象,可以看到它们的原始值都在包装对象的内部属性[[PrimitiveValue]]
上面,这个属性是不会被Object.assign
拷贝的。只有字符串的包装对象,会产生可枚举的实义属性,那些属性则会被拷贝:
const v1 = 'abc';const v2 = true;const v3 = 10;const obj = Object.assign({}, v1, v2, v3);console.log(obj); // { "0": "a", "1": "b", "2": "c" }
Object(true) // {[[PrimitiveValue]]: true}Object(10) // {[[PrimitiveValue]]: 10}Object('abc') // {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}
属性名为 Symbol 值的属性,也会被Object.assign
拷贝
Object.assign({ a: 'b' }, { [Symbol('c')]: 'd' })// { a: 'b', Symbol(c): 'd' }
注意点:1)该方法为浅拷贝,不是深拷贝,得到的是对象的引用
2)同名属性的值会替换
3)可以用来处理数组,并视为对象
Object.assign([1, 2, 3], [4, 5])// [4, 5, 3]
上面代码中,Object.assign
把数组视为属性名为 0、1、2 的对象,因此源数组的 0 号属性4
覆盖了目标数组的 0 号属性1
4)Object.assign
只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制:
const source = { get foo() { return 1 }};const target = {};Object.assign(target, source)// { foo: 1 }
代码中,source
对象的foo
属性是一个取值函数,Object.assign
不会复制这个取值函数,只会拿到值以后,将这个值复制过去。常见用途:1)为对象添加属性
class Point { constructor(x, y) { Object.assign(this, {x, y}); }}
2)为对象添加方法Object.assign(SomeClass.prototype, { someMethod(arg1, arg2) { ··· }, anotherMethod() { ··· }});// 等同于下面的写法SomeClass.prototype.someMethod = function (arg1, arg2) { ···};SomeClass.prototype.anotherMethod = function () { ···};
3)克隆对象function clone(origin) { return Object.assign({}, origin);}
不过,采用这种方法克隆,只能克隆原始对象自身的值,不能克隆它继承的值。如果想要保持继承链,可以采用下面的代码。
function clone(origin) { let originProto = Object.getPrototypeOf(origin); return Object.assign(Object.create(originProto), origin);}
4)合并多个对象:
将多个对象合并到某个对象:
const merge = (target, ...sources) => Object.assign(target, ...sources);
合并后返回一个新的对象:const merge = (...sources) => Object.assign({}, ...sources);
5)为属性指定默认值:const DEFAULTS = { logLevel: 0, outputFormat: 'html'};function processContent(options) { options = Object.assign({}, DEFAULTS, options); console.log(options); // ...}
6.属性的可枚举性和遍历:
对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor
方法可以获取该属性
的描述对象
let obj = { foo: 123 };Object.getOwnPropertyDescriptor(obj, 'foo')// {// value: 123,// writable: true,// enumerable: true,// configurable: true// }
描述对象的enumerable
属性,称为”可枚举性“,如果该属性为false
,就表示某些操作会忽略当前属性。
目前,有四个操作会忽略enumerable
为false
的属性。
for...in
循环:只遍历对象自身的和继承的可枚举的属性。
Object.keys()
:返回对象自身的所有可枚举的属性的键名。
JSON.stringify()
:只串行化对象自身的可枚举的属性。
Object.assign()
: 忽略enumerable
为false
的属性,只拷贝对象自身的可枚举的属性。
ES6 一共有 5 种方法可以遍历对象的属性。
(1)for...in :
for...in
循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
(2)Object.keys(obj):
Object.keys
返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
(3)Object.getOwnPropertyNames(obj):
Object.getOwnPropertyNames
返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols
返回一个数组,包含对象自身的所有 Symbol 属性的键名。
(5)Reflect.ownKeys(obj)
Reflect.ownKeys
返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则。
首先遍历所有数值键,按照数值升序排列。
其次遍历所有字符串键,按照加入时间升序排列。
最后遍历所有 Symbol 键,按照加入时间升序排列。
7 Object.setPrototypeOf
方法:
Object.setPrototypeOf
方法的作用与__proto__
相同,用来设置一个对象的prototype
对象,返回参数对象本身
// 格式Object.setPrototypeOf(object, prototype)// 用法const o = Object.setPrototypeOf({}, null);
读取一个对象的原型对象,若参数不是对象,则转换成对象如果参数是undefined
或null
,它们无法转为对象,所以会报错。
Object.getPrototypeOf(obj);
// 等同于 Object.getPrototypeOf(Number(1))Object.getPrototypeOf(1)// Number {[[PrimitiveValue]]: 0}// 等同于 Object.getPrototypeOf(String('foo'))Object.getPrototypeOf('foo')// String {length: 0, [[PrimitiveValue]]: ""}// 等同于 Object.getPrototypeOf(Boolean(true))Object.getPrototypeOf(true)// Boolean {[[PrimitiveValue]]: false}Object.getPrototypeOf(1) === Number.prototype // trueObject.getPrototypeOf('foo') === String.prototype // trueObject.getPrototypeOf(true) === Boolean.prototype // true
8.super:
指向当前对象的原型对象
const proto = { foo: 'hello'};const obj = { find() { return super.foo; }};Object.setPrototypeOf(obj, proto);obj.find() // "hello"
注意,super
关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错
// 报错const obj = { foo: super.foo}// 报错const obj = { foo: () => super.foo}// 报错const obj = { foo: function () { return super.foo }}
JavaScript 引擎内部,super.foo
等同于Object.getPrototypeOf(this).foo
(属性)或Object.getPrototypeOf(this).foo.call(this)
(方法)。
const proto = { x: 'hello', foo() { console.log(this.x); },};const obj = { x: 'world', foo() { super.foo(); }}Object.setPrototypeOf(obj, proto);obj.foo() // "world"
9.Object.keys():
ES5 引入了Object.keys
方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名
var obj = { foo: 'bar', baz: 42 };Object.keys(obj)// ["foo", "baz"]
ES2017 引入了跟Object.keys
配套的Object.values
和Object.entries
,作为遍历一个对象的补充手段,供for...of
循环使用。
Object.values
方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。返回数组的成员顺序,与本章的《属性的遍历》部分介绍的排列规则一致。会过滤属性名为 Symbol 值的属性。
如果Object.values
方法的参数是一个字符串,会返回各个字符组成的一个数组。
Object.values('foo')// ['f', 'o', 'o']
Object.entries
方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
const obj = { foo: 'bar', baz: 42 };Object.entries(obj)// [ ["foo", "bar"], ["baz", 42] ]
Object.entries
的基本用途是遍历对象的属性
let obj = { one: 1, two: 2 };for (let [k, v] of Object.entries(obj)) { console.log( `${JSON.stringify(k)}: ${JSON.stringify(v)}` );}// "one": 1// "two": 2
Object.entries
方法的另一个用处是,将对象转为真正的Map
结构
const obj = { foo: 'bar', baz: 42 };const map = new Map(Object.entries(obj));map // Map { foo: "bar", baz: 42 }
10.对象扩展运算符:
1)解构赋值:对象的解构赋值用于从一个对象取值,相当于将所有可遍历的、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面。不能复制继承自原型对象的属性。
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };x // 1y // 2z // { a: 3, b: 4 }
2)扩展运算符:(...
)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。
let z = { a: 3, b: 4 };let n = { ...z };n // { a: 3, b: 4 }
如果想完整克隆一个对象,还拷贝对象原型的属性,可以采用下面的写法。
// 写法二const clone2 = Object.assign( Object.create(Object.getPrototypeOf(obj)), obj);// 写法三const clone3 = Object.create( Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj))
- ES6对象知识扩展(ECMAScript 6 入门笔记)
- ES6数组扩展知识(ECMAScript 6 入门笔记)
- ES6关于函数的扩展知识(ECMAScript 6 入门笔记)
- ES6-Symbol(ECMAScript 6 入门笔记)
- ECMAScript 6 学习笔记----对象的扩展
- ES6-Set 和 Map 数据结构(ECMAScript 6 入门笔记)
- ES6(ECMAScript 6)学习笔记
- ES6(ECMAScript 6 ) 解构 扩展运算符
- es6入门-对象的扩展
- Promise对象——ECMAScript 6 入门笔记(一)
- ECMAScript 6 入门--Promise 对象
- 《ECMAScript 6入门》笔记6
- ECMAScript 6 入门学习笔记
- ECMAScript 6入门 学习笔记
- 《ECMAScript 6入门》笔记1
- 《ECMAScript 6入门》笔记2
- 《ECMAScript 6入门》笔记3
- 《ECMAScript 6入门》笔记4
- frameset宽度设置及居中
- 数据库优化技巧
- 【Scikit-Learn 中文文档】分解成分中的信号(矩阵分解问题)
- Reflection—Method
- spring-boot项目在外部tomcat环境下部署
- ES6对象知识扩展(ECMAScript 6 入门笔记)
- 【Scikit-Learn 中文文档】协方差估计 / 经验协方差 / 收敛协方差 / 稀疏逆协方差 / Robust 协方差估计
- Mysql——添加表字段到数据较大表导致表锁死
- ubuntu mv和cp命令
- Uboot配置编译及常见指令
- C\C++中strcat()函数
- CCF CSP 201709-2 公共钥匙盒
- Salesforce -- Apex发送电子邮件
- Python基础篇之List四.(添加新元素)