JavaScript 系列 - getPrototypeOf、setPrototypeOf、Object.prototype.isPrototypeOf

184 阅读1分钟

Object.getPrototypeOf(obj)  静态方法返回指定对象的原型(即内部 [[Prototype]] 属性的值)。

getPrototypeOf

const proto = {};
const obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true

非对象强制类型转换

该参数将被强制转换为 Object

Object.getPrototypeOf("foo");
// String.prototype (ES2015 code)

Object.setPrototypeOf()

Object.setPrototypeOf(obj, prototype)  静态方法可以将一个指定对象的原型(即内部的 [[Prototype]] 属性)设置为另一个对象或者 null

由于性能问题建议使用 Object.create() 替换 Object.setPrototypeOf()

异常

  • obj 参数为 undefined 或 null
  • obj 参数是不可扩展的,或者它是一个不可修改原型的特异对象,如果新原型与 obj 的原始原型具有相同的值,则不会抛出错误
  • prototype 参数不是对象或 null
  • 如果 obj 参数不是对象,不执行任何操作直接将 obj 作为原始值返回

不可修改原型的特异对象有 Object.prototypewindowlocation

类继承

function Human(name, level) {
  this.name = name;
  this.level = level;
}

function SuperHero(name, level) {
  Human.call(this, name, level);
}

Object.setPrototypeOf(SuperHero.prototype, Human.prototype);

// 将 `SuperHero.prototype` 的 `[[Prototype]]` 设置为 `Human.prototype` 以设置原型继承链

Human.prototype.speak = function () {
  return `${this.name} says hello.`;
}

SuperHero.prototype.fly = function () {
  return `${this.name} is flying.`;
}

const superMan = new SuperHero('Clark Kent', 1);

console.log(superMan.fly());
console.log(superMan.speak())
class Human {}
class SuperHero {}

// 设置实例属性
Object.setPrototypeOf(SuperHero.prototype, Human.prototype);

// 连接静态属性
Object.setPrototypeOf(SuperHero, Human);

const superMan = new SuperHero();

Object.prototype.isPrototypeOf()

isPrototypeOf(object)  方法用于检查一个对象是否存在于另一个对象的原型链中。

class Foo {}
class Bar extends Foo {}
class Baz extends Bar {}

const foo = new Foo();
const bar = new Bar();
const baz = new Baz();

// 原型链:
// foo: Foo --> Object
// bar: Bar --> Foo --> Object
// baz: Baz --> Bar --> Foo --> Object
console.log(Baz.prototype.isPrototypeOf(baz)); // true
console.log(Baz.prototype.isPrototypeOf(bar)); // false
console.log(Baz.prototype.isPrototypeOf(foo)); // false
console.log(Bar.prototype.isPrototypeOf(baz)); // true
console.log(Bar.prototype.isPrototypeOf(foo)); // false
console.log(Foo.prototype.isPrototypeOf(baz)); // true
console.log(Foo.prototype.isPrototypeOf(bar)); // true
console.log(Object.prototype.isPrototypeOf(baz)); // true

Foo.prototype 存在于 baz 的原型链中并不意味着 baz 是使用 Foo 作为其构造函数创建的,的代码从 baz 中读取 Foo 的私有属性,它仍然会失败

class Foo {
  #value = "foo";
  static getValue(x) {
    return x.#value;
  }
}

const baz = { __proto__: Foo.prototype };

if (Foo.prototype.isPrototypeOf(baz)) {
  console.log(Foo.getValue(baz)); // TypeError: Cannot read private member #value from an object whose class did not declare it
}