小谈js原型链和继承

原型(prototype)在js中可是担当着举足轻重的作用,原型的实现则是在原型链的基础上,理解原型链的原理后,对原型的使用会更加自如,也能体会到js语言的魅力。

本文章会涉及的内容

  • 原型及原型对象
  • 原型链(JavaScript核心部分)
  • 类的继承
  • instanceof
  • constructor

我们先用一个构造器来实现一个构造函数:

function A(){
    this.mark = "A";
    this.changeMark = function(){
        this.mark += "_changed";
    }
}

A.prototype.mark2 = "A2";
A.prototype.changeMark2 = function(){
    this.mark2 += "_changed";
}

var a = new A();
var a2 = new A();

//下面则说明构造函数实例化后,分配着不同的实例对象,互不相关
console.log(a.mark);  //"A"
console.log(a2.mark); //"A"
    a.changeMark();   //使用实例对象中的方法
console.log(a.mark);  //"A_changed"
console.log(a2.mark); //"A"

//下面则说明了new操作符的一项作用,即将原型中的this指向当前对象,
//在a.changeMark2执行时,changMark2中的方法先找 this.mark2 的值,
//但是实例对象this中没有mark2值,则在原型链(后面会介绍)向上寻找,得到A原型对象中的mark2值,
//在赋值时,将修改后的值添加在了a实例中。
//总:虽然调用的是prototype方法,但是不会对prototype属性做修改,只会说是在实例中新增属性,但是在使用时,会最使用最近得到的属性(在后面原型链中可以加以理解)
console.log(a.mark2);  //"A2"
console.log(a2.mark2); //"A2"
    a.changeMark2();   //使用原型链中的方法
console.log(a.mark2);  //"A2_changed"
console.log(a2.mark2); //"A2"

为什么a可以使原型中的changeMark2方法?这就和js巧妙的原型链相关,在Firefox中我们可以打印出对象并可查看到对象下面的__proto__。

我们把上面的过程用流程图来表示:

只有构造函数才会有prototype属性,而实例化出来的对象会拥有__proto__,而不会有prototype。

就像上图画的那样,两个实例化的对象都通过__proto__属性指向了A.prototype(即构造函数的原型对象)

而原型对象的__proto__指向Object对象,就像a.toString()的toString方法就是存在于Object原型对象(Object.prototype)中。

so:当使用对象的方法或属性时,对象会在一步一步通过__proto__向上寻找,找到最近的则是最终的获取到的方法或属性。

  ————这就是js中的原型链。

就像图上看到的一样,所有对象的原型链最终都指向了Object对象,而Object的原型对象(Object.prototype)是为数不多的不继承自任何属性的对象,即Object.prototype没有__proto__,是原型链的顶峰。

通过上面我们可以了解到,当我们对A.prototype或Object.prototype添加属性或方法时,在a和a2实例中都会查看到该属性或方法,因为这两个实例都通过原型链与A和Object的原型对象相连。

 再来看看原型对象和原型链在继承方面的实现:

再构造一个函数A和一个函数B,并让B继承A,如下:

function A(mark){
    this.mark = mark;
}
A.prototype.getMark = function(){
    return this.mark;
}

function B(mark){
  this.mark = mark
}

//var temp = new A("A");
//B.prototype = temp;
//上面语句和下语句作用相同

B.prototype = new A("A"); //实例化一个A,其赋值于B.prototype                //我们知道了原型链,这样做就是将B的原型对象与A的原型对象通过原型链(__proto__)连接起来                //以实现继承

var b = new B("B");

console.log(b.mark); //B, 结果如上面原型链分析的那样,向上找到最近的属性,则为b实例中的mark:"B"

其中的结构示意大概如下图:

这时我们可以看到,在B.prototype中是没有constructor的,因为B.prototype只是简单的new A("A")对象赋值的结果。

在js中的constructor有什么作用呢?如:

var arr = new Array();
arr instanceof Array;      //true
arr.constructor === Array; //true

function TEMP(){
}
var temp = new TEMP();
temp instanceof TEMP;      //true
temp.constructor === TEMP; //true

引用《JavaScript权威指南》中的对于constructor的解释为:对象通常继承的constructor均指代它们的构造函数,而构造函数是类的“公共标识”。即constructor可用来判断对象所属的类。

 

在上面的小例子中,用instanceof也可判断对象的类,但是有自身的缺陷,instanceof的实现方法为:

instanceof不会去检查temp是不是由TEMP()构造函数初始化的,面是判断temp是否继承自TEMP.prototype,这样,范围就宽了很多。

如在上面的大例中,使用

b instaceof B //true 因为在b的原型链中可以找到B.prototype对象

b instaceof A //true 在b的原型链中也可以找到A.prototype对象

可以说instanceof是用来检测继承关系的。

而当

console.log(b.constructor) //function A()
//因为在b的原型链中,最近的constructor就是A.prototype中有constructor指向了构造函数A();

但我们知道的b是属于B类的,那最后所以要做的就是:

B.prototype.constructor = B; //将constructor指向自身的构造函数

var new_b = new B("B");
console.log(new_b.constructor) //function B() 

这样,一个完整的类继承才完成了。

最后附上一个完整继承后的结果图:

第一次写长文,如有问题,还请大家指出。

转载请注明出处,谢谢。

Finish.

时间: 2024-10-08 09:47:53

小谈js原型链和继承的相关文章

浅谈js原型链与继承

js原型链与继承是js中的重点,所以我们通过以下三个例子来进行详细的讲解. 首先定义一个对象obj,该对象的原型为obj._proto_,我们可以用ES5中的getPrototypeOf这一方法来查询obj的原型,我们通过判断obj的原型是否与Object.prototype相等来证明是否存在obj的原型,答案返回true,所以存在.然后我们定义一个函数foo(),任何一个函数都有它的prototype对象,即函数的原型,我们可以在函数的原型上添加任意属性,之后通过new一个实例化的对象可以共享

深入理解JS原型链与继承

我 觉得阅读精彩的文章是提升自己最快的方法,而且我发现人在不同阶段看待同样的东西都会有不同的收获,有一天你看到一本好书或者好的文章,请记得收藏起来, 隔断时间再去看看,我想应该会有很大的收获.其实今天要讨论的主题,有许多人写过许多精彩的文章,但是今天我还是想把自己的理解的知识记录下来.我在学习 掌握JS原型链和继承的时候,就是看得@阮一峰老师的写的文章,觉得他写的技术类的文章都容易让理解,简明概要,又好理解.他是我学习JS路程里面一个比较佩服的导师,昨天重新看了他写的<Javascript 面向

js原型链与继承(初体验)

js原型链与继承是js中的重点,所以我们通过以下三个例子来进行详细的讲解. 首先定义一个对象obj,该对象的原型为obj._proto_,我们可以用ES5中的getPrototypeOf这一方法来查询obj的原型,我们通过判断obj的原型是否与Object.prototype相等来证明是否存在obj的原型,答案返回true,所以存在.然后我们定义一个函数foo(),任何一个函数都有它的prototype对象,即函数的原型,我们可以在函数的原型上添加任意属性,之后通过new一个实例化的对象可以共享

js 原型链和继承(转)

在理解继承之前,需要知道 js 的三个东西: 什么是 JS 原型链 this 的值到底是什么 JS 的 new 到底是干什么的 1. 什么是 JS 原型链? 我们知道 JS 有对象,比如 var obj = { name: "obj" }; 我们通过控制台把 obj 打印出来: 我们会发现 obj 已经有几个属性(方法)了.那么问题来了:valueOf / toString / constructor 是怎么来?我们并没有给 obj.valueOf 赋值呀. 上面这个图有点难懂,我手画

js原型链与继承

先看看JAVA中继承的定义 :Java继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类. 所以继承需要实现的是:能够拥有父类的方法和属性,也能自己定义新的方法和属性; 那么直接用原型链会有什么问题? //定义一个CarModel类 function CarModel(c){ this.color=c||"白色"; this.getColor=function(){ console.log('我的颜色是'+

对js原型链及继承的理解:__proto__&amp;prototpye

首先我们来理解一下原型链的概念: 要理解原型链必须知道构造函数.原型和实例的关系: 每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针(即prototype),而实例则包含一个指向原型对象的内部指针(即__proto__). var father = function() { this.relation = "father"; } father.prototype.money = function() { this.money = 100000; } var father

Js基础知识(二) - 原型链与继承精彩的讲解

作用域.原型链.继承与闭包详解 注意:本章讲的是在es6之前的原型链与继承.es6引入了类的概念,只是在写法上有所不同,原理是一样的. 几个面试常问的几个问题,你是否知道 instanceof的原理 如何准确判断变量的类型 如何写一个原型链继承的例子 描述new一个对象的过程 也许有些同学知道这几个问题的答案,就会觉得很小儿科,如果你还不知道这几个问题的答案或者背后所涉及到的知识点,那就好好看完下文,想必对你会有帮助.先不说答案,下面先分析一下涉及到的知识点. 什么是构造函数 JavaScrip

JS原型链与几种继承方法的对比

继承的方式有两种:接口继承.实现继承接口继承:即虚函数,父类只定义接口,不具体实现子类继承接口,自己负责实现这个方法,运行时动态决定调用哪个实现.实现继承:父类实现的方法,子类可以直接调用 JS中只支持实现继承,以原型链来实现. 回顾一下构造函数.原型.实例的关系:每个构造函数都有一个原型对象,原型对象又都包含一个constructor指针指向构造函数,实例包含一个_proto_内部属性指向原型对象. 继承的实现方法(父类型叫Parent,子类型叫Child)原本Child.prototype

Js中的对象、构造函数、原型、原型链及继承

1.对象 在传统的面向过程的程序设计中,会造成函数或变量的冗余.而JS中对象的目的是将所有的具有相同属性或行为的代码整合到一起,形成一个集合,这样就会方便我们管理,例如: var person1={    name:"tan",    age:26,    showMessage:function(){        alert("name:"+this.name);    }};person.showMessage();//输出name:tan 以上的例子将nam