文档章节

JavaScript原型、原型链和继承

栋栋也疯狂
 栋栋也疯狂
发布于 2017/07/01 16:10
字数 1639
阅读 14
收藏 0

##背景 这两天在看JavaScript高级程序设计一书,看到了原型的一章,看得我是云里雾里,然后再在网上看了一些博文,算是对这个有一点了解 ##原型和原型链 javascript(下面简称js),在每定义一个function的时候,都会有一个prototype的属性,是一个默认属性,这个东西就是原型,那么这个原型有什么用呢,这个原型里面有一个constructor属性,这个属性值回到方法本身 这里写图片描述 那么当我们在实例化这个方法的时候,实例对象就会有一个__proto__的属性,这个属性是指回到构造函数本身的原型的。具体看下面的代码

function A(){}
var a = new A();
console.log(a.__proto__ === A.prototype); //这里是TRUE的

这就是简单的原型

那么什么是原型链呢,这里有一个需要说明的是,所有的原型其实都是基于Object的

function A(){}
var a = new A();
console.log(a.__proto__ === A.prototype);  //true
console.log(A.prototype.__proto__ === Object.prototype); //true
console.log(Object.prototype.__proto__ === null);  //true

这个就是原型链了

##继承 那么,知道了原型和原型链以后,可以做什么呢,继承,先看一个简单的例子


function A() {
    this.a = 'a';
}
A.prototype.sayHello = function(){
	console.log("Hello");
}
function B() {
    this.b = 'b';
}
// B继承了A
B.prototype = new A();

B.prototype.sayBye = function(){
	console.log("Bye");
}
// 实例化B
var b = new B();
console.log(b.a); //a
console.log(b.b); //b
b.sayHello(); //Hello
b.sayBye(); //Bye
console.log(b);

这里写图片描述

我们首先定义了一个A构造函数里面有属性a='a',再定义个B构造函数,里面有属性b='b',然后我们把A实例赋给了B的prototype,我们前面说过,一个函数的prototype里面有什么,有constructor这个属性,这个属性是正常是指回到函数本身的,这样我们实例化这个函数的时候,才可以得到里面的属性,那么如果我们把它的值改为另外一个函数的话,会发生什么事情,当我们在实例化这个新的构造函数的时候,不止可以得到使用本来的属性,也可以使用它继承得来的属性。

但是这里有一个需要注意的是,继承得来的属性是放在原型里面的,一旦我们定义一个和原型属性一样的属性,那么,我们去使用这个属性的时候,就会先找实例的属性,没有才去找原型的属性

注意 原型链虽然很强大,可以用它来实现继承,但它也存在一些问题

function SuperType() {
    this.color = ["red", "blue", "green"];
}
function SubType(){}

// 继承
SubType.prototype = new SuperType();

var instance1 = new SubType();
instance1.color.push("black");
console.log(instance1.color);//"red,blue,green,black"

var instance2 = new SubType();
console.log(instance2.color);//"red,blue,green,black"

从上面的代码我们可以看到,我们首先定义了一个构造函数SuperType,里面有一个color的属性,我们再用一个SubType的构造函数继承了它。这个时候我们去实例化SubType,得到instance1,并且给他的color属性push一个值,这个时候我们打印这个color得到一个值,是原来的加上push进去的,这没问题,下面我们再实例化一个instance2,这次我们不做任何操作,打印他的color,问题就来了,出来的结果和上面的color一样,但是我明明没有对instance2的color进行过任何操作啊,这是为什么呢。

原因很简单,因为我们在操作instance1.color.push的时候,我们去找实例的属性,发现没有这个color,我们往上面找,在原型里面找到了它,然后再往里面push了一个black,这个时候,这个原型已经被改变了,那么这个时候,我们去打印同样是继承这个对象的instance2的color的时候,自然也会多了这个black。再看下面这段代码


function SuperType() {  
    this.color = ["red", "blue", "green"];
}
function SubType(){}

// 继承
SubType.prototype = new SuperType();

var instance1 = new SubType();  
instance1.color = ["black"];
console.log(instance1.color);//"black"

var instance2 = new SubType();  
console.log(instance2.color);//"red,blue,green"

和上面的代码差不多,但是为什么,两次的结果这次反而不一样了呢,因为这次使用的是赋值语句,赋值有什么不一样呢,赋值就是,我直接找到当前函数里面的属性来赋值,并不会找原型里面的属性来赋值,我们可以打印出来看一下

接上面的代码

console.log(instance1);

可以看到,在实例的对象里面有一个color,而在原型里面也有一个color

//我们打印原型里面的color
console.log(instance1.__proto__.color); //"red,blue,green"

这种继承还有另外一个问题,无法对于父类传参

这个时候我们可以使用一种叫借用构造函数的方法

// 父类
function SuperType(name) {
    this.name = name;
}
// 子类
function SubType(){
    // 继承
    SuperType.call(this,"dong");

    this.age = 29;
}


var instance = new SubType();
console.log(instance.name);  //dong
console.log(instance.age);  //29

但是这种也会引发一个问题,就是父类的原型方法子类没办法调用

优化以后的代码


function SuperType(name) {
    this.name = name;
    this.color = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
    console.log(this.name);
}


// 子类
function SubType(name, age) {
    // 继承属性
    SuperType.call(this, name);

    this.age = age;
}

SubType.prototype = new SuperType();
SubType.prototype.sayAge = function() {
    console.log(this.age);
}
SubType.prototype.constructor = SubType;

var instance1 = new SubType('dong',29);
instance1.color.push("black");
console.log(instance1.color);//["red", "blue", "green", "black"]
instance1.sayName();    //dong
instance1.sayAge();      //29

var instance2 = new SubType('ting',27);
console.log(instance2.color);  //["red", "blue", "green"]
instance2.sayName();           //ting
instance2.sayAge();            //27

这里是借用函数和原型一起使用,还是比较复杂的,需要注意的几点 ######1.我们的子类里面,需要使用call来对父类进行一次调用,这样就可以把参数传到父类去了 ######2.在继承完了以后,我们需要对子类的原型做一次修正,SubType.prototype.constructor = SubType,把它重新指向本身

这样的话,我们既可以对于父类传参,也可以对于示例的属性操作,不用担心影响到原型的属性了

接上面的代码
console.log(instance1);
console.log(instance2);

可以看到分别的属性,在实例的属性里面有color,在原型的属性里面也在color,也就是说,把父类的属性在子类里面全部都实现了一遍,但是原型的方法还是放在原型里面

##后记 到此,对于原型、原型链、继承算是有一个初步的认识,对于js来,这个原型的理解是很关键的一个事情,所以特意把思路理了一次,写了这个博文

参考博文

http://www.cnblogs.com/Yirannnnnn/p/4896542.html http://www.108js.com/article/article1/10201.html?id=1092

© 著作权归作者所有

栋栋也疯狂
粉丝 1
博文 32
码字总数 27170
作品 0
广州
私信 提问
简单理解JavaScript原型链

简单三连 什么是原型 ? 我是这样理解的:每一个JavaScript对象在创建的时候就会与之关联另外一个特殊的对象,这个对象就是我们常说的原型对象,每一个对象都会从原型“继承”属性和方法。 什么...

森林小猎人
05/07
0
0
图解javascript原型链

作者: HerryLo 本文永久有效链接: https://github.com/AttemptWeb...... 原型链和原型对象是js的核心,js以原型链的形式,保证函数或对象中的方法、属性可以让向下传递,按照面向对象的说法,...

HerryLo
09/06
0
0
前端基本功(七):javascript中的继承(原型、原型链、继承的实现方式)

1. js的继承机制 javascirpt没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instance)的区分,全靠一种很奇特的"原型链"(prototype chain)模式,来实现继承。继承意味着复制操作......

大家都叫我四姨
06/18
0
0
用通俗易懂的语言介绍JavaScript原型

原型(prototype)是每个JavaScript开发人员必须理解的基本概念,本文的目标是通俗而又详细地解释JavaScript的原型。如果你读完这篇博文以后还是不理解JavaScript的原型,请将你的问题写在下...

gsbhzh
2014/10/29
191
0
如何理解JavaScript的原型和原型链?

之前有朋友在公众号给我留言,问问怎么去理解原型和原型链的问题。这个问题,在面试中,很多同学经常都会遇到。 回复多了,觉得大家对这块知识点理解还是不够深。于是决定今天来给大家讲讲,...

WEB开发阿靖
2018/12/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

JIT编程与方法内联

JIT的比较冷门,首先你要读一下这两篇 帖子: 《面向JIT编程-方法内联》 https://blog.csdn.net/u012834750/article/details/79488572 《浅谈对JIT编译器的理解》 https://www.cnblogs.com/...

爱吃窝窝头
19分钟前
3
0
基于TCP的RPC实现

RPC即远程服务调用 出现原因:随着项目越来越大,访问量越来越大,为了突破性能瓶颈,需要将项目拆分成多个部分,这样比起传统的项目都是本地内存调用,分布式的项目之间需要在网络间进行通信...

少年已不再年少
29分钟前
5
0
OSChina 周二乱弹 —— 他只能用这个办法劝你注意身体了

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @-冰冰棒- :#今日歌曲推荐# Kodaline《High Hopes》 《High Hopes》- Kodaline 手机党少年们想听歌,请使劲儿戳(这里) @xiaoshiyue :仙女...

小小编辑
50分钟前
1K
21
Spring Boot Actuator 整合 Prometheus

简介 Spring Boot 自带监控功能 Actuator,可以帮助实现对程序内部运行情况监控,比如监控状况、Bean加载情况、环境变量、日志信息、线程信息等。这一节结合 Prometheus 、Grafana 来更加直观...

程序员果果
59分钟前
11
0
Linux文件查找命令详解

对于文件查找,我们最好用的还是属于find命令了,在说find命令之前,先把另外几个查找命令介绍一下。 目录 0x01 查询命令介绍 0x02 find命令介绍 0x01 查询命令介绍 在介绍之前,首先先了解一...

无心的梦呓
59分钟前
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部