原型链

228 阅读3分钟

1. 创建对象有几种方法

// 1. 字面量
var o1 = { name: 'o1' }
var o2 = new Object({ name: 'o2' });
// o2 也可看作时构造函数
// 构造函数
var M = function (name) {
    this.name = name;
}
var o3 = new M('o3M')
// 3. Object.create()
var p = {name:'p'}
var o4 = Object.create(p)
// o4是直接拿不到name属性的
// 

2. 原型、构造函数、实例、原型链

  1. 只要是对象就是实例
  2. 只要是用new来操作的都是构造函数
  3. 构造函数可以使用new运算符生成一个实例
  4. 函数都有一个prototype属性(申明一个函数时js自动加上的属性)
  5. prototype属性会初始化一个空对象---原型对象
  6. 原型对象如何区分被哪一个构造函数所引用:原型对象中会有一个构造器(constructor),这个构造器会默认你申明的那个函数
  7. 实例对象有__proto__属性(函数也有__proto__属性)

例1

// 构造函数
var M = function (name) {
    this.name = name;
}
var o3 = new M('o3M')

o3是创建的一个实例对象
M是构造函数

构造函数M有一个原型对象prototype,原型对象中有构造器constructor,constructor属性指向这个构造函数

对象有一个__proto__属性,指向构造函数的原型对象

所以构造函数、实例、原型对象的关系为:

  1. 构造函数通过new和实例关联,
  2. 构造函数的原型对象通过constructor和构造函数相关联
  3. 实例的__proto__属性指向构造函数的原型对象

原型链 从一个实例对象往上找构造这个实例的相关的对象,然后这个关联的对象再往上找,他又有创建它的上一级的原型对象,以此类推,一直到Object.protopyte原型对象终止,这个链条就断了。也就是说Object.protopyte属性是整个原型链的顶端

在访问一个实例或者他上面的方法的时候,如果在实例本身没有找到这个方法和属性的时候,就通过__proto__属性从实例的原型对象上找,如果上一级对象上还没有找到,再从原型对象的基础上,再通过__proto__属性再往上一级查找,以此类推,知道找到直到Object.protopyte,若还未找到,则没有这个方法,原路返回。

原型链是通过prototype这个原型对象和__proto__属性来完成原型链的查找 原型对象和原型链之间的起了什么样的作用:当构造函数中写了多个属性和方法,实例是不是就可以公用这个东西了/当有多个实例的时候,想去共用这个方法的时候,可以存到一个共同的东西上(原型对象)

var M = function (name) {
    this.name = name;
}
var o3 = new M('o3M')4 
// 通过再M的原型链上增加方法
M.prototype.say = function () {
    console.log('say hi')
}
let o5 = new M('o5')

通过原型链的方式,找到原型对象,原型对象上的方法是被不同的实例所共有---原型链的工作原理

3. 原型链类之instanceof 的原理

原理:判断实例对象的__proto__属性和构造函数的prototype属性是不是同一个引用地址。

检测基本数据类型时用typeof,检测引用数据类型是什么类型的对象时用instanceof 如果使用 instanceof 操作符检测基本类型的 值,则该操作符始终会返回 false,因为基本类型不是对象。

只要是在这个原型链上的构造函数,都会被instanceof看作是实例对象的一个构造函数

比如a继承了b,b继承了c。a生成的实例对象,用instanceof判断b或c,返回的都是true。

为了严谨,使用constructor来准确判断到底是a还是b、c生成的实例

严谨一点就用实例对象的__proto__.constructor来判断