原型&原型链

111 阅读3分钟

构造函数

构造函数也是函数的一种,只不过构造函数作用是用来生成对象实例,且函数名首字母一般大写。一般通过new关键字生成对象。

function Person (name, age) {
    this.name = name
    this.age = age
    this.add = '北京'
    this.say = function () {
        console.log('say hello)
    }
}
let p = new Person('lucy', 18)

原型对象

js中,只要是函数类型的数据,都有prototype属性,指向一个特殊对象,叫原型对象。

原型对象一般存放着构造函数new出实例的公共方法和属性。

构造函数的prototype属性指向原型对象,原型对象有constructer属性,指向构造函数本身。

image.png

作用

存放构造函数new的实例的公共方法和属性

如上例子中,add 和 say 所有实例都一样,没有必要放在构造函数中,每次实例化都占用额外空间,我们就可以放在原型对象上。

function Person (name, age) {
    this.name = name
    this.age = age
}
Person.prototype.add = '北京'
Person.prototype.say = function () {
        console.log('say hello)
}

const p1 =  new Person('lucy', 18)
const p2 =  new Person('lily', 22)

console.log(p1.add, p1.say())    // lucy, say hello

这里p1没有add 属性和 say方法,那为什么能够通过点访问到?是因为js中,如果本身访问不到的属性,会去该对象的构造函数的原型对象上去找。如果找到,那么就会返回对象属性或者调用对应方法。这也是为什么我们能进行以下访问?

p1.constructor === Person

因为查找顺序为p1=>Person.prototype

**注意:**p1后Person.prototype怎么建立联系?proto

那么如果原型对象上找不到怎么办,这里就涉及到原型链,找不到就会顺着原型链一直往上找,直到原型链末尾。

原型链

显式原型

  • 函数类型数据才有
  • 通过prototype访问

隐式原型

  • 对象类型数据才有
  • 通过__proto__访问,一般通过实例去访问
  • 指向构造函数的原型对象。
p1.__proto__ === Person.prototype
p2.__proto__ === Person.prototype

因此,实例__proto__,prototype,constructor关系如下:

image.png

隐式原型链

  • 既然隐式原型是对象的属性,那么Person.prototype也是对象,那么他也有__proto__属性。
  • __proto__指向构造函数的原型对象,那么要知道普通对象的构造函数都是Object()构造函数。

image.png

那么就可以回答前边问题,如果对象本身以及原型上都没有对应属性,那么就会去原型的原型上找,找到则返回,找不到就会到Object.prototype.proto=null末尾,没有则返回undefined。这个查找顺序叫做原型链。

可以看到,查找变量的过程是顺着途中蓝色的线,顺着对象的__proto__属性查找的过程,因此原型链也叫做隐式原型链。

正因如此,我们创建的一些内置对象类型,如数组、Date,正则等数据结构都有公共的属性和方法,因为存在他们的原型对象上。

函数也是一种对象

  • 函数也是一种特殊对象
  • 因此函数也有__proto__属性
  • 所有函数的构造函数都是Function(),包括Object(),Function()本身
  • 函数公共属性的查找也是顺着隐式原型链查找
Person.constructor => Person.__proto__.constructor => Function.prototype.constructor === Function

Object.constructor = Function
Function.constructor = Function

image.png

总结

  1. 所有函数都有prototype对象,指向原型对象。构造函数原型对象的constructor指向构造函数本身。
  2. 所有函数都是Function()的实例,或者说所有函数的构造函数都是Function
  3. 所有对象都有__proto__,指向构造函数的原型对象。
  4. 对象的构造函数是Object()。函数的构造函数是Function()
  5. 原型链是隐式原型链,都是根据__proto__去查找属性。
  6. 原型链末尾Object.prototype.proto=null

练习题

function Person(name) {
    this.name = name
}
var p2 = new Person('king');
console.log(p2.__proto__) // Person.prototype
console.log(p2.__proto__.__proto__) // Object.prototype
console.log(p2.__proto__.__proto__.__proto__) // null
// console.log(p2.__proto__.__proto__.__proto__.__proto__) // null后面报错
// console.log(p2.__proto__.__proto__.__proto__.__proto__.__proto__) // null后面报错
console.log(p2.constructor) // Person
console.log(p2.prototype) // undefined
console.log(Person.constructor) // Function
console.log(Person.prototype) // 打印出Person.prototype里面的属性和方法
console.log(Person.prototype.constructor) // Person
console.log(Person.prototype.__proto__) // Object.prototype
console.log(Person.__proto__) // Function.prototype
console.log(Function.prototype.__proto__) // Object.prototype
console.log(Function.__proto__) // Function.prototype
console.log(Object.__proto__) // Function.prototype
console.log(Object.prototype.__proto__) // null

题目:blog.csdn.net/weixin_4566…