Js中的原型及原型链

354 阅读4分钟

原型[prototype]

函数的prototype属性

- 每个函数都有一个prototype属性, 它指向一个默认为空的Object实例对象(即称为: 原型对象)

- 原型对象中有一个属性constructor, 它指向函数对象

在这里插入图片描述

给原型对象添加属性(一般都是方法)

 // 每个函数都有一个prototype属性, 它默认指向一个空的Object实例对象(即称为: 原型对象)
function Fun() { }
console.log(Fun.prototype)  // 默认指向一个空的Object实例对象(没有我们的属性)

console.log(Date.prototype, typeof Date.prototype)

var obj = {};
console.log(obj.prototype);

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

//给原型对象添加属性(一般是方法) ===>实例对象可以访问
Fun.prototype.test = function () { console.log('test()') }
var fun = new Fun()
fun.test()

作用

函数的所有实例对象自动拥有原型中的属性(方法)

显式原型与隐式原型

- 每个函数对象都有一个prototype,即显式原型(属性),(其实也有__proto__属性,因为他们都是Function的实例)

- 每个实例对象都有一个__ proto __,可称为隐式原型(属性)

- 对象的隐式原型的值为其对应构造函数的显式原型的值

- 他们两个存放的其实都是地址值,指向那个默认为空的Object实例对象,是对其的引用

//定义构造函数
function Fn() {
  //我们在这个过程中从未有对其添加设置prototype属性
  // 而是其js内部默认执行语句: Fn.prototype = {constructor = Fn}
}
// 1. 每个函数function都有一个prototype,即显式原型属性, 指向一个默认为空的Object实例对象
console.log(Fn.prototype)

// 2. 每个实例对象都有一个__proto__,可称为隐式原型属性
//创建实例对象
var fn = new Fn()  // 我们在这个过程中从未有对其添加设置__proto__属性,内部默认执行语句: this.__proto__ = Fn.prototype
console.log(fn.__proto__)

// 3. 对象的隐式原型的值等于其对应构造函数的显式原型的值
console.log(Fn.prototype === fn.__proto__) // true


//给原型添加方法
Fn.prototype.test = function () {
  console.log('test()')
}
fn.__proto__.test = function () {
  console.log('test()')
}
//通过实例调用原型的方法
fn.test();

内存结构图

在这里插入图片描述

总结

- 函数的[prototype]属性: 在定义函数时自动添加的, 默认值是一个空Object对象

- 对象的[__ proto __]属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值

- 程序员能直接操作显式原型, 但不能直接操作隐式原型(ES6之前)

原型链

定义

访问一个对象的属性时:

1. 先在自身属性中查找,找到返回

2. 如果没有, 再沿着[__ proto __]这条链(原型链)向上查找, 找到返回

3. 如果最终没找到, 返回undefined

// 首先要明白一点
console.log(Object);//一开始就存在

// 声明构造函数Fn
function Fn() {
  this.test1 = function () {
    console.log('test1()');
  }
}

// 向其原型对象上添加方法
Fn.prototype.test2 = function () {
  console.log('test2()');
}

// 实例化
var fn = new Fn();

fn.test1();

fn.test2();

console.log(fn.toString());

console.log(fn.test3);

fn.test3();


console.log(Object.prototype);//原型链的尽头,因为其__proto__: null
console.log(Object.prototype.__proto__);

在这里插入图片描述

别名

隐式原型链

作用

查找对象的属性(方法)

构造函数、原型、实例对象之间的关系

 var o1 = new Object();
 var o2 = {};

在这里插入图片描述

function Foo() { }
// 相当于
// var Foo = new Function();

// 所有函数的[__ proto __]都是一样的: 因为它们都是Function构造函数的实例

在这里插入图片描述

从上图可以发现:Function居然也有__proto__属性,什么东西有该属性呢? ———— 实例对象

而且此时它的__proto__属性指向的prototype属性的constructor属性指向它自己

即:

Function.__proto__ === Function.prototype

此时出现了:某个构造函数的实例对象的隐式原型属性 === 该构造函数的显式原型属性的情况

这说明什么?

这说明它是new自己产生的自己!!!

即:

Function = new Function();

还可以发现:

Object.__proto__ === Function.prototype

这说明Object也是由Function构造出来的

结论

1. Function是最顶层的构造器,Object是最顶层的对象

2. 先有的Object.prototypeObject.prototype构造出Function.prototype,然后Function.prototype构造出ObjectFunction

3. prototype是另一个对象,__proto__是指向prototype的指针属性。prototype对象一直通过[[Prototype]]往回追溯,根是Object.prototype,而Object.prototype的内部属性[[Prototype]]null

4. 从原型链讲 Function继承了Object

5. 从构造器讲 Function构造了Object

我们之前说所有的函数的原型对象都是默认为空的Object实例对象,但是这里要加一个Object的原型对象除外

个人总结图

在这里插入图片描述

属性问题

- 读取对象的属性值时: 会自动到原型链中查找

- 设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值

- 方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上

function Fn() { }
  Fn.prototype.a = 'xxx'
  var fn1 = new Fn()
  console.log(fn1.a, fn1) //xxx Fn{}

  var fn2 = new Fn()
  fn2.a = 'yyy'
  console.log(fn1.a, fn2.a, fn2) //xxx yyy  Fn{a: "yyy"}

  function Person(name, age) {
    this.name = name
    this.age = age
  }
  Person.prototype.setName = function (name) {
    this.name = name
  }
  var p1 = new Person('Tom', 12)
  p1.setName('Bob')
  console.log(p1)  //Person {name: "Bob", age: 12}

  var p2 = new Person('Jack', 12)
  p2.setName('Cat')
  console.log(p2) //Person {name: "Cat", age: 12}
  console.log(p1.__proto__ === p2.__proto__) // true   -->所以方法一般定义在原型中

instanceof

instanceof是如何判断的

- 表达式: A instanceof B

- 如果B函数的显式原型对象在A对象的原型链上, 返回true, 否则返回false

/*
 案例1
  */
 function Foo() {  }
 var f1 = new Foo()
 console.log(f1 instanceof Foo) // true
 console.log(f1 instanceof Object) // true

 /*
 案例2
  */
 console.log(Object instanceof Function) // true
 console.log(Object instanceof Object) // true
 console.log(Function instanceof Function) // true
 console.log(Function instanceof Object) // true

 function Foo() {}
 console.log(Object instanceof  Foo) // false

逻辑关系图1

在这里插入图片描述

逻辑关系图2

在这里插入图片描述