[JS] ECMAScript 6 - Object : compare with c#

时间:2022-10-01 10:17:26

Ref: 对象的扩展

Outline:

  1. 属性的简洁表示法
  2. 属性名表达式
  3. 方法的 name 属性
  4. Object.is()
  5. Object.assign()
  6. 属性的可枚举性和遍历
  7. Object.getOwnPropertyDescriptors()
  8. __proto__属性,Object.setPrototypeOf(),Object.getPrototypeOf()
  9. super 关键字
  10. Object.keys(),Object.values(),Object.entries()
  11. 对象的扩展运算符

简洁表示法

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 属性

返回函数名(即方法名)。

[JS] ECMAScript 6 - Object : compare with c#

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

[JS] ECMAScript 6 - Object : compare with c#

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

key1对应的 Symbol 值有描述,key2没有。

[JS] ECMAScript 6 - Object : compare with c#

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一个打补丁的机会】

[JS] ECMAScript 6 - Object : compare with c#

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会直接返回该参数。

如果该参数不是对象,则会先转成对象,然后返回。【强制类型转换】

雷区:由于undefinednull无法转成对象,所以如果它们作为参数,就会报错。

Object.assign(undefined) // 报错
Object.assign(null) // 报错

雷区:如果undefinednull不在首参数,就不会报错。

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);  // 将DEFAULTSoptions合并成一个新对象,如果两者有同名属性,则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(): 忽略enumerablefalse的属性,只拷贝对象自身的可枚举的属性。

- Object.getOwnPropertyDescriptors方法

ES2017 引入了Object.getOwnPropertyDescriptors方法,返回指定对象所有自身属性(非继承属性)的描述对象。

例一:

let obj = { foo: 123 };

[JS] ECMAScript 6 - Object : compare with c#

例二:

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.valuesObject.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#的更多相关文章

  1. &lbrack;JS&rsqb; ECMAScript 6 - Variable &colon; compare with c&num;

    前言 范围包括:ECMAScript 新功能以及对象. 当前的主要目的就是,JS的学习 --> ECMAScript 6 入门 let 命令 js 因为let, i的范围限制在了循环中. var ...

  2. &lbrack;JS&rsqb; ECMAScript 6 - Class &colon; compare with c&num;

    Ref: Class 的基本语法 Ref: Class 的基本继承 许多面向对象的语言都有修饰器(Decorator)函数,用来修改类的行为.目前,有一个提案将这项功能,引入了 ECMAScript. ...

  3. &lbrack;JS&rsqb; ECMAScript 6 - Inheritance &colon; compare with c&num;

    这一章,估计是js最操蛋的一部分内容. 现代方法: 简介 Object.getPrototypeOf() super 关键字 类的 prototype 属性和__proto__属性 原生构造函数的继承 ...

  4. &lbrack;JS&rsqb; ECMAScript 6 - Prototype &colon; compare with c&num;

    开胃菜 prototype 对象 JavaScript 语言的继承则是通过“原型对象”(prototype). function Cat(name, color) { // <----构造函数 ...

  5. &lbrack;JS&rsqb; ECMAScript 6 - Array &colon; compare with c&num;

    扩展运算符(spread) 先复习下 rest 参数. (1) argument模式,但不够好. // https://blog.csdn.net/weixin_39723544/article/de ...

  6. &lbrack;JS&rsqb; ECMAScript 6 - Async &colon; compare with c&num;

    一段引言: Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大. 它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对 ...

  7. js types &amp&semi; primitive &amp&semi; object

    js types & primitive & object js 数据类型 typeof null // "object" typeof undefined // ...

  8. JS 深度拷贝 Object Array

    JS 深度拷贝 Object Array function cloneObj(o) { var isArray = o instanceof Array; var isObject = o insta ...

  9. JS如何遍历Object中的所有属性?

    JS如何遍历Object中的所有属性? var params = ""; for(var i in baseParams){ params += "&" ...

随机推荐

  1. java3

    1:在定义Long或者Float类型变量的时候,要加L或者f. 整数默认是int类型,浮点数默认是double. byte,short在定义的时候,他们接收的其实是一个int类型的值. 这个是自己做了 ...

  2. 大饱眼福 7款类型各异的CSS3实用菜单

    1.清新小图标的HTML5/CSS3侧边栏菜单 前我们分享过几款CSS3侧边栏菜单,像CSS3侧边栏菜单 带可爱的小图标菜单和CSS3侧边栏手风琴菜单,都非常不错.今天我们要分享的这款CSS3侧边栏菜 ...

  3. iOS-NSString-Base64String-Base64原理

    之前看到好多人找Str2Base64Str,还有好多自己写了方法的,仔细研究了下base64的编码原理(这个我写在下面),发现官方的API已经可以完成这项功能,这里贴出来供大家参考. 一言不合就上代码 ...

  4. android签名相关

    生成apk.keystore: 右键工程:Android tools——>Export Signed Application Package后,相册中截图: 一直下一步下一步,成功后jarsig ...

  5. 15&period; 使用Apache Curator管理ZooKeeper

    Apache ZooKeeper是为了帮助解决复杂问题的软件工具,它可以帮助用户从复杂的实现中解救出来. 然而,ZooKeeper只暴露了原语,这取决于用户如何使用这些原语来解决应用程序中的协调问题. ...

  6. python 素因子分解

    在使用python解决问题之前,我们先说一下,什么是素因子分解 所谓素因子分解就是,先找这个数的所有约数(约数即:a%b == 0,也就是a可以被b整除) 例如:20的约数集合为 [1, 2, 5, ...

  7. ISP PIPLINE &lpar;二&rpar; LensShading Correct

    what is the LSC? lens shading 分为:Y-shading , color shading. 在讲LSC之前,我们先来理解一个重要的术语--CRA(Chief ray ang ...

  8. mysql找安装路经,更改密码

    1:如果安装了mysql但是启动不了,可以到C:/Windows/System32的cmd.exe,用管理员身份打开,然后输入net strat mysql即可 2:忘记安装路经       sele ...

  9. spring-boot集成Springfox-Swagger2

    import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Co ...

  10. Git的杀手级功能之 一 远程仓库

    Git的杀手级功能之一:远程仓库 Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上. 一.注册GitHub账号,然后和本地Git仓库来关联免费获得Git远程仓库来学校git的远程仓 ...