js继承
一、JavaScript 的原型
JavaScript继承可以说是发生在对象与对象之间,而原型链则是实现继承的主要方法。
根据上面的解释,我们可以得出下图,即为原型:
MDN中还有这么一句话:当谈到继承时,JavaScript 只有一种结构:对象。每个实例对象(object )都有一个私有属性(称之为 proto)指向它的原型对象(prototype)。该原型对象也有一个自己的原型对象 ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。扯太多容易乱,暂且瞄下这个概念哈。
1、原型中的术语
在原型中,有很多小伙伴对原型方面的理解存在很大的误区,笔者觉得是对原型中的术语理解不彻底或者混淆了概念。想要了解js的原型继承,需要对面向对象知识中的对象、原型、原型链、构造函数等基础知识掌握透彻,因此给小伙伴们一一介绍下原型中各位“大哥”:
(1)对象
其实所谓的对象就是一个包含相关数据的方法的集合(通常由一些变量和函数组成,我们称之为对象里面的属性和方法),在JavaScript中,所有的事物都是对象:包括基本的数据类型字符串、数值、数组、函数等,而且是允许自定义对象的
来看一下这张图片
我们初始化了一个字符串stringA和stringB,对于stringB有length和split方法是因为new了一个String对象实例,这可以理解吧。但是stringA字符串却可以获取到length属性,更神奇的是还可以使用split方法,咋们并没有定义这些东西啊,怎么能说用就用呢,神奇吧?我们来打印个东西就清晰了:
`console.log(stringA.proto === String.prototype) // true
其实stringA初始化时,是继承了String对象中的所有属性和方法,简单的说,是使用了JavaScript的内建对象,因此stringA能使用split方法并且能获取length,这其实就是原型中的一种基础继承。
(2)constructor属性
每个实例对象都从原型中继承了一个constructor属性,该属性指向了用于构造此实例对象的构造函数
(3)构造函数
主要用来在创建对象时初始化对象,即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。其实也叫构造器,如:
function Cat(name,color){
this.name = name;
this.color = color;
}
var cat1 = new Cat(‘猫哥’, ‘亮闪闪’)
cat1.name //猫哥
前端的构造函数特点:
a、构造函数的首字母必须大写,用来区分于普通函数
b、内部使用的this对象,来指向即将要生成的实例对象
c、使用New来生成实例对象
缺点:
所有的实例对象都可以继承构造函数中的属性和方法。但是,同一个对象实例之间,无法共享属性
(4)原型对象(prototype)
其他面向对象语言:面向对象的语言有一个标志,即拥有类(class)的概念,抽象实例对象的公告属性与方法,基于类可以创建多个实例对象,一般具有封装、继承、多态的特性!
在JavaScript中,并不存在类的概念,所有的实例对象需要共享的属性和方法,都放在一个对象中,哪些不需要共享的属性和方法,就放在构造函数中,以此来模拟类,而这个对象指的就是prototype,即原型对象。
注:在前端中,prototype是函数才有的对象
_proto_属性是一个访问器属性(一个getter函数和一个setter函数),暴露了通过它访问的对象的内部【[prototype]】(一个对象或者null)。通过构造函数创建的实例会包含一个_proto_属性,这个_proto_属性是一个指针,指向构造函数的原型对象。因为JavaScript都是由对象组成
a、在ES5中,所有的构造函数的_proto_都是指向Function.prototype
b、在ES6中,构造函数的_proto_指向它的父类构造函数
注:绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于 Person.prototype 中,实际上,它是来自于 Object.prototype ,与其说是一个属性,不如说是一个 getter/setter,当使用 obj.proto 时,可以理解成返回了 Object.getPrototypeOf(obj)。
(6)实例
实例时对象的具体表现,操作可以作用于实例,实例可以由状态地存储操作的结果。实列被用来模拟现实世界存在的、具体的或原型的东西。简单的说可以理解为实际的例子,构造函数通过new创建得到的对象。