javascript的原型和继承

在这里插入图片描述

1.什么是原型?

  • javascript中的对象有个内置属性[[Prototype]],称为原型
  • [[Prototype]]是对其他对象的引用
  • 每个函数都会创建一个prototype属性,这个属性是一个对象。分别称之为构建函数, 原型对象

[[Prototype]]原型 指向 一个prototype原型对象

function Car(name){this.name=name;this.type='手动挡';} //这个name直接挂载在Car
Car.prototype.name='车' //可以在Car的原型对象上挂载新的属性
Car.prototype.getName=function(){return this.name;} //挂载新的方法
Car.prototype.fuel='石油';
Car.prototype.getFuel=function(){return this.fuel;}
const car = new Car('小车车'); //car是Car的一个实例对象
const tesla = new Car('特斯拉');

在这里插入图片描述

tesla.type='自动挡';
console.log(car,tesla);//{小车车,手动挡} {特斯拉,自动挡}
console.dir(car); //car的原型指向Car.prototype
car.getName(); //getName方法在原型中,car有直接挂载name:小车车
car.getFuel(); //car没有直接挂载fuel,所以取原型中的fuel:石油

lab1

  • 改变Car.prototype的属性时,car和tesla随之反应
  • 改变直接挂载在Car上的属性时,car和tesla不受影响

改变属性

2.什么是原型链?

  • 创建卡丁车,使得卡丁车的原型是小车车
    原型链
    原型链

在原型链上,如果在对象上找不到需要的属性或者方法,引擎就会继续在[[Prototype]]指向的原型上查找。

3.原型链继承

  • 在传统OOP中,继承的本质是复制,子类拷贝了父类的方法和属性。
  • 根据原型的特性,js中继承的本质是链接。
  • 探索差异

3.1 原始方式

Kart.prototype=car
让构造函数的prototype指向另一个构造函数的实例。

数组Array, 日期Data是常见的引用数据类型
引用数据类型在赋值时传递引用地址而不是具体值

function Car(){this.date=new Date();}
function Kart(){}
Kart.prototype=new Car(); // 原型对象指向Car的实例
const kart = new Kart();
const renault = new Kart(); 
kart.date.setFullYear(2000); //设置日期的年份
//观察renault.date是否随之变化。

缺点:当原型上的属性是引用数据类型时,所有实例都会共享这个属性。
共享引用类型

3.2 经典继承

function Kart(){Car.call(this);}
在子类中调用父类的构造函数,实现上下文的绑定
经典继承
缺点:丢失父类的原型
丢失

3.3 组合继承

function Kart(){Car.call(this);}Kart.prototype=new Car();
二者取其优,十分nice!
也有缺点:性能浪费!这里两次调用了Car的构造函数

在子类构造函数内部调用Car.call(this)
在修改子类原型时调用 new Car(),将引入多余的属性或方法
产生不必要的内存消耗和性能损失

4. 原型式继承

Douglas Crockford在它的《JavaScript编程风格指南》中提出。

  • 原型链是实现对象之间继承关系的机制
  • 原型式继承是基于原型链机制的继承方式
  • 复制已有对象的属性和方法来创建新对象

经典函数: 原型继承的核心代码

const object = function(o){
	function F() {}
	F.prototype = o
	return new F()
}
//返回的实例对象的[[Prototype]]指向o,从而实现继承

4.1 原始

共享

ES5的Object.create()将原型式继承规范化

缺点:共享引用类型的属性,同原始链继承(3.1

4.2 寄生式组合继承

4.2.1 增强对象

function parasitize(o){
	let clone = Object.create(o);
	clone.run = function(){return '速度七十迈';}
	return clone;
}
function Car(){this.date=new Date();}
const car = new Car();
const kart = parasitize(car);
const renault = parasitize(car);

增强

4.2.2 改变原型的constructor指向

function parasitize(Son,Father){
	const prototype = Object.create(Father.prototype);//此prototype是副本
	prototype.constructor = Son;
	Son.prototype = prototype;
	//两步下来,副本为Son所用
	//无需返回,只需改变子类的原型对象
}
function Car(){this.date=new Date();}
function Kart(){Car.call(this)} //调用构造函数
parasitize(Kart,Car); //不用二次调用构造函数
const kart = new Kart();
const renault = new Kart();

好的
原型链关系同 组合式继承(3.3)
寄生组合式继承是对组合式继承的优化改进。

通过使用Object.create(Father.prototype)避免调用父类构造函数,从而避免引入多余属性或方法

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值