Object类型

241 阅读3分钟

关于Object

  • ECMAScript 中的对象其实就是一组数据和功能的集合
  • 对象通过 new 操作符后跟对象类型的名称创建
  • 开发者可以通过创建 Object 类型的实例来创建自己的对象,然后再给对象添加属性和方法
  • ECMA 只要求在给构造函数提供参数时使用括号,但不推荐
const o1 = new Object();
const o2 = new Object; // 合法,但不推荐
  • Object 实例本身并不是很有用,但他也是派生其他对象的基类,他上面所有的属性和方法在派生的对象上同样存在
  • 注意
    • 因为在 ECMA 中 Object 是所有对象的基类,所以任何对象都有这些属性和方法
    • 但严格来讲,ECMA 中的对象行为不一定适合 JavaScript 中的其他对象。比如 BOM 和 DOM,他们都是有宿主环境定义和提供的宿主对象,而宿主对象不受 ECMA 约束,所以他们可能不继承于 Object

属性 及 方法

constructor

  • 用于创建当前对象的函数
class Obj { }

const obj = new Obj();
console.log(obj.constructor); // class Obj { }
console.log(obj.constructor === Obj); // true

hasOwnProperty(propertyName)

  • 用于判断当前对象实例(不是原型)上是否存在给定的属性
  • 检查的属性名必须是字符串或符号(Symbol)
const s = Symbol('s')
function Obj() {
  this.a = 1;
  this[s] = 2;
}
Obj.prototype.fn = function () { };

const obj = new Obj();

console.log(obj.hasOwnProperty('a')); // true
console.log(obj.hasOwnProperty(s)); // true
console.log(obj.hasOwnProperty('fn')); // false

// 因 in 能找到 prototype,可搭配 hasOwnProperty 使用筛选
// 其中 Symbol 需使用 getOwnPropertySymbols、Reflect.ownKeys 方法找到,这里不再举例
// 当然我们也可以通过 Object.key、Reflect.ownKeys 循环也能过滤 prototype
for (const key in obj) {
  if(!Object.hasOwnProperty.call(obj, key)) continue
  console.log(obj[key]);
}
  • 注意:JavaScript 并没有保护 hasOwnProperty 这个属性名,因此,当某个对象可能自有一个占用该属性名的属性时,就需要使用外部的 hasOwnProperty 获得正确的结果
function Obj() {
  this.a = 1;
}
Obj.prototype.hasOwnProperty = function () {
  return false
}

const obj = new Obj();

console.log(obj.hasOwnProperty('a')); // false
console.log(Object.hasOwnProperty.call(obj, 'a')); // true (Object.prototype.hasOwnProperty 省略 prototype)

isPrototypeOf(Object)

  • 用于判断当前对象是否为另一个对象的原型
  • 实际用起来与 instanceof 类似,暂时没找到一些实质性的差别
function Foo() { }
function Bar() { }
function Baz() { }

Bar.prototype = Object.create(Foo.prototype);
Baz.prototype = Object.create(Bar.prototype);

var bar = new Bar();
var baz = new Baz();

console.log(Baz.prototype.isPrototypeOf(baz)); // true
console.log(Bar.prototype.isPrototypeOf(baz)); // true
console.log(Foo.prototype.isPrototypeOf(baz)); // true
console.log(Object.prototype.isPrototypeOf(baz)); // true

console.log(baz instanceof Baz); // true
console.log(baz instanceof Bar); // true
console.log(baz instanceof Foo); // true
console.log(baz instanceof Object); // true

console.log(baz instanceof Baz.prototype.constructor); // true

propertyIsEnumerable(propertyName)

  • 用于判断给定的属性是否可以使用 for-in 语句枚举
  • 检查的属性名必须是字符串或符号(Symbol)
  • 注意:通过原型链继承的属性除外
const s = Symbol('s');
const obj = {};
const arr = [];
obj[s] = 42;
arr[0] = 42;

console.log(obj.propertyIsEnumerable(s)); // true
console.log(arr.propertyIsEnumerable(0)); // true
console.log(arr.propertyIsEnumerable('length')); // false

class A {
  a() { }
}
const a = new A();
console.log(a.propertyIsEnumerable('a')); // false

toLocaleString()

  • Object - 返回调用 toString() 的结果
  • Array、Number、Date - 主要是国际化和格式上的区别

toString()

  • 返回一个表示该对象的字符串
  • 默认情况下返回 [object type] 其中 type 是对象的类型
  • 注意:该方法可被覆盖,Array、Number、String、Function 均不相同
const obj = {};
console.log(obj.toString()); // [object Object]
  • 覆盖 与 检测
class Obj {
  toString() {
    return 123456
  }
}
const o = new Obj();
console.log(o.toString()); // 123456
console.log(`hhhh${o}hhhh`); // hhhh123456hhhh (模板字面量插值隐式调用 toString)

// 需要检测时需要使用外部的 toString
console.log(Object.prototype.toString.call(o)); // [object Object]
  • 注意
console.log(Object.prototype.toString === Object.toString); // false
// Object 的本质是一个构造函数,因此 prototype 不能省略
console.log(Object.toString === Fuction.prototype.toString); // true

valueOf()

  • 返回指定对象的原始值,通常与 toString() 的返回值相同
对象返回值
Array返回数组对象本身。
Boolean布尔值。
Date存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC。
Function函数本身。
Number数字值。
Object对象本身。这是默认情况。
String字符串值。
Math 和 Error 对象没有 valueOf 方法。
  • 改写 .prototype.valueOf
  • 下一次每当要被转换为原始类型值时,js 在此之前会自动调用自定义的valueOf方法
class Obj {
  valueOf() {
    return 1
  }
}
const obj = new Obj();
console.log(obj + 1); // 2