学习笔记:JS高级——原型和原型链

24 阅读3分钟

原型prototype

  1. 函数的prototype属性
    • 每个函数都有一个prototype属性,它默认指向一个Object空对象(即称为:原型对象)
    • 原型对象中有一个属性constructor,它指向函数对象

image.png

  1. 给原型对象添加属性(一般为方法)
    • 作用:函数的所有实例对象自动拥有原型中的属性(方法)
console.log(Date.prototype, typeof Date.prototype) // Date在初始化时,已经添加了许多方法

function Fn() {}

console.log(Fn.prototype) // 默认指向一个Object空对象(没有开发者添加的属性)

Fn.prototype.test = function (){
    console.log('test()')
}

console.log(Fn.prototype) // 此时Object中有了开发者添加的方法

// 原型对象中有一个属性constructor,它指向函数对象
console.log(Date.prototype.constructor === Date)
console.log(Fn.prototype.constructor === Fn)

// 给原型对象添加属性(一般为方法)=> 实例对象可以访问
var fn = new Fun()
fn.test() // test()

显式原型和隐式原型

  1. 每一个函数function都有显式原型,即prototype属性
  2. 每一个实例对象都有隐式原型,即__proto__属性
  3. 实例对象的隐式原型 指向 其对应函数的显式原型
function Fn() { // 内部语句:this.prototype = {}
    // add some propert
}
// 1.每一个函数function都有显式原型,即prototype属性
console.log(Fn.prototype)
var fn = new Fn() // 内部语句:this.__proto__ = Fn.prototype
// 2. 每一个实例对象都有隐式原型,即__proto__属性
console.log(fn.__proto__)
// 3. 实例对象的隐式原型 **指向** 其对应函数的显式原型
console.log(fn.__proto__ === Fn.prototype) // true

// 给原型添加方法
Fn.prototype.test = function () {
    console.log('test()')
}
fn.test() // test()
  1. 内存结构(图)

image.png

  1. 总结:
    • 函数对象的prototype属性:在定义函数对象时自动添加,默认值是一个空object对象
    • 实例对象的__proto__属性:在创建实例对象时自动添加,默认值是其构造函数的prototype属性值
    • 开发者能直接操作显式原型,但不能直接操作隐式原型(ES6之前)

原型链

  1. 图解
    • 访问一个对象的属性时

      1. 首先在自身属性中查找,找到返回
      2. 如果没有,再沿着__proto__这条链向上查找,找到返回
      3. 如果最终没找到,则返回undefined
    • 别名:隐式原型链

    • 作用:查找对象的属性(方法)

function Fn() {
    this.test1 = function () {
        console.log('test1()')
    }
}
Fn.prototype.test2 = function () {
    console.log('test2()')
}
var fn = new Fn() 

fn.test1() // fn => 4 => test1
fn.test2() // fn => 4 => 5 => test2
console.log(fn.toString()) // fn => 4 => 5 => 8 => toString
fn.test3() // Error: fn.test3 is not a function

image.png

  1. 构造函数与实例对象的关系(图解)
    • 所有函数的__proto__都是指向Function的原型对象
    • 所有函数都是Function的实例,包括它本身
    • 函数的显式原型指向的对象默认是空Object实例对象,但是函数对象Object指向的是null
    • Object的原型对象是原型链尽头
// 引擎内部还会有以下两条语句
// Function = new Function()
// Function Object = new Function()

function Foo() { // 内部相当于 Function Foo = new Function()
    // add some properties
}

// 函数的显式原型指向的对象默认是空Object实例对象,但是函数对象Object指向的是null
console.log(Foo.prototype instanceof Object) // true
console.log(Object.prototype instanceof Object) // false
console.log(Function.prototype instanceof Object) // true

// 所有函数都是Function的实例,包括它本身
console.log(Function.__proto__ === Function.prototype) // true

// Object的原型对象是原型链尽头
console.log(Object.prototype.__proto__) // null

image.png

属性问题

  1. 读取对象的属性值时:会自动到原型链中查找
  2. 设置对象的属性值时:不会查找原型链,如果当前对象中没有此属性,则直接添加此属性到对象中
  3. 方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
function Fn() {
    // add some properties
}
Fn.prototype.a = 'xxx'
var fn1 = new Fn()
console.log(fn1.a) // xxx

var fn2 = new Fn()
fn2.a = 'yyy' // 注意!此时添加到fn2实例对象的属性中
console.log(fn1.a) // xxx
console.log(fn2.a) // yyy

// 一般情况下,属性一般通过构造函数定义在对象本身上
function Person(name, age) {
    this.name = name,
    this.age = age
}
Person.prototype.setName = function(name) {
    this.name = name
}

var p1 = new Person('Joshua', 22)
p1.setName('Bob')
console.log(p1)