原型
为什么要用原型
为了节约内存空间
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__--> 原型
原型链
例1:
- 数组a是Array创建出来的对象
- Array.prototype是Object创建出来的对象
graph LR
数组a --__proto__--> Array.prototype
Array.prototype --__proto__--> Object.prototype
Object.prototype --__proto__--> null
重中之重
- Function = new Function()
- Object = new Function()
- Function.prototype = new Object()
- Array.prototype = new Object()
- Object.prototype.__ proto __ = null
- 看到
A.ptotoype, 就要想到A是构造函数 - 看到
a._proto_就思考:- 谁
new了a, 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。
例二:
如何给一个实例指定原型呢?
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。
例四:
一个页面的脚本如下,请问会打印出什么内容?
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