12

图片描述

在 JavaScript 中,函数也是属于对象,可以像其他对象一样访问属性,其中便有一个属性叫原型 prototype,值为一个对象,默认,原型有一个 constructor 属性,指向了构造函数本身

function Person () {
  return 'hi'
}
Person.prototype // {constructor: ƒ}
Person.prototype.constructor // ƒ Person() {}

用图来表示:

图片描述

我们可以对这个属性进行操作,但这个属性,只有在对函数进行构造调用的时候才会起作用

? 为原型添加属性和方法

function Person (name) {
  this.name = name
}
Person.prototype.smart = true
Person.prototype.run = function () {
  console.log('running')
}

// 或者一次性添加

Person.prototype = {
  smart: true,
  run() {
    console.log('running')
  }
}

? 使用

// ...
let a = new Person('a')
a.name // a
a.smart // true
a.run() // running

? instanceof

用来检测构造函数的原型是否存在于实例的原型链

// ...
let b = new Person('b')
b instanceof Person // true
b instanceof Object // true

? hasOwnPrototype

该方法来判断是否自身属性,如:

function Person () {
  this.name = 'Jon'
}
Person.prototype.name = 'people'
Person.prototype.age = 18
let jon = new Person()
jon.hasOwnProperty('name') // true
jon.hasOwnProperty('age') // false

age 为原型上的属性,所以为 false

? isPrototypeOf

该方法来判断对象是否是另一个对象的原型,如:

let base = {
  name: 'people',
  age: 18
}
function Person () {
  this.name = 'Jon'
}
Person.prototype = base
let jon = new Person()
base.isPrototypeOf(jon) // true

? getPrototypeOf

当不知道对象的原型具体是哪个的时候,可以使用该方法来判断,如:

let base = {
  name: 'people',
  age: 18
}
function Person () {
  this.name = 'Jon'
}
Person.prototype = base
let jon = new Person()
Object.getPrototypeOf(jon) // { name: 'people', age: 18 }

? _ _proto_ _

引用《MDN _ _proto_ _ 》 的解释:

Object.prototype 的 _ _proto_ _ 属性是一个访问器属性(一个 getter 函数和一个 setter 函数), 暴露了通过它访问的对象的内部原型 (一个对象或 null)。

也就是说,每个对象都有一个该属性,便携访问原型对象,直指原型对象:

let base = {
  name: 'people',
  age: 18
}
function Person () {
  this.name = 'Jon'
}
Person.prototype = base
let jon = new Person()
jon.__proto__ // { name: 'people', age: 18 }

用图来表示:

图片描述

与 prototype 不同的是,_ _proto_ _ 是对象的属性,prototype 是构造函数的属性

?【ES5】Object.create(..)

该方法创建一个新对象,使用现有的对象来提供新创建的对象的 _ _proto_ _

let base = {
  name: 'people',
  age: 18
}
let jon = Object.create(base)
jon.__proto__ // { name: 'people', age: 18 }

? 原型链

当访问对象的一个属性时,js 引擎会遍历自身对象的属性,如果找不到,便会去原型上查找该属性,如果还是找不到,便会继续查找原型的属性,直到到 Object 原型

由于原型是一个对象,是对象便会有一个原型,有原型说明存在构造函数,如 Person 例子,查看原型的构造函数是啥:

// ...
Person.prototype.__proto__.constructor // ƒ Object() { [native code] }

Person.prototype.__proto__.constructor === Object // true

说明 ObjectPerson 原型 的构造函数

说明 Person 原型_ _proto_ _ 会指向 Object.prototype,因为 _ _proto_ _ 能快捷访问原型:

// ...
Object.getPrototypeOf(jon.__proto__) === Object.prototype // true
// 或者
jon.__proto__.__proto__ === Object.prototype // true
// 或者
Person.prototype.__proto__ === Object.prototype // true

用图表示就是:

图片描述

举个例子:

// ...
let a = new Person('a')
a.toString() // "[object Object]"

Person 函数和原型上都没有 toString 方法,所以只能调用 Object 上的 toString 方法。

注意:基于同一个构造函数生成的对象,共享函数的原型,如:

// ...
let b = new Person('b')
b.name // b
b.smart = false
b.smart // false
a.smart // false
b.__proto__ === a.__proto__ // true

对 b 的 smart 属性进行修改,a 访问 smart 也有原先的 true 变为 false 了。

? Object.prototype

Object.prototype.__proto__ // null

null 是什么意思?此处无对象的意思,说明 Object.prototype 没有原型,查到这里就停止查找了,如果在找不到目标属性,就返回 undefined。

? 自身属性优先

如果自身和原型上存在同名属性,会优先使用自身属性,例如:

function Person () {
  this.name = 'Jon'
}
Person.prototype.name = 'people'
let jon = new Person()
jon.name // Jon

? 参考


Karon_
1.1k 声望16 粉丝

JavaScript