前言
js原型这块,之前是半蒙半懂,今天终于在闲暇之余将这个概念深入到底,下面是我的个人理解,如果错误请指正。
继承的概念
继承是面向对象软件技术当中的一个概念,与多态、封装共为面向对象的三个基本特征。继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等
js如何定义继承
js中没有类的概念,只有对象(函数也是对象),每一个对象的都有一个私有属性__proto__指向它的构造函数的prototype,该原型对象又有__proto__属性指向它的构造函数的prototype,层层向上直到一个对象的原型对象为 null
let fn=function(){}
fn.__proto__.__proto__.__proto__==null //true
fn instanceof Function //true
注意!
Function.prototype是 函数RegExp.prototype是 正则表达式Array.prototype是 数组
如上图所示:
fn.__proto__指向Function.prototype
Function.prototype.__proto__指向Object.prototype
Object.prototype.__proto__是null
便于理解,构造函数称呼改为class, 只要x.__proto__指向y的prototype,那么x就拥有了y的一些属性和方法(可以理解为x就是y的实例),那么fn(这个Funtion类的实例)通过层层原型链,拥有了Object类的属性和方法,所以可以说Function类继承了Object类
这种基于原型链的方式就是js的继承方式
new一个对象
-
如果用
new关键词生成实例,那么实例都可以使用prototype里的属性和方法; 原理是js的原型链,在当前obj上找不到此属性或方法的时候,就在obj.__proto__上找,一直找,直到找到为止,如果当...__proto__==null的时候都没有找到,那么就报undefined -
js函数没有放在
prototype的属性和方法,只有函数本身可以使用,不可以被继承,比如Number.max() Date.now(),也可称为静态方法 -
js对象有三种构建方式:
1)
{}对象字面量:可以理解为若干个属性集合,值可以是基本类型或者object类型2)
new Fn()通过构造函数创建3)
Object.create(null)可以创建一个没有原型链的对象 -
js继承这个说法不是很准确,因为js的继承并不是将父类的属性和方法复制到子类,而是js引擎通过原型链寻找属性和方法,所以用委托这个词比较贴切
借用其他同学的例图:
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
}
function SubType() {
this.subproperty = false;
}
// 这里是关键,创建SuperType的实例,并将该实例赋值给SubType.prototype
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function() {
return this.subproperty;
}
var instance = new SubType();
console.log(instance.getSuperValue()); // true
js常见的继承模式
基于原型链
不足:1. 子类生成的实例都共享一个对象(就是父类的一个实例对象);2.不能给超类的构造函数传参数
function SuperType(){
this.name="i'm your father"
}
SubType.prototype=new SuperType()
SubType.prototype.constructor=SubType
借用构造函数(经典继承)
不足:超类原型上的方法不可见,不好复用,所以一般不单独使用
function SubType(args){
SuperType.call(this,args)
}
组合继承(伪经典继承)
不足:调用了两次父类构造函数
function SubType(){
//继承父类属性
SuperType.call(this)
}
//继承父类方法
SubType.prototype=new SuperType()
SubType.prototype.constructor=SubType
原型式继承
指定一个对象作为原型创建
Object.create(protoObject/*指定对象*/)
寄生式继承
function create(protoObject){
let clone=Object.create(protoObject/*指定对象*/)
//增加方法
clone.fn=function(){}
return clone
}
寄生组合式继承
function inheritPrototype(subType,superType){
// 以superType.prototype为原型
// 使subType.prototype.__proto__=superType.prototype
// 从而形成一个原型链来实现父类方法的继承
subType.prototype=Object.create(superType.prototype)
//将构造函数纠正为子类
subType.prototype.constructor=subType
}
es6新特性
Object.getPrototypeOf()和Object.setPrototypeOf()
从 ECMAScript 6 开始,[[Prototype]] 可以通过 Object.getPrototypeOf() 和 Object.setPrototypeOf() 访问器来访问。这个等同于 JavaScript 的非标准但许多浏览器实现的属性 __proto__。
class语法糖
class Person{
static name
//构造函数
constructor(name){
this.name=name
}
//原型方法
say(){
return `my name is ${this.name}`
}
}
class Man extends Person{
constructor(name){
super(name)
this.gender="man"
}
say(){
return `i'm a ${this.gender}`
}
}
extends与寄生组合式继承模式一样,作用如下:
super(this)借用父类的构造函数,默认隐式执行,如果子类需要扩展,则需要先显示执行。Man.prototype.__proto__ = Person.prototype通过将原型对象指向父类原型对象,来继承父类的可继承属性和方法Man.prototype.constructor = Man将构造函数纠正为子类本身
结语
以上是我个人对 js继承的理解,如有错误,请指正。