原型链

180 阅读3分钟

原型

为什么要用原型

为了节约内存空间

function User(name) {
    this.name = name
    this.say = function(){
        alert(`my name is ${this.name}`)
    }
}

const jack = new User('jack')
const tom = new User('tom')
console.log(jack.say === tom.say)  // false

通过原型实现函数复用

function User(name) {
    this.name = name
}
User.prototype.say = function(){
    alert(`my name is ${this.name}`)
}

const jack = new User('jack')
const tom = new User('tom')
console.log(jack.say === tom.say)  // true

什么是原型

  • a.__ proto __ : 此时a是一个实例
  • a.prototype : 此时a是一个构造函数
graph LR

构造函数 --prototype--> 原型
构造函数 --new-->  实例
实例 --____proto__--> 原型

原型链

image.png

例1:

  • 数组a是Array创建出来的对象
  • Array.prototype是Object创建出来的对象
graph LR

数组a --__proto__--> Array.prototype
Array.prototype --__proto__--> Object.prototype
Object.prototype --__proto__--> null

image.png

重中之重

  • Function = new Function()
  • Object = new Function()
  • Function.prototype = new Object()
  • Array.prototype = new Object()
  • Object.prototype.__ proto __ = null
  • 看到 A.ptotoype, 就要想到A是构造函数
  • 看到 a._proto_ 就思考:
    • newa,
    • a = new A()
    • 所以 a.__proto__ === A.ptototype
function User(name){
  this.name = name
}

User.prototype.say = function(){
  console.log(this.name)
}

const u1 = new User()
const u2 = new User()


console.log(u1.say === u2.say) // true

// User.prototype此时User是一个构造函数
// 每一个构造函数都有一个共用空间 prototype
console.log(User.prototype === Function.prototype) // false

// User.__proto__ 就要想是谁new出了User
// User = new Function()
console.log(User.__proto__ === Function.prototype) // true

// 看到User.__proto__就要想: 是谁new了User
// User是构造函数, new它的肯定就是Function
// User = new Function()
// 所以 User.__proto__ === Function.prototype
// 同理:
// 看到Function.__proto__就要想: 是谁new了Function
// Function = new Function()
// 所以 Function.__proto__ === Function.prototype
console.log(User.__proto__ === Function.__proto__) // true

// u1 = new User()
// u2 = new User()
console.log(u1.__proto__ === u2.__proto__)  // true

// 所有的构造函数都是Function new 出来的
// User = new Function()
// u1 = new User()
console.log(u1.__proto__ === User.__proto__)  // false

// 所有的构造函数都是Function new 出来的
// Object = new Function()
// Function = new Function()
console.log(Object.__proto__ === Function.__proto__) // true

// Object.prototype.__proto__ = null
// Function.prototype = new Object()
console.log(Object.prototype.__proto__ === Function.prototype.__proto__) // false

// Function.prototype = new Object()
console.log(Object.prototype === Function.prototype.__proto__) // true

例2:

全为true

console.log({} instanceof Object) 
console.log({}.toString instanceof Function)
// 求出原型链: Object.__proto__
// Object = new Function()
// Object --> Function.prototype --> Object.prototype --> null
console.log(Object instanceof Function)
// 求出原型链: Function.__proto__
// Function = new Function
// Function --> Function.prototype --> Object.prototype --> null
console.log(Function instanceof Object)

例3:


Function.prototype.a = 1
Object.prototype.b = 2 

function A() {}

var a = new A()
// 找出原型链: a --> A.prototype --> Object.prototype --> null
// undefind, 2
console.log(a.a, a.b) 

// 原型链: A --> Functin.prototype --> Object.prototype --> null
// 1, 2
console.log(A.a, A.b)

例4:

new Son() --> Son.prototype=new Father() --> Father.prototype --> Object.prototype --> null

function Father(name, age) {
  this.name = name;
  this.age = age;
}

Father.prototype.work = function () {
  alert("work");
};

function Son(name, age) {
  Father.call(this, name, age);
}
Son.prototype = new Father();
Son.prototype.play = function () {
  alert("play");
};

const jack = new Son("jack", 19);

继承

通过原型和构造器

import "./styles.css";

function Father(name, age) {
  this.name = name;
  this.age = age;
}

Father.prototype.work = function () {
  alert("work");
};

function Son(name, age) {
  Father.call(this, name, age);
}
Son.prototype = new Father();
Son.prototype.play = function () {
  alert("play");
};

const jack = new Son("jack", 19);

console.log(jack);

es6中实现继承

class Father {
  constructor(name) {
    this.name = name;
  }
  work() {
    console.log("work");
  }
}

class Son extends Father {
  constructor(name, age) {
    super(name);
    this.age = age;
  }
  play() {
    console.log("play");
  }
}

const jack = new Son("jack", 19);

案例

例一:

一个页面的脚本如下,请问会打印出什么内容?为什么?

function Dog() {
  this.name = 'puppy'
}
Dog.prototype.bark = () => {
  console.log('woof!woof!')
}
const dog = new Dog()
dog.prototype.bark()

答案:

会报错

Cannot read property 'bark' of undefined
  • 在原型链上, __proto__是线, prototype是点
  • 普通对象实例是没有prototype这个属性的,也就是说普通对象的prototype属性的值是undefined。

image.png

例二:

如何给一个实例指定原型呢?

var a = {name: 'dog'}
var b = {age: 15}
a.__proto__ = b
a.age === 15 // true

例三:

一个页面的脚本如下,请问会打印出什么内容?为什么?

function Dog() {
  this.name = 'puppy'
}
Dog.prototype.bark = () => {
  console.log('woof!woof!')
}

const dog = new Dog()
console.log(Dog.prototype.constructor === Dog && dog.constructor === Dog && dog instanceof Dog)

答案:

打印出:true。

image.png

例四:

一个页面的脚本如下,请问会打印出什么内容?

function Dog() {
  this.name = 'puppy'
}
Dog.prototype.bark = () => {
  console.log('woof!woof!')
}
function BigDog() {}
BigDog.prototype = new Dog()
const bigDog = new BigDog()
console.log(bigDog.constructor === BigDog)

答案:

打印出:false

bigDog --> BigDog.prototype === new Dog() --> Dog.prototype 

Dog.prototype.constructor === Dog
graph LR
Dog{Dog}--prototype-->DP[Dog.prototype]
DP--counstructor-->Dog
bigdog((bigDog))--__proto__-->dog((dog))
dog--__proto__-->DP
BigDog{BigDog}--prototype-->dog
BDP[BigDog.prototype]--counstructor-->BigDog
BigDog--x断开-prototype-->BDP

例5:

一个页面的脚本如下,请问会打印出什么内容?

const a = {}
console.log(a.__proto__ === Object.prototype)

答案: true

graph TB
O{Object}--prototype-->op[Object.prototype]
op--counstructor-->O
a((a))--__proto__-->op

例6: 原型链的终点是什么?如何打印出原型链的终点?

由于Object是构造函数

原型链终点是Object.prototype.__proto__,而

Object.prototype.__proto__=== null // true

所以,原型链的终点是null

graph BT
O{Object}--prototype-->op[Object.prototype]
op--__proto__-->null((null))

例7

function Foo() {
  Foo.a = function () {
    console.log(1);
  };
  this.a = function () {
    console.log(2);
  };
}

Foo.prototype.a = function () {
  console.log(3);
};

Foo.a = function () {
  console.log(4);
};

Foo.a();

let foo = new Foo();
foo.a();
Foo.a();

// 答案
Foo.a(); // 4

let foo = new Foo();
foo.a(); // 2
Foo.a(); // 1

画图

constructor

Foo --protptype--> Foo.prototype
Object --protptype--> Object.prototype
Functon --protptype--> Functon.prototype

Foo.prototype --constructor--> Foo
Object.prototype --constructor--> Object
Functon.prototype --constructor--> Functon
graph TB;

subgraph 1
Foo --protptype--> Foo.prototype
Object --protptype--> Object.prototype
Functon --protptype--> Functon.prototype
Foo.prototype --constructor--> Foo
Object.prototype --constructor--> Object
Functon.prototype --constructor--> Functon
end

_ proto _

在原型链上: prototype是节点, __ proto __ 是线

// -.-> 表示虚线
// 虚线 表示 __proto__
// f1 = new Foo()
// f2 = new Foo()
// o1 = new Object()

f1 -.-> Foo.prototype
f2 -.-> Foo.prototype
o1 -.-> Object.prototype
o2 -.-> Object.prototype
graph TB;

subgraph 原型图
Foo --protptype--> Foo.prototype
Object --protptype--> Object.prototype
Functon --protptype--> Functon.prototype
Foo.prototype --constructor--> Foo
Object.prototype --constructor--> Object
Functon.prototype --constructor--> Functon
end

subgraph 虚线表示__proto__
f1 -.-> Foo.prototype
f2 -.-> Foo.prototype
o1 -.-> Object.prototype
o2 -.-> Object.prototype
end

原型链的终点是null


// -.-> 表示虚线 
// 虚线 表示 __proto__ 
// f1 = new Foo() 
// f2 = new Foo() 
// o1 = new Object()

Foo.prototype -.-> Object.prototype
Functon.prototype -.-> Object.prototype
Object.prototype -.-> null
graph TB;

subgraph 1
Foo --protptype--> Foo.prototype
Object --protptype--> Object.prototype
Functon --protptype--> Functon.prototype
Foo.prototype --constructor--> Foo
Object.prototype --constructor--> Object
Functon.prototype --constructor--> Functon
end

subgraph 虚线表示__proto__
f1 -.-> Foo.prototype
f2 -.-> Foo.prototype
o1 -.-> Object.prototype
o2 -.-> Object.prototype
end

Foo.prototype -.-> Object.prototype
Functon.prototype -.-> Object.prototype
Object.prototype -.-> null

函数的原型链

所有函数的 _proto_ =Functon.prototype

// -.-> 表示虚线
// 虚线 表示 __proto__

Foo -.-> Functon.prototype
Functon -.-> Functon.prototype
Object -.-> Functon.prototype
graph TB;

subgraph 1
Foo --protptype--> Foo.prototype
Object --protptype--> Object.prototype
Functon --protptype--> Functon.prototype
Foo.prototype --constructor--> Foo
Object.prototype --constructor--> Object
Functon.prototype --constructor--> Functon
end

subgraph 虚线表示__proto__
f1 -.-> Foo.prototype
f2 -.-> Foo.prototype
o1 -.-> Object.prototype
o2 -.-> Object.prototype
end

Foo.prototype -.-> Object.prototype
Functon.prototype -.-> Object.prototype
Object.prototype -.-> null

Foo -.-> Functon.prototype
Functon -.-> Functon.prototype
Object -.-> Functon.prototype

原型图

1671d387e4189ec8~tplv-t2oaga2asx-watermark.image.png