day18 原型和继承
文章目录
函数的prototype
-
每一个函数内都存在一个prototype的对象空间 构造函数也是函数,所以也存在
-
prototype这个空间会在预编译的时候进行开辟(只开辟一次)
-
prototype里面的内容可以直接通过对应的 实例对象.方法名 来访问
利用prototype可以解决构造函数会开辟多个内存空间的问题
class的相关机制
class里,constructor外部声明的函数会默认直接加入到原型prototype中
class Animal{
constructor(){}
say(){
console.log('hello')
}
}
console.log(new Animal().say === new Animal().say)//true
对象的__proto__
__ptoto__
是对象的一个对象空间,他指向对应的构造函数的prototype
对象的__proto__
保存着该对象的构造函数的prototype
原型链
在_proto_
寻找属性的过程形成的链子 被称为原型链
示例
fucntino Person(){
}
let person = new Person()
console.log(person.__proto__)//person构造函数的prototype
console.log(person.__proto__.__proto__)//Person构造函数的prototype(也是个对象)
理解
Object.prototype.test = function(){
console.log('test');
}
class Animal{
constructor(){
this.name = 'Animal'
}
run(){
console.log('run!');
}
}
class Dog extends Animal{
constructor(){
super()
this.color = 'yellow'
}
say(){
console.log('wooh!');
}
}
let dog = new Dog()
dog.age = 9
let animal = new Animal()
animal.age = 18
let obj = new Object()
obj.weight = 99
console.log(dog.__proto__)//Animal {constructor: ƒ, say: ƒ}
console.log(Dog.prototype)//Animal {constructor: ƒ, say: ƒ}
console.log(dog.__proto__.__proto__)//Animal的prototype
console.log(dog.__proto__.__proto__.__proto__)//Object的prototype
console.log(dog.__proto__.__proto__.__proto__.__proto__)//null
模拟实现instanceOf 原型链查找构造函数
function MyInstanceOf(obj,con){
while(obj.__proto__){
obj = obj.__proto__
if(obj.constructor == con){
return true
}
}
return false
}
console.log(MyInstanceOf(dog,Animal));//true
模拟实现一个new
function Person(){
this.name = name
}
function myNew(fn){
let obj = {}//新建一个空对象
obj.__proto__ = fn.prototype//将构造函数的原型放到这个空对象的__proto__上
fn.call(obj)//执行构造函数,将this指向这个新对象
return obj//最后返回这个构造完成的对象
}
console.log(myNew(Person));
继承
class继承
extends
构造函数继承
-
原型继承
new一个父类对象,放在子类的原型上,此后new一个子类对象,都可以继承到父类的属性和方法
缺点:继承的属性,无法赋初始值
-
对象冒充继承
将父类的构造函数当做普通函数执行,并且将this指向改为子类
缺点:无法继承原型方法
-
组合继承
结合原型继承和对象冒充继承
缺点:原型上会有重复的属性
-
寄生组合继承
利用寄生原型(将父类原型对象加入到子类的原型上)+对象冒充
原型上不再会有重复的属性,但是不会继承静态的属性和方法
原型继承
new一个父类对象,放在子类的原型上,此后new一个子类对象,都可以继承到父类的属性和方法
- 缺点:继承的属性,无法赋初始值
// 原型继承
function Person(name, age) {
this.name = name
this.age = age
}
//原型方法
Person.prototype.sayHello = function () {
console.log('hello')
}
//静态方法
Person.run = function () {
console.log('run')
}
function Student(score) {
this.score = score
}
//new一个Person对象,放在Student的原型上,此后new一个student对象,都可以继承到Person的属性和方法
Student.prototype = new Person()
console.log(new Student(99))//Student
//继承的属性,无法赋初始值,因为是个新的对象
console.log(new Student(99).name)//undefined
console.log(new Student(99).age)//undefined
new Student(99).sayHello()//hello
对象冒充继承
将父类的构造函数当做普通函数执行,并且将this指向改为子类
- 缺点:无法继承方法
// 对象冒充继承
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayHello = function () {
console.log('hello')
}
Person.run = function () {
console.log('run')
}
function Student(score,name,age) {
// 将Person的构造函数当做普通函数执行,并且将this指向改为Student
Person.call(this,name,age)
this.score = score
}
console.log(new Student(99,'zs',18))//Student {name: 'zs', age: 18, score: 99}
new Student(99).sayHello()//报错,无法继承到Person的原型方法
组合继承
结合原型继承和对象冒充继承
- 缺点:原型上会有重复的属性
// 寄生组合继承
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayHello = function () {
console.log('hello')
}
Person.run = function () {
console.log('run')
}
// 结合原型继承和对象冒充继承
function Student(score, name, age) {
// 将Person的构造函数当做普通函数执行,并且将this指向改为子类
Person.call(this, name, age)
this.score = score
}
// new 一个Person对象,放在Student的原型上,此后new一个student对象,都可以继承到Person的属性和方法
Student.prototype = new Person()
console.log(new Student(99,'zs',18))//Student {name: 'zs', age: 18, score: 99}
new Student(99).sayHello()//hello
寄生组合继承
利用寄生原型(将父类原型对象加入到子类的原型上)+对象冒充
- 原型上不再会有重复的属性
- 但是不会继承静态的属性和方法
// 寄生组合继承
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayHello = function () {
console.log('hello')
}
Person.run = function () {
console.log('run')
}
// 结合原型继承和对象冒充继承
function Student(score, name, age) {
// 将Person的构造函数当做普通函数执行,并且将this指向改为子类
Person.call(this, name, age)
this.score = score
}
// 将父类的原型对象加入到子类的原型对象
Student.prototype = Object.create(Person.prototype)
console.log(new Student(99,'zs',18))//Student {name: 'zs', age: 18, score: 99}
new Student(99).sayHello()//hello