JS原生引用类型解析1-Object类型

(注1:如果有问题欢迎留言探讨,一起学习!转载请注明出处,喜欢可以点个赞哦!)
(注2:更多内容请查看我的目录。)

1. 简介

Object是ECMAScript中使用最多的一个类型,所有引用类型默认都继承Object,这种既成通过原型链实现,所有对象从Object.prototype继承方法和属性,尽管它们可能被覆盖。

例如,其他构造函数的原型将覆盖constructor属性并提供自己的toString()方法。Object原型对象的更改将传播到所有对象,除非受到这些更改的属性和方法将沿原型链进一步覆盖。

所以我们需要对Object的内置属性和方法有一个清晰的认识。

2. Object构造函数的使用

前面我们讲过创建对象的各种方法。其中,Object构造函数为给定值创建一个对象包装器。

如果给定值是null或undefined,将会创建并返回一个空对象。否则,将返回一个与给定值对应类型的对象。

当以非构造函数形式被调用时,Object 等同于 new Object()。

3. Object构造函数的属性与方法

我们用Object.getOwnPropertyNames()方法获取Object构造函数的所有属性与方法。

Object.getOwnPropertyNames(Object);
// (23) ["length", "name", "prototype", "assign", "getOwnPropertyDescriptor", "getOwnPropertyDescriptors", "getOwnPropertyNames", "getOwnPropertySymbols", "is", "preventExtensions", "seal", "create", "defineProperties", "defineProperty", "freeze", "getPrototypeOf", "setPrototypeOf", "isExtensible", "isFrozen", "isSealed", "keys", "entries", "values"]

发现一共有23个属性和方法。

3.1 Object构造函数的属性

Object.length
长度为1

Object.name
名称为"Object"

Object.prototype
指向Object构造函数的原型,可以为所有 Object 类型的对象添加属性。

3.2 Object构造函数的方法

Object.assign()
用于将所有可枚举属性的值从一个或多个源对象复制到目标对象,复制过程对已存在的属性会进行覆盖。它将返回目标对象。

var obj = {
    a: 0,
    d: 6
}
var obj1 = {
    a: 1,
    b: 2
}
Object.defineProperty(obj1, 'c', {
    value: 3,
    enumerable: false
});
var obj2 = Object.assign(obj, obj1);
console.log(obj);  // {a: 1, d: 6, b: 2}
console.log(obj2); // {a: 1, d: 6, b: 2}

Object.create()
使用指定的原型对象及其属性去创建一个新的对象。(具体可参考JS入门难点解析10-创建对象)

Object.defineProperty()
直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。(具体可参考JS入门难点解析13-属性描述符,数据属性和访问器属性)

Object.defineProperties()
直接在一个对象上定义多个新属性,或者修改一个对象的现有属性,并返回这个对象。

Object.entries()
该方法接收一个对象为参数,返回该对象自身可枚举属性的键值对数组,其排列与使用for...in...循环循环遍历该对象时返回的顺序一致(区别在于 for-in 循环也枚举原型链中的属性)。(具体可参考JS常用方法整理-遍历对象)

Object.freeze()
可以冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。也就是说,这个对象永远是不可变的。该方法返回被冻结的对象。(具体可参考JS入门难点解析13-属性描述符,数据属性和访问器属性)

Object.getOwnPropertyDescriptor()
返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

Object.getOwnPropertyNames()
返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。(具体可参考JS常用方法整理-遍历对象)

Object.getOwnPropertySymbols()
回一个给定对象自身的所有 Symbol 属性的数组。

Object.getPrototypeOf()
返回指定对象的原型(内部[[Prototype]]属性的值)。

Object.is()
判断两个值是否是相同的值。如果下列任何一项成立,则两个值相同:

  • 两个值都是 undefined
  • 两个值都是 null
  • 两个值都是 true 或者都是 false
  • 两个值是由相同个数的字符按照相同的顺序组成的字符串
  • 两个值指向同一个对象
  • 两个值都是数字并且
    • 都是正零 +0
    • 都是负零 -0
    • 都是 NaN
    • 都是除零和NaN外的其它同一个数字

这种相等性判断逻辑和传统的 == 运算符所用的不同,== 运算符会对它两边的操作数做隐式类型转换(如果它们类型不同),然后才进行相等性比较,(所以才会有类似 "" == false 为 true 的现象),但 Object.is 不会做这种类型转换。

这与 === 运算符也不一样。=== 运算符(和 == 运算符)将数字值-0和+0视为相等,并认为Number.NaN不等于NaN

Object.is('foo', 'foo');     // true
Object.is(window, window);   // true

Object.is('foo', 'bar');     // false
Object.is([], []);           // false

var test = { a: 1 };
Object.is(test, test);       // true

Object.is(null, null);       // true

// 特例
Object.is(0, -0);            // false
Object.is(-0, -0);           // true
Object.is(NaN, 0/0);         // true

Object.isExtensible()
判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。

Object.isFrozen()
判断一个对象是否是被冻结的。

Object.isSealed()
判断一个对象是否是被密封的。

Object.keys()
返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用for...in...循环遍历该对象时返回的顺序一致 (两者的主要区别是for-in 循环还会枚举其原型链上的属性)。

Object.preventExtensions()
让一个对象变的不可扩展,也就是永远不能再添加新的属性。

Object.seal()
让一个对象密封,并返回被密封后的对象。密封对象将会阻止向对象添加新的属性,并且会将所有已有属性的可配置性(configurable)置为不可配置(false),即不可修改属性的描述或删除属性。但是可写性描述(writable)为可写(true)的属性的值仍然可以被修改。

Object.setPrototypeOf()
设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或null
注意:Object.setPrototypeOf()是ECMAScript 6最新草案中的方法,相对于Object.prototype._proto_,它被认为是修改对象原型更合适的方法。但是,如果你关心性能,你应该避免设置一个对象的[[Prototype]]。相反,你应该使用 Object.create()来创建带有你想要的[[Prototype]]的新对象。

Object.values()
返回一个给定对象自己的所有可枚举属性值的数组,值的顺序与使用for-in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。

4. Object原型对象的属性与方法

我们用Object.getOwnPropertyNames()方法获取Object原型对象的所有属性与方法。

Object.getOwnPropertyNames(Object.prototype);
// (12) ["constructor", "__defineGetter__", "__defineSetter__", "hasOwnProperty", "__lookupGetter__", "__lookupSetter__", "isPrototypeOf", "propertyIsEnumerable", "toString", "valueOf", "__proto__", "toLocaleString"]

发现一共有12个属性和方法。

4.1 Object原型对象的属性

Object.prototype.constructor
指向构造函数Object

Object.prototype._proto_
对于Object.prototype,其值为null,以此避免无限循环。构造函数新建实例对象时,在实例对象调用会指向实例对象的原型对象。该特性为非标准特性,尽量不要使用。

4.2 Object原型对象的方法

Object.prototype.hasOwnProperty()
该方法会返回一个布尔值,指示对象自身属性(非原型链继承)中是否具有指定的属性。

Object.prototype.isPrototypeOf()
该方法返回一个布尔值,表示指定的对象是否在本对象的原型链中。

Object.prototype.PropertyIsEnumerable()
该方法返回一个布尔值,判断指定属性是否可枚举。

Object.prototype.toString()
如果此方法在自定义对象中未被覆盖,toString() 返回 "[object type]",其中type是对象的类型。对于Object.prototype.toString(),其值为"[object Object]"。

Object.prototype.toLocalString()
返回一个该对象的字符串表示。此方法被用于派生对象为了特定语言环境的目的(locale-specific purposes)而重载使用。绝大多数情况下和Object.prototype.toString()一样。

Object.prototype.valueOf()
返回值为该对象的原始值。

5. Object实例对象的属性与方法

我们用Object.getOwnPropertyNames()方法获取Object实例对象的所有属性与方法。

var obj = new Object({a:1,b:2});
Object.getOwnPropertyNames(obj);  // ["a", "b"]

传入属性的key值即为其属性。但是有一点要注意的是,此时可以使用obj._proto指向其原型对象,这个_proto属性按照《JAvaScript高级程序设计》一书和我们前面的分析,按道理应该是实例属性,但这里却并不是(或者是虽然是,但是无法被Object.getOwnPropertyNames()方法列出,如果这样的话,也说得通),不知道底层具体是如何来实现的,如果是共享自Object原型,为什么每一个实例的值都是不同的。(如果有懂这块的同学,还请不吝赐教。)

参考

MDN-Object

你可能感兴趣的:(JS原生引用类型解析1-Object类型)