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

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

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

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

雷区:由于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 };

例二:

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. [JS] ECMAScript 6 - Variable : compare with c#

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

  2. [JS] ECMAScript 6 - Class : compare with c#

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

  3. [JS] ECMAScript 6 - Inheritance : compare with c#

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

  4. [JS] ECMAScript 6 - Prototype : compare with c#

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

  5. [JS] ECMAScript 6 - Array : compare with c#

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

  6. [JS] ECMAScript 6 - Async : compare with c#

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

  7. js types & primitive & 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. jdk9+版本的bug

    今天从jvm大神"你假笨"的公众号上,看到一个jdk 9+版本的编译bug,记录一下: public class JavacEvalBug{ private static Stri ...

  2. Knockout.Js官网学习(加载或保存JSON数据)

    前言 Knockout可以实现很复杂的客户端交互,但是几乎所有的web应用程序都要和服务器端交换数据(至少为了本地存储需要序列化数据),交换数据最方便的就是使用JSON格式 – 大多数的Ajax应用程 ...

  3. python3简单使用requests 用户代理,cookie池

    官方文档:http://docs.python-requests.org/en/master/ 参考文档:http://www.cnblogs.com/zhaof/p/6915127.html#und ...

  4. H5使用Swiper过程中遇到的滑动冲突

    一.问题 (1)PC端可以鼠标可以拖动中间的轮子让页面上下滑动,点击左键按着也是拖不动 (2)手机端浏览H5手指不能滑动页面,导致很多页面下面的文字看不到 二.解决问题 1.下面分先说css的问题,主 ...

  5. Android性能优化-内存优化

    原文链接 Manage Your App’s Memory 前言 在任何软件开发环境中,RAM都是比较珍贵的资源.在移动操作系统上更是这样,因为它们的物理内存通常受限.尽管在ART和Dalvik虚拟机 ...

  6. ORA-16447 Redo apply was not active at the target standby database

    Cause ALTER SYSTEM FLUSH REDO TO STANDBY failed because redo apply is not active at the target datab ...

  7. 使用Guava的ComparisonChain实现自定义的排序

    可以看到使用比较器前,先要写一个实体类,还要实现comparable接口,实现compareTo方法.这个方法一般会返回-1 0 1三个int类型数字,分别表示,对象和传入的对象比较,排序应该在传入的 ...

  8. apache的性能调配 MaxClients 与MaxRequestsPerChild

    因近期服务不稳定,现象和这个比较类似http://hi.baidu.com/xinfeng999/blog/item/1aea470e214ab1cd7acbe1ed.html根据现象来对APACHE ...

  9. SNF开发平台WinForm之十五-时间轴控件使用-SNF快速开发平台3.3-Spring.Net.Framework

    一.显示效果如下: 二.在控件库里选择UCTimeAxis 拖拽到窗体里. 三.加入以下代码,在load事件里进行调用就可以运行了. #region 给时间轴控件加载数据 private void U ...

  10. SNF快速开发平台3.0之BS页面展示和九大优点-部分页面显示效果-Asp.net+MVC4.0+WebAPI+EasyUI+Knockout

    一)经过多年的实践不断优化.精心维护.运行稳定.功能完善: 能经得起不同实施策略下客户的折腾,能满足各种情况下客户的复杂需求. 二)编码实现简单易懂.符合设计模式等理念: 上手快,见效快.方便维护,能 ...