原型

[[prototype]]proto

在 JavaScript 中,每个对象(包括Function)都有一个特殊的隐藏属性 [[Prototype]],它要么为 null,要么就是对另一个对象的引用, 若为其他的类型都会被忽略。该对象被称为“原型”。

obj 中读取一个缺失的属性时,JavaScript 会自动从原型中获取该属性。

1.1 设置/获取原型

  • proto : obj.__proto__ = objProto

    • __proto__ 与内部的 [[Prototype]]不一样的__proto__[[Prototype]] 的 getter/setter
  • Object.setProtoTypeOf(obj,objProto)

  • Object.getProtoTypeOf(obj)

注意: 原型仅用于的读取属性, 对于写入/删除操作可以直接在对象上进行

__proto__ 不是一个对象的属性,只是 Object.prototype 的访问器属性:
image.png
因此,如果 obj.__proto__ 被读取或者赋值,那么对应的 getter/setter 会被从它的原型中调用,它会 set/get [[Prototype]]
__proto__** 是一种访问 [[Prototype]] 的方式,而不是 [[prototype]] 本身**。

Object.create(null)

1.2 “this”的指向

this 根本不受原型的影响。
无论在哪里找到方法:在一个对象还是在原型中。在一个方法调用中,this 始终是点符号 . 前面的对象。
这将决定:当继承的对象运行继承的方法时,它们将仅修改自己的状态,而不会修改大对象的状态。

  1. let animal = {
  2. sleep() {
  3. this.isSleeping = true;
  4. }
  5. };
  6. let rabbit = {
  7. name: "White Rabbit",
  8. __proto__: animal
  9. };
  10. // 修改 rabbit.isSleeping
  11. rabbit.sleep();
  12. alert(rabbit.isSleeping); // true
  13. alert(animal.isSleeping); // undefined(原型中没有此属性)

1.3 属性遍历

  • for ... in : 既遍历自身属性, 也遍历继承属性, 且是可枚举的
    • obj.hasOwnProperty(key) : 过滤掉继承的属性
  • Object.keys(obj) : 只包含自身可枚举属性
  • Object.values(obj)
  • Object.enties(obj)


F.prototype

每个函数都有 "prototype" 属性, 且只有函数有**Prototype**属性,它指向这个函数得原型对象。
默认的原型对象只有一个属性 constructor ,指向函数自身。

  • :在常规对象上,prototype没什么特别的,仅仅是一个普通的属性。
    1. let A = {};
    2. let B = function(){};
    3. let b = new B();
    4. console.log(A.prototype) // undefined
    5. console.log(B.prototype) // {constructor: ƒ}
    6. console.log(b.__proto__ === B.prototype) // true
    image.png
    使用new F() 这样的构造函数来创建一个新对象时,
    如果 F.prototype 是一个对象,那么 new 操作符会使用它为新对象设置 [[Prototype]]
    image.png

    F.prototype 属性仅在 new F 被调用时使用。 如果在创建之后,F.prototype 属性有了变化(F.prototype = <another object>),那么之后通过 new F 创建的新对象也将随之拥有新的对象作为 [[Prototype]],但已经存在的对象将保持旧有的值

  1. var A = function() {};
  2. A.prototype.n = 1;
  3. var b = new A();
  4. A.prototype = {
  5. n: 2,
  6. m: 3
  7. }
  8. var c = new A();
  9. console.log(b.n); // 1
  10. console.log(b.m); // undefined
  11. console.log(c.n); // 2
  12. console.log(c.m); // 3

constructor

函数原型对象上有一个 constructor 属性,它指向函数自身。

  • Rabbit.prototype.constructor == Rabbit ```javascript function Rabbit() {} // by default: // Rabbit.prototype = { constructor: Rabbit }

alert( Rabbit.prototype.constructor == Rabbit ); // true

  1. 可以使用 `constructor` 属性来创建一个新对象,该对象使用与**现有对象**有相同的**构造器**。
  2. - `let inst2 = new inst1.constructor(...args);`
  3. ```javascript
  4. function Rabbit(name) {
  5. this.name = name;
  6. alert(name);
  7. }
  8. let rabbit = new Rabbit("White Rabbit");
  9. let rabbit2 = new rabbit.constructor("Black Rabbit");

原型链

  • 每个对象都拥有一个原型对象:newFoo的原型是Foo.prototype
  • 对象的原型可能也是继承自其它的原型对象:Foo.prototype也有它的原型Object.prototype
  • 一层一层的,以此类推,这种关系就是原型链

每个对象拥有一个原型对象,通过__proto__ 指针指向上一个原型 ,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向null,这种关系被称为原型链(prototype chain)。

当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__ (即它的构造函数的prototype)中寻找。

一个对象是否在另一个对象的原型链上

1. instanceof

语法:obj instanceof constructor
检测 constructor.prototype是否存在于参数 obj 的原型链上。

  1. let Fn = function () { }
  2. let f = new test();
  3. f instanceof Fn // true
  4. f instanceof Function // false
  5. f instanceof Object // true

2. isPrototypeOf

语法:protoObj.isPrototypeOf(obj)
检测一个对象是否存在于另一个对象的原型链上

  1. let Fn = function () { }
  2. let f = new test();
  3. Fn.prototype.isPrototypeOf(testObject) // true
  4. Object.prototype.isPrototypeOf(testObject) // true