Object
1. 静态方法
Object 是最基础的对象,其他所有对象都继承自它
可以直接通过 Object.方法名 调用,故为静态方法
属性相关
-
.keys()- 获取对象自身的属性键(不包括继承的),返回一个数组
print(Object.keys(obj)); // ["key1", "key2"]- 只返回可枚举的属性,最常用,用来计算对象属性个数
- 获取对象自身的属性键(不包括继承的),返回一个数组
-
.getOwnPropertyNames()- 获取对象自身的属性键(不包括继承的),返回一个数组
print(Object.getOwnPropertyNames(obj)); // ["key1", "key2"] print(Object.getOwnPropertyNames(arr)); // ["0", "1", "length"]- 会同时返回不可枚举的,比如 length
- 获取对象自身的属性键(不包括继承的),返回一个数组
-
.values()- es8 新增,可遍历对象的值
- 作用于对象
let obj = { x: "123", y: 1 }; let values = Object.values(obj); // ['123', 1] - 作用于数字键对象,会按键的升序导出
const obj = { 10: "xxx", 1: "yyy", 3: "zzz" }; Object.values(obj); // ['yyy', 'zzz', 'xxx'] - 作用于字符串
let values = Object.values("es8"); // ['e', 's', '8']
-
.entries()- es8 新增,可遍历对象的键和值,二者拼成数组,再作为大数组的一个元素
- 作用于对象
const obj = { x: "123", y: 1 }; Object.entries(obj); // [['x', '123'], ['y', 1]]
原型链相关
-
.create()-
es6 新增,可使用现有对象 proto 来提供原型信息,从而创建一个新对象
newObj = Object.create(proto, [propertiesObject]); -
参数
- proto 必选
- 表示新对象的原型对象,即该对象会被复制到新对象的原型上
- 可填值
- 另一个对象,或者函数的 prototype 属性
- 创建空对象时可以传 null
- propertiesObject 可选
- 表示添加到新对象的可枚举属性(即其自身的属性,而不是原型链上的枚举属性)
- 对应 Object.defineProperties()的第二个参数
- proto 必选
-
下面通过几个案例,说明这种创建方式,与原有的构造函数创建,有何不同
-
案例 1
- 在 es6 之前,如果通过
构造函数创建,会直接添加到实例下面let a = { rep: "apple" }; let b = new Object(a); console.log(b); // {rep: "apple"} console.log(b.__proto__); // {} console.log(b.rep); // {rep: "apple"}- 这里最终能输出,是因为自身实例就有
- es6 出现后,通过
.create()创建,可以添加到原型下面var a = { rep: "apple" }; var b = Object.create(a); console.log(b); // {} console.log(b.__proto__); // {rep: "apple"} console.log(b.rep); // {rep: "apple"}- 这里最终能输出,是向上追溯原型链得到的
- 在 es6 之前,如果通过
-
案例 2
- 在 es6 之前,如果通过
构造函数创建,需要自己一个个地补充原型let People = function () {}; People.prototype.y = 20; People.prototype.showNum = function () {}; let p = new People();- 如果我们检查,会发现
p.__proto__的值就是People.prototype
- 如果我们检查,会发现
- es6 出现后,通过
.create()创建,可以直接先写个对象,然后当成原型使用let proto = { y: 20, z: 40, showNum() {}, }; let o = Object.create(proto);- 这时候,
p.__proto__的值就是proto,方便多了
- 这时候,
- 在 es6 之前,如果通过
-
案例 3
- 创建一个 以空对象为原型,且拥有一个 p 实例属性(但此属性默认不可被循环枚举)的新对象
o = Object.create({}, { p: { value: 42 } }); o.p = 24; console.log(o.p); //输出42 o.q = 12; for (var prop in o) { console.log(prop); //输出"q" } console.log(o.__proto__); //输出{}- 上面出现这些输出,是因为
- 默认可枚举属性描述符全为 false,不可写,不可枚举,不可配置
- 对象的原型属性,就是创建时给的{}
- 如果通过字面量方法或者 new 创建
- 则描述符全为 true
- 对象的原型属性是有的,而且是 Object(或者是构造函数.prototype)
- 上面出现这些输出,是因为
- 创建一个 以空对象为原型,且拥有一个 p 实例属性(但此属性默认不可被循环枚举)的新对象
-
-
.setPrototypeOf()- es6 新增,可以给现有对象 obj,添加一个新的原型
Object.setPrototypeOf(obj, proto);- 以前是通过给
__proto__属性赋值实现的,但兼容性不好,只有浏览器要部署,其他环境不用部署
- 以前是通过给
- es6 新增,可以给现有对象 obj,添加一个新的原型
-
.getPrototypeOf()-
es6 新增,可以读取现有对象 obj 的原型
Object.getPrototypeOf(obj);- 以前是直接读取
__proto__属性实现,但兼容性不好,只有浏览器要部署,其他环境不用部署
- 以前是直接读取
-
案例 1
-
es6 之前,直接
.assign()是拷贝不到原型上面的方法的let triangle = { x: 1 }; function ColoredTriangle() { this.color = "red"; } Object.assign(ColoredTriangle.prototype, triangle); let c = new ColoredTriangle(); Object.defineProperty(c, "colorGet", { enumerable: true, // 设为可枚举,不然 Object.assign 方法会过滤该属性 get() { return "Could it return " + this.color; }, }); let c2 = Object.assign({}, c); console.log(c2.x); //undefined- 这里拷贝的时候,把原型上面的属性和方法都弄丢了
-
es6 出现后,通过
.getPrototypeOf()可以拿到原型,使得原型的拷贝成为可能let originProto = Object.getPrototypeOf(c); let objWithProto = Object.create(originProto); var c2 = Object.assign(objWithProto, c); console.log(c2.x); // 1- 这样就不会弄丢了
-
其实上面的拷贝还有弊端,就是还是无法拷贝到可枚举属性中的 get 描述符,这就需要用到
.getOwnPropertyDescriptors()let originProto = Object.getPrototypeOf(c); let c2 = Object.create(originProto, Object.getOwnPropertyDescriptors(c));
-
-
2. 原型方法
是通过Object.prototype.方法名挂载上去的,故为原型方法
需要用过对象实例.方法名来调用
-
.prototype.valueOf()- 返回当前对象对应的值
- 一般用在自动类型转换中
-
.prototype.toString()- 返回当前对象对应的字符串形式
- 一般用在自动类型转换中
- 也常用来判断一个值的类型名
Object.prototype.toString.call(值);- 会返回
[object 类型名]
- 会返回
-
.prototype.toLocaleString()- 返回当前对象对应的本地字符串形式
-
.prototype.hasOwnProperty()- 判断某个属性是否为自身的属性(而不是继承的)
-
.prototype.isPrototypeOf()- 判断当前对象是否为另一个对象的原型
-
.prototype.propertyIsEnumerable()- 判断某个属性是否可枚举