TBLEG
扫描微信账号

扫一扫微信二维码

深入浅出JavaScript之原型链和继承

2020-05-16 信息
区块链白皮书代写

Javascript语言继承机制,它没有”子类”和”父类”概念,也没有”类”(class)和”实例”(instance)区分,全靠一种很奇特”原型链”(prototype chain)模式,来实现继承。

这部分知识也是JavaScript里核心重点之一,同时也是一个难点。我把学习笔记整理了一下,方便大家学习,同时自己也加深印象。这部分代码细节很多,需要反复推敲。那我们就开始吧。

小试身手

原型链例子(要点写在注释里,可以把代码复制到浏览器里测试,下同)

function foo(){}              //通过function foo(){}定义一个函数对象 foo.prototype.z = 3;          //函数默认带个prototype对象属性   (typeof foo.prototype;//"object")  var obj =new foo();           //我们通过new foo()构造器方式构造了一个新对象 obj.y = 2;                    //通过赋值添加两个属性给obj obj.x = 1;                    //通过这种方式构造对象,对象原型会指向构造函数prototype属性,也就是foo.prototype  obj.x; // 1                 //当访问obj.x时,发现obj上有x属性,所以返回1 obj.y; // 2                 //当访问obj.y时,发现obj上有y属性,所以返回2 obj.z; // 3                 //当访问obj.z时,发现obj上没有z属性,那怎么办呢?它不会停止查找,它会查找它原型,也就是foo.prototype,这时找到z了,所以返回3  //我们用字面量创建对象或者函数默认prototype对象,实际上它也是有原型,它原型指向Object.prototype,然后Object.prototype也是有原型,它原型指向null。                                    //那这里Object.prototype有什么作用呢? typeof obj.toString; // ‘function'    //我们发现typeof obj.toString是一个函数,但是不管在对象上还是对象原型上都没有toString方法,因为在它原型链末端null之前都有个Object.prototype方法, //而toString正是Object.prototype上面方法。这也解释了为什么JS基本上所有对象都有toString方法 'z' in obj; // true               //obj.z是从foo.prototype继承而来,所以'z' in obj返回了true obj.hasOwnProperty('z'); // false   //但是obj.hasOwnProperty('z')返回了false,表示z不是obj直接对象上,而是对象原型链上面属性。(hsaOwnProperty也是Object.prototype上方法) 

刚才我们访问x,y和z,分别通过原型链去查找,我们可以知道:当我们访问对象某属性时,而该对象上没有相应属性时,那么它会通过原型链向上查找,一直找到null还没有话,就会返回undefined。

基于原型继承

function Foo(){    this.y = 2;      }  Foo.prototype.x = 1; var obj3 = new Foo();  //①当使用new去调用时候,函数会作为构造器去调用②this会指向一个对象(这里是obj3),而这个对象原型会指向构造器prototype属性(这里是Foo.prototype) obj3.y; //2  obj3.x; //1    //可以看到y是对象上,x是原型链上原型(也就是Foo.prototype上) 

prototype属性与原型

我们再来看看Foo.prototype是什么样结构,当我们用函数声明去创建一个空函数时候,那么这个函数就有个prototype属性,并且它默认有两个属性,constructor和__proto__,

constructor属性会指向它本身Foo,__proto__是在chrome中暴露(不是一个标准属性,知道就行),那么Foo.prototype原型会指向Object.prototype。因此Object.prototype上

一些方法toString,valueOf才会被每个一般对象所使用。

function Foo(){} typeof Foo.prototype; // "object" Foo.prototype.x = 1; var obj3 = new Foo(); 

总结一下:我们这里有个Foo函数,这个函数有个prototype对象属性,它作用就是当使用new Foo()去构造实例时候,这个构造器prototype属性会用作new出来这些对象原型。

所以我们要搞清楚,prototype和原型是两回事,prototype是函数对象上预设属性,原型通常是构造器上prototype属性。

实现一个class继承另外一个class

function Person(name, age) {    this.name = name;    //直接调用话,this指向全局对象(this知识点整理)    this.age = age;      //使用new调用Peoson话,this会指向原型为Person.prototype空对象,通过this.name给空对象赋值,最后this作为return值 }  Person.prototype.hi = function() {   //通过Person.prototype.hi创建所有Person实例共享方法,(可以参考上节左图:对象原型会指向构造器prototype属性,所以想让obj1,obj2,obj3共享一些方法话,只需在原型对象上一次性地添加属性和方法就可以了);    console.log('Hi, my name is ' + this.name + ',I am ' + this.age + ' years old now.')//这里this是全局对象 };  Person.prototype.LEGS_NUM = 2;   //再设置一些对Person类所有实例共享数据 Person.prototype.ARMS_NUM = 2; Person.prototype.walk = function() {   console.log(this.name + ' is walking...'); };  function Student(name, age, className) {  //每个学生都属于人   Person.call(this, name, age);  //在Student这个子类里面先调用一下父类   this.className = className; }  //下一步就是我们怎么去把Student实例继承Person.prototype一些方法  Student.prototype = Object.create(Person.prototype);    //Object.create():创建一个空对象,并且这个对象原型指向它参数  //这样子我们可以在访问Student.prototype时候可以向上查找到Person.prototype,又可以在不影响P
                      
全文阅读
文章关键词
函数
class
javascript
Create
prototype
扫描关注微信账号

试试长按二维码加关注