javascript 之 原型-原型链

一 原型

1.原型对象

  • 每个函数都有一个 prototype (原型)属性,它指向一个对象,这个对象就是原型对象。默认情况下,原型对象上都有一个 constructor (构造函数)属性,它是一个指向 prototype 属性所在函数的指针。

  • 创建自定义构造函数后,其原型对象默认只会取得 constructor 属性,其他方法都是从 object 继承而来。

  • 通过原型可以创建自定义类型,所有引用类型也都在其构造函数的原型上定义了方法,可以通过原生对象的原型取得默认方法的引用,也可以定义新方法(不推荐)。

2.原型对象和对象实例的关系

  • 当调用构造函数创建一个实例后,该对象实例内部有个 __proto__ 属性,指向构造函数的原型对象。

  • 实例和原型之间的连接是一个指针,不是副本,所以原型中的属性变化实例在访问时会反应出来

  • 确定一个实例是否指向一个构造函数的原型对象

    • isPrototypeOf():返回布尔值

    • Object. getPrototypeOf():返回对象实例指向的原型对象

3.原型对象上的属性和对象实例之间的关系

function Person () {}
Person.prototype.name = 'Tom';
​
person = new Person();
console.log(person.name) // Tom
​
person.name = 'Nike'
console.log(person.name) // Nike

javascript 之 原型-原型链

  • 当读取某个对象上的某个属性时,先在对象实例上搜索是否有给定名字的属性,如果找到返回对应的值,否则在原型对象中找,找到时返回。

  • 可以通过对象实例访问保存在原型中的值,但不能通过对象实例重写原型中的值,通过"对象实例.属性 = 值''的形式在修改对象属性时,这个属性假如不在对象实例上,而是在原型对象上,则它所执行的操作是在对象实例上创建了一个相同属性名的属性,并没有改变原型对象上的属性,在访问时候,对象实例会屏蔽原型对象上相同属性名的属性而读取对象实例上的属性。

  • hasOwnProperty() 方法检测一个属性存在于对象实例还是原型对象中,在对象实例上返回 true。

4.原型对象上属性的访问

  • 单独使用 in 操作符:当通过对象能够访问到给定属性时返回 true。(通过hasOwnProperty() 和 in 操作符可以确定给定属性在对象实例还是原型对象上)

console.log('name' in person) // true
  • 使用for-in循环时,返回所有能通过对象访问的、可枚举的属性。(包括实例和原型上的属性)

  • hasPrototypeProperty() 是当实例中没有给定属性而原型上有返回true,当实例重写了给定属性后就找不到了(因为原型中的该属性让屏蔽了),此时返回false。

  • Object.keys() 方法接受一个对象作为参数,返回该对象上所有可枚举属性的字符串数组。(不向上找)

  • Object.getOwnPropertyNames() 返回所以对象属性,无论是否可枚举。(不向上找)

5.原型对象的重写

  • 为了简写每次添加属性都要写一次 "构造函数.prototype“ 的写法,可以直接一次赋给它一个对象,然后将要添加的属性封装到那个对象中。但是问题是这样会导致原型对象的 constructor 不在指向该构造函数了,因为此操作相当于重写了默认的原型对象,所以此时的 constructor 指向的是 Object 构造函数,即无法用 constructor 确定对象类型了。所以在重写原型对象后,要同时修改它的 constructor 指向。

  • 重写原型对象会切断现有原型和任何之前已经存在的实例对象之间的联系,那些实例对象指向的仍然是之前的那个原型。

javascript 之 原型-原型链

二 原型链

1.概念

  • 构造函数、原型对象、实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。

  • 原型链:让一个原型对象等于另一个类型的实例,原型对象将包含一个指向另一个原型对象的指针,另一个原型中也包含着一个指向另一个构造函数的指针,假如另一个原型又是另一个类型的实例,这样层层递进,就构成了实例和原型的链条。

2.确定原型和实例的关系

  • instanceof

  • isPrototypeof()

3.存在的问题

  1. 通过原型链实现继承时,不能使用对象字面量创建原型方法,这样会重写原型链。

  2. 包含引用类型值的原型属性会被所有实例共享。(所以属性在构造函数中定义,不在原型中定义)