资讯专栏INFORMATION COLUMN

JavaScript原型、原型链、继承的理解

Aceyclee / 539人阅读

摘要:构造函数实例和原型的概念和关系每个函数都属于对象,都会有一个属性叫。这也是继承的依据。这样一来,原型找不到构造函数,这是非常蛋疼的事情,违反了原型链的定义啊。所以现在子对象原型和父对象原型是就建立关系了。

构造函数、实例和原型的概念和关系

每个函数都属于对象,都会有一个属性叫prototype。这个属性指向一个对象,我们把他叫做当前函数的原型对象。原型对象下面有个属性叫constructor.这个属性指向当前函数。函数又分为普通函数和构造函数。这里我们说一下构造函数。
定义一个函数 :

function Person(x, y ) {
this.age = x;
this.name = y;
}
var xiaoming= new Person(12, "xiaoming" );

这里创建实例对象 xiaoming的时候就是调用了Person构造函数,使xiaoming有了自己的属性和方法,之后xiaoming和Person也就没有什么直接交集了(可以理解为小明分手了,哎程序员好难╥..╥)
但是每个实例对象都会有一个隐藏属性[[prototype]],这个属性在chrome/firefox下叫__proto__,仅仅供学习调试用.它指向的就是构造函数的原型对象。

原型对象的深入理解

对于这个原型对象,我们就要重点理解下了。这个对象的作用就是为了让所有的实例对象都能共享这个对象的属性和方法(当然实例本身的属性和方法优先级是高于原型的)。每个构造函数都会有一个默认的原型对象。我们只要在改原型对象上做文章就可以实现很多功能。

● 共享属性和方法:

Person.prototype.eyes = 2;
Person.prototype.walk = function ( ){……};
var xiaoming= new Person(12, "xiaoming" );
var xiaohong= new Person(12, "xiaohong" );
xiaoming.eyes
xiaohong.eyes
 // 小明和小红都有2只眼
xiaoming.walk 
xiaohong.walk
//小明和小红都会走路

● 原型链:
我们先做一个假设,假如我们把一个函数对象Man的原型直接给换成另一个函数对象Person的实例对象xiaoming会怎么样呢?
前面说了,通过实例对象是可以找到函数对象Person的原型。那我们现在Man对象的实例xiaoming是不是也就可以访问到Person对象的原型对象了呢。

function Man( ) {
this.beard = "xxx";
}
Man.prototype = new Person( 23, "xiaoming" );
这里我们相当于把默认的那个原型给重写了,给参数其实就是给原型添加属性和方法

var xiaoming = new Man();
xiaoming.beard //xxx 这里实例xiaoming自己的属性(小明有胡子)

xiaoming.age //23
xiaoming.name //xiaoming 这两个属性是实例的原型上面的属性(其实这个属性是Person实例的属性,但是现在的原型不就是Person实例吗)

xiaoming.eyes //2 这个属性呢,是Person的原型对象上面的了

这里我们基本上都可以访问到,是不是有点继承的味道了。
如果我们再这样搞一个对象,也这么干,这里是不是就感觉像条链一样。最顶端的对象是Object,也就是说到最后了。我们把这条链接方式叫做原型链。这也是继承的依据。

继承

和传统的OOP语言来说,JavaScript语言比较蛋疼的是它没有类这个机制。所以说我们事先js的继承就从对象角度下手了。我们重点说一下依据原型链继承的。(其他的继承我就不说了,比如借用父对象的构造函数等,实用性不强)
1.上面所说的实现原型链的方法虽然有点继承的味道了,但是你有没有发现 实例化xiaoming这个对象的时候调用了Man这个构造函数,但是xiaoming自己的age和name都没能进行构造,只不过是原型上的属性而已(其实是Person自己构造的,new Person( 23, "xiaoming" ))。我们其实可以这样用call和apply这个object原型下面给我们定义好的方法改进下(call和apply方法自己看api说明吧)

function Man(x, y) {
Person.call(this, x, y); //这里你可以这样理解,this指的是Man,这样其实就是借用Person构造函数
this.beard = "xxx";
}

我们把Man的构造函数这样一改,实例化的时候传参,这样age和name这两个属性就是Man自己构造出来的了,并不会被共享

Man.prototype = new Person( );
Man.prototype.constructor = Man;
var xiaoming = new Man(23, "xiaoming");

这里只是让Man的原型的构造函数变成原有的构造函数,如果不加这一句的话,那么Man原型的构造函数就变成undefied,因为实例和构造函数并没有直接关系。这样一来,原型找不到构造函数,这是非常蛋疼的事情,违反了原型链的定义啊。
这边可能会有人问了,我为什么不自己像胡子beard 那个属性一样直接构造呢。
大哥,我这是举例子,你以为实际的项目中就会有这么两个属性吗。而且这样不正是继承的目的吗
可以少写很多代码啊。(说多了都是泪)
但是也是有缺点的:两次调用父类构造函数(第一次是在创建子类原型的时候,第二次是在子类构造函数内部);子类继承父类的属性,一组在子类实例上,一组在子类原型上(在子类原型上创建不必要的多余的属性,实例上的屏蔽原型上的同名属性,是不是感觉有点多余了 ,效率低。

2.为了改进这种方法,下面说的这种继承方式是借助我们伟大的道爷(这个人很厉害,自行百度)的灵感 。这种就是利用一个空函数对象来做一个桥梁.
具体实现方式如下:

function inherits(Child, Parent) {
    var F = function () {};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
}

另外在子对象的构造函数中别忘了借用父对象的构造函数哦。(就是那个call或者apply方法)

这里和上面的区别是,子对象的原型现在不是父对象的实例了,变成了空函数对象的实例(父对象不用再创建两次了,并且子对象的原型上也不会有啥属性和方法了)。而空函数对象的原型变成了父对象的原型。前面我们说过,有了实例就能找到原型。所以现在子对象原型和父对象原型是就建立关系了。这种方式现在是最稳的方法,也已经被很多框架给写到源码里面了。
这里我们就用google closure 关于继承的两个api,这边简单举个例子:

Child = function( ){
goog.base(this);
this.height = 12;
}
goog.inherits(Child, Parent);

这里就实现了我们上述实现的,不过封装起来了而已。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/91355.html

相关文章

  • 如何理解JavaScript原型原型

    摘要:之前有朋友问怎么去理解原型和原型链的问题。理解原型链的小技巧将箭头视作泛化子类到父类关系那么图中所有的虚线将构成一个继承层级,而实线表示属性引用。原型链是实现继承的重要方式,原型链的形成是真正是靠而非。 之前有朋友问怎么去理解原型和原型链的问题。这个问题,在面试中,很多同学经常都会遇到。这里给大家讲讲,方便大家记忆。 JavaScript的特点JavaScript是一门直译式脚本...

    xuexiangjys 评论0 收藏0
  • 如何理解JavaScript原型原型

    摘要:之前有朋友问怎么去理解原型和原型链的问题。理解原型链的小技巧将箭头视作泛化子类到父类关系那么图中所有的虚线将构成一个继承层级,而实线表示属性引用。原型链是实现继承的重要方式,原型链的形成是真正是靠而非。 之前有朋友问怎么去理解原型和原型链的问题。这个问题,在面试中,很多同学经常都会遇到。这里给大家讲讲,方便大家记忆。 JavaScript的特点JavaScript是一门直译式脚本...

    adie 评论0 收藏0
  • 理解js原型继承

    摘要:相当于在用原型继承编写复杂代码前理解原型继承模型十分重要。同时,还要清楚代码中原型链的长度,并在必要时结束原型链,以避免可能存在的性能问题。 js是一门动态语言,js没有类的概念,ES6 新增了class 关键字,但只是语法糖,JavaScript 仍旧是基于原型。 至于继承,js的继承与java这种传统的继承不一样.js是基于原型链的继承. 在javascript里面,每个对象都有一...

    wthee 评论0 收藏0
  • 彻底理解Javascript原型继承

    摘要:在节中,我们学习到了通过构造函数创建对象的三个重要步骤,其中的一步是把构造函数的对象设置为创建对象的原型。利用而不是直接用创建一个实例对象的目的是,减少一次调用父构造函数的执行。 JavaScript语言不像面向对象的编程语言中有类的概念,所以也就没有类之间直接的继承,JavaScript中只有对象,使用函数模拟类,基于对象之间的原型链来实现继承关系,ES6的语法中新增了class关键...

    ziwenxie 评论0 收藏0
  • 你是否理解jsObject与Function与原型

    摘要:原型对象是由创建的,因此原型对象的构造函数是构造函数也可以是称为对象,原型对象也就继承了其生父构造函数中的数据,也同时继承了原型对象的数据。当然这条原型链中的数据,会被还是还是这类构造函数继承,但是不会被这些继承,他们不处于同一个链条上。 js中,Function的本质是什么?Object的本质又是什么?js中有几条原型链? showImg(https://segmentfault.c...

    itvincent 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<