博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript原型、原型链和继承
阅读量:7024 次
发布时间:2019-06-28

本文共 4186 字,大约阅读时间需要 13 分钟。

  hot3.png

##背景 这两天在看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);  //trueconsole.log(A.prototype.__proto__ === Object.prototype); //trueconsole.log(Object.prototype.__proto__ === null);  //true

这个就是原型链了

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

function A() {    this.a = 'a';}A.prototype.sayHello = function(){	console.log("Hello");}function B() {    this.b = 'b';}// B继承了AB.prototype = new A();B.prototype.sayBye = function(){	console.log("Bye");}// 实例化Bvar b = new B();console.log(b.a); //aconsole.log(b.b); //bb.sayHello(); //Hellob.sayBye(); //Byeconsole.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

//我们打印原型里面的colorconsole.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);  //dongconsole.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();    //donginstance1.sayAge();      //29var instance2 = new SubType('ting',27);console.log(instance2.color);  //["red", "blue", "green"]instance2.sayName();           //tinginstance2.sayAge();            //27

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

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

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

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

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

参考博文

转载于:https://my.oschina.net/gcdong/blog/1094047

你可能感兴趣的文章
有关位运算的基础知识和应用
查看>>
框架dubbox的简单使用
查看>>
codevs1163访问艺术馆 树形dp
查看>>
java获取登陆用户的IP地址
查看>>
JAVA线程控制
查看>>
Java关键字final、static使用总结
查看>>
转载-Objective-C内存管理详解(含示例代码)
查看>>
uchome中模糊搜索的实现
查看>>
深入理解MVC原理
查看>>
LCD之mipi DSI接口驱动调试流程【转】
查看>>
内核中dump_stack()的实现,并在用户态模拟dump_stack()【转】
查看>>
五子棋AI的思路
查看>>
AtomicInteger和count++的比较
查看>>
为乐趣而生----禁止网页右键、复制、另存为方法
查看>>
JS删除数组条目中重复的条目
查看>>
jQuery数组处理详解(转)
查看>>
hdu1412
查看>>
后仿真笔记 - ise 联合 modelsim
查看>>
python @property
查看>>
XCOJ 1168 (搜索+期望+高斯消元法)
查看>>