[JS] ECMAScript 6 - Object : compare with c#
Ref: 对象的扩展
Outline:
- 属性的简洁表示法
- 属性名表达式
- 方法的 name 属性
- Object.is()
- Object.assign()
- 属性的可枚举性和遍历
- Object.getOwnPropertyDescriptors()
- __proto__属性,Object.setPrototypeOf(),Object.getPrototypeOf()
- super 关键字
- Object.keys(),Object.values(),Object.entries()
- 对象的扩展运算符
简洁表示法
ES6 允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
- 属性:
// 推荐
function f(x, y) {
return {x, y};
} // 等同于 function f(x, y) {
return {x: x, y: y};
} f(1, 2) // Object {x: 1, y: 2}
- 方法:
// 推荐
const o = {
method() { return "Hello!"; }
}; // 等同于 const o = {
method: function() {
return "Hello!";
}
};
- 变量名就是属性名的写法:
let ms = {};
function getItem (key) {
return key in ms ? ms[key] : null;
}
function setItem (key, value) {
ms[key] = value;
}
function clear () {
ms = {};
}
module.exports = { getItem, setItem, clear }; // <---- 如此,简洁了许多
// 等同于
module.exports = {
getItem: getItem,
setItem: setItem,
clear: clear
};
- 属性的赋值器(setter)和取值器(getter):
const cart = {
_wheels: 4,
// 采用了简洁的写法
get wheels () {
return this._wheels;
},
// 采用了简洁的写法
set wheels (value) {
if (value < this._wheels) {
throw new Error('数值太小了!');
}
this._wheels = value;
}
}
- 定义属性名 - 把表达式放在方括号内
let lastWord = 'last word';
const a = {
'first word': 'hello',
[lastWord]: 'world'
};
a['first word'] // "hello"
a[lastWord] // "world"
a['last word'] // "world"
- 定义方法名 - 把表达式放在方括号内
let obj = {
['h' + 'ello']() {
return 'hi';
}
};
obj.hello() // hi
雷区:注意对[...]的理解
// 报错
const foo = 'bar';
const bar = 'abc';
const baz = { [foo] }; // bar有不是值,当然不能这么写;[]只是告诉编译器,你需要计算一下才能得到结果 // 正确
const foo = 'bar';
const baz = { [foo]: 'abc'};
雷区:[keyA]和[keyB]得到的都是[object Object],所以[keyB]会把[keyA]覆盖掉,而myObject最后只有一个[object Object]属性。
const keyA = {a: 1};
const keyB = {b: 2};
const myObject = {
[keyA]: 'valueA',
[keyB]: 'valueB' // Object的内部细节看不到,所以就引发了”覆盖“.
};
myObject // Object {[object Object]: "valueB"}
对象方法的 name 属性
返回函数名(即方法名)。

get or set方法,需要特殊处理:
const obj = {
get foo() {},
set foo(x) {}
};
obj.foo.name
// TypeError: Cannot read property 'name' of undefined
const descriptor = Object.getOwnPropertyDescriptor(obj, 'foo'); // <---- 需要特殊处理
descriptor.get.name // "get foo"
descriptor.set.name // "set foo"
有两种特殊情况:
bind方法创造的函数 --> name属性返回bound加上原函数的名字;
Function构造函数创造的函数 --> name属性返回anonymous。

如果对象的方法是一个 Symbol 值,那么name属性返回的是这个 Symbol 值的描述。
key1对应的 Symbol 值有描述,key2没有。

Object.is()
给相等运算符(==)和严格相等运算符(===)进一步加了补丁。
与严格比较运算符(===)的行为基本一致。
不同之处只有两个:一是+0不等于-0,二是NaN等于自身。
Object.is('foo', 'foo')
// true
Object.is({}, {})
// false
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
ES5 可以通过下面的代码,部署Object.is。【给es5一个打补丁的机会】

Object.assign()
将源对象(source)的所有可枚举属性,复制到目标对象(target)。This is 是浅拷贝!
如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
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}
如果只有一个参数,Object.assign会直接返回该参数。
如果该参数不是对象,则会先转成对象,然后返回。【强制类型转换】
雷区:由于undefined和null无法转成对象,所以如果它们作为参数,就会报错。
Object.assign(undefined) // 报错
Object.assign(null) // 报错
雷区:如果undefined和null不在首参数,就不会报错。
let obj = {a: 1};
Object.assign(obj, undefined) === obj // true
Object.assign(obj, null) === obj // true
雷区:只有字符串的包装对象,会产生可枚举属性;数值和布尔值都会被忽略。
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' }
把数组视为对象,以及同名属性(index)的替换
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
取值函数的处理
const source = {
get foo() { return 1 }
};
const target = {};
Object.assign(target, source)
// { foo: 1 }
常见用途
- 为对象添加属性/方法
class Point {
constructor(x, y) {
Object.assign(this, {x, y}); // 将x属性和y属性添加到Point类的对象实例
}
}
// 方法
Object.assign(SomeClass.prototype, {
someMethod(arg1, arg2) { // 直接写进来即可
···
},
anotherMethod() { // 直接写进来即可
···
}
});
-----------------------------------------------------------------------
// 等同于下面的写法
SomeClass.prototype.someMethod = function (arg1, arg2) {
···
};
SomeClass.prototype.anotherMethod = function () {
···
};
- 克隆对象
function clone(origin) {
return Object.assign({}, origin);
}
// 如果想要保持继承链,可以采用下面的代码
function clone(origin) {
let originProto = Object.getPrototypeOf(origin);
return Object.assign(Object.create(originProto), origin);
}
- 合并多个对象
const merge =
(target, ...sources) => Object.assign(target, ...sources); const merge =
(...sources) => Object.assign({}, ...sources); // 合并后返回一个新对象
- 为属性指定默认值
const DEFAULTS = {
logLevel: 0,
outputFormat: 'html'
};
function processContent(options) {
options = Object.assign({}, DEFAULTS, options); // 将DEFAULTS和options合并成一个新对象,如果两者有同名属性,则option的属性值会覆盖DEFAULTS的属性值。
console.log(options);
// ...
}
--------------------------------------------------
const DEFAULTS = {
url: {
host: 'example.com',
port: 7070
},
};
processContent({ url: {port: 8000} }) // 不是替换port,而是直接把url给覆盖掉了,哈哈
// {
// url: {port: 8000}
// }
属性的可枚举性和遍历
- 属性的描述对象(Descriptor)
描述对象(Descriptor),用来控制该属性的行为。
- Object.getOwnPropertyDescriptor方法
如下:描述对象的enumerable属性,称为”可枚举性“,如果该属性为false,就表示某些操作会忽略当前属性。
for...in循环:只遍历对象自身的和继承的可枚举的属性。Object.keys():返回对象自身的所有可枚举的属性的键名。JSON.stringify():只串行化对象自身的可枚举的属性。Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。
- Object.getOwnPropertyDescriptors方法
ES2017 引入了Object.getOwnPropertyDescriptors方法,返回指定对象所有自身属性(非继承属性)的描述对象。
例一:
let obj = { foo: 123 };

例二:
Object.getOwnPropertyDescriptor( Object.prototype, 'toString' ).enumerable
// false Object.getOwnPropertyDescriptor( [], 'length' ).enumerable
// false Object.getOwnPropertyDescriptor( class {foo() {}}.prototype, 'foo' ).enumerable
// false
ES6 规定,所有 Class 的原型的方法都是不可枚举的。
- 属性的遍历
(1)for...in
(2)Object.keys(obj)
(3)Object.getOwnPropertyNames(obj)
(4)Object.getOwnPropertySymbols(obj)
(5)Reflect.ownKeys(obj)
以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则。
- 首先遍历所有数值键,按照数值升序排列。
- 其次遍历所有字符串键,按照加入时间升序排列。
- 最后遍历所有 Symbol 键,按照加入时间升序排列。
Reflect.ownKeys({ [Symbol()]:, b:, :, :, a: })
// ['2', '10', 'b', 'a', Symbol()]
遍历对象
ES2017 引入了跟Object.keys配套的Object.values和Object.entries,作为遍历一个对象的补充手段,供for...of循环使用。
- Object.keys()
let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };
for (let key of keys(obj)) {
console.log(key); // 'a', 'b', 'c'
}
for (let value of values(obj)) {
console.log(value); // 1, 2, 3
}
for (let [key, value] of entries(obj)) {
console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}
- Object.values()
只返回对象自身的可遍历的属性,比如value是个对象,那么就要将该对象内的enumerate设置为true,才能遍历到。
const obj = Object.create({}, {p: {value: 42}});
Object.values(obj) // []
-------------------------------------------------
const obj = Object.create({}, {p:
{
value: 42,
enumerable: true
}
});
Object.values(obj) // [42]
- Object.entries()
返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
解构赋值与扩展运算符
略,之前已有总结。
[JS] ECMAScript 6 - Object : compare with c#的更多相关文章
- [JS] ECMAScript 6 - Variable : compare with c#
前言 范围包括:ECMAScript 新功能以及对象. 当前的主要目的就是,JS的学习 --> ECMAScript 6 入门 let 命令 js 因为let, i的范围限制在了循环中. var ...
- [JS] ECMAScript 6 - Class : compare with c#
Ref: Class 的基本语法 Ref: Class 的基本继承 许多面向对象的语言都有修饰器(Decorator)函数,用来修改类的行为.目前,有一个提案将这项功能,引入了 ECMAScript. ...
- [JS] ECMAScript 6 - Inheritance : compare with c#
这一章,估计是js最操蛋的一部分内容. 现代方法: 简介 Object.getPrototypeOf() super 关键字 类的 prototype 属性和__proto__属性 原生构造函数的继承 ...
- [JS] ECMAScript 6 - Prototype : compare with c#
开胃菜 prototype 对象 JavaScript 语言的继承则是通过“原型对象”(prototype). function Cat(name, color) { // <----构造函数 ...
- [JS] ECMAScript 6 - Array : compare with c#
扩展运算符(spread) 先复习下 rest 参数. (1) argument模式,但不够好. // https://blog.csdn.net/weixin_39723544/article/de ...
- [JS] ECMAScript 6 - Async : compare with c#
一段引言: Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大. 它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对 ...
- js types & primitive & object
js types & primitive & object js 数据类型 typeof null // "object" typeof undefined // ...
- JS 深度拷贝 Object Array
JS 深度拷贝 Object Array function cloneObj(o) { var isArray = o instanceof Array; var isObject = o insta ...
- JS如何遍历Object中的所有属性?
JS如何遍历Object中的所有属性? var params = ""; for(var i in baseParams){ params += "&" ...
随机推荐
- memcache 在php中的用法
memcached 的安装方法详见我博客的另一个页面:http://www.cnblogs.com/chrdai/p/6656443.html 用法: 一.memcache 连接命令: 1.memca ...
- 来自极客头条的 35 个 Java 代码性能优化总结
前言 代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用, ...
- C#高级编程9-第13章 异步编程
异步编程 1)异步编程的重要性 在C#5.0中提供了关键字:async和await 使用异步编程后台运行方法调用,程序的运行过程中就不会一直处于等待中.便于用户继续操作. 异步编程有3种模式:异步模式 ...
- AngularJS中控制器继承
本篇关注AngularJS中的控制器继承,了解属性和方法是如何被继承的. 嵌套控制器中属性是如何被继承的? ==属性值是字符串 myApp.controller("ParentCtrl&qu ...
- .ipynb文件转.py文件
到要转的demo.ipynb所在目录下,然后输入命令: jupyter nbconvert --to script demo.ipynb
- lua去掉字符串中的UTF-8的BOM三个字节
废话不多说,还是先说点吧,项目中lua读取的text文件如果有BOM,客户端解析就会报错,所以我看了看,任务编辑器swGameTaskEditor 在写入文件的时候,也不知道为什么有的文件就是UTF- ...
- [Spring Unit Testing] Spring Unit Testing with a Java Context
For example, we want to test against a implemataion: package com.example.in28minutes.basic; import o ...
- SqlSession介绍
SqlSession是MyBatis的关键对象,是执行持久化操作的对象,类似于JDBC中的Connection.它是应用程序与持久存储层之间执行交互操作的一个单线程对象,也是MyBatis执行持久化操 ...
- C# System.Collections.SortedList
using System; using System.Collections; public class SamplesSortedList { public static void Main() { ...
- SoapUI Pro Project Solution Collection –Easy develop Groovy Script to improve SoapUI ability
As you know the groovy script and java script language is the soapui supported .but unfortunately So ...