JavaScript的原型与继承讲解

关于JS的原型与继承相关概念 在ES6后,JavaScript已经可以通过class、extends等语法糖实现面向对象的写法,但是以前的原型对象也是必须得了解的,看文章的话记不清楚,自己总结一下。 构造...

关于JS的原型与继承相关概念

在ES6后,JavaScript已经可以通过class、extends等语法糖实现面向对象的写法,但是以前的原型对象也是必须得了解的,看文章的话记不清楚,自己总结一下。


构造函数

在说原型前,有必要了解一下以前的面向对象的写法,JavaScript的对象是通过构造函数实例获得的:

function Fo(msg) {
  this.msg = msg
}


Person就是一个构造函数,一般首字母大写。并且有两个形参:name和sex,赋值给了this对象。

此时,可以通过new的操作获取一个Person的实例:

const f = new Foo('Hello')
console.log(f.msg)  // Hello


这里有一个问题,为什么通过man这个实例对象能访问到msg呢,这里就要说一下new的操作了,其实在new实例化构造函数时,内部做了以下操作:

var obj = {}
obj.__proto__ = Person.prototype
Person.call(obj)
return obj


上面看到了两个奇怪的东西,就是__proto__和prototype,那这两个又是啥呢?


原型对象和原型链

__proto__:每个实例对象都有这一个属性,与构造函数的原型函数对应;

prototype:原型对象,每一个构造函数都有这一个对象。

从下面这张图,我们可以看到两者的关系:

attachments-2021-07-dch4sZmw60fa41759ad36.png

从图中可以看到,实例对象的__proto__是指向其构造函数的prototype的,并且有JavaScript在使用属性或方法时有一个特点就是,在当前实例对象寻找需要调用的属性或方法,如果没有,则向实例对象的proto**(也就是构造函数的prototype对象上找),直到找到或者到顶层的null为止。**


并且从代码中,可以看到是完全相等的:

console.log(f.__proto__ === Fo.prototype) // true


由f.__proto__ => Fo.prototype => Fo.prototype.__proto__ => Object.prototype => null,这就形成了一条链式的结构,这就是所谓的原型链。


继承

JavaScript的继承分为两种情况,第一种是继承属性,可以通过call方法来实现,第二种就是方法的继承,需要通过原型链来实现,看一下代码:

function Foo(msg) {
  this.msg = msg
}
Foo.prototype.printMsg = function () {
  console.log(this.msg)
}
function Fo(msg, greet) {
  Foo.call(this, msg)
  this.greet = greet
}
Fo.prototype = new Foo()
Fo.prototype.constructor = Fo
Fo.prototype.printGreet = function () {
  console.log(this.greet)
}
const fo = new Fo('Hello', 'How are you?')
console.log(fo)


打印这个fo,可以看到下图:

attachments-2021-07-Cr8JfQtK60fa41ca4ecbc.png

明显的,greet属性和msg属性就是属于Fo实例对象的,然后看看printMsg和printGreet这两个方法:


printGreet此时是在fo的__proto__上的,即Fo.prototype上;

又因为Fo.prototype又指向了Foo的实例对象,所以Fo.prototype其实是指向Foo的实例对象的;

最后可以看到printMsg是挂在Foo.prototype原型对象上的。


所以,可以看出我们访问fo对象的属性时,本身就在实例对象上,可以直接访问到;

而当访问方法时,是通过访问fo.__proto__即Fo.prototype即Foo实例对象上找的,又根据原型链的特点,访问不到对应方法时,会往Foo实例对象的__proto__属性即Foo.prototype上找,所以就实现了方法的继承。

总结

其实,JavaScript的对象是通过new构造函数得到的,new的过程内部已经帮我们处理过了;

继承是通过原型链的特点来实现的,把“子类”的prototype指向“父类”的实例对象,这样通过原型链查找时,自然会找从子类找向父类。

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
admin
admin

651 篇文章

作家榜 »

  1. admin 651 文章
  2. 粪斗 185 文章
  3. 王凯 92 文章
  4. 廖雪 78 文章
  5. 牟雪峰 12 文章
  6. 李沁雪 9 文章
  7. 全易 2 文章
  8. Stevengring 0 文章