您好,欢迎访问一九零五行业门户网

javascript中通过原型链实现继承的解析(附代码)

本篇文章给大家带来的内容是关于javascript中通过原型链实现继承的解析(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。
原型和原型链原型prototype,在创建新函数的时候,会自动生成,而prototype中也会有一个constructor,回指创建该prototype的函数对象。
__proto__是对象或者实例中内置的[[prototype]],其指向的是产生该对象的对象的prototype,在浏览器中提供了__proto__让我们可以访问,通过__proto__的指向形成的一个链条,就称做原型链,原型链的整个链路是:实例对象- ->构造函数的prototype- ->object的prototype- ->null。
我们在访问对象的属性或者方法的时候,首先从本对象寻找,如果本对象不存在该属性或者方法时,就会沿着原型链向上寻找,直至找到该属性或者方法,或者到null时停止。
这也解释了为什么数组对象上没有push,pop,shift,unshift等方法,却可以访问
constructorconstructor属性指向的是生成该函数(对象)的函数(对象),例如
var a = function(){};var b = new a();var c = {};var d = [];//以下皆为trueconsole.log(b.constructor === a) //因为实例b是由构造函数产生的console.log(a.constructor === function)//函数a实际是function的实例,同理console.log(c.constructor === object)//空对象c是object的实例console.log(d.constructor === array)//空对象c是object的实例console.log(object.constructor === function)//object自身就是一个构造函数,同理console.log(array.constructor === function)//array自身也是一个构造函数//---------------------------------------------------------------//首先__proto__指向的是产生该对象的对象的prototype,//也即a.prototype,prototype中也的constructor,回指创建该prototype的函数对象,也即函数aconsole.log(b.__proto__.constructor === a)
这里顺便说一下instanceof,a instanceof b 是在 a 的原型链中找 b 的 prototype,找到返回 true,找不到返回 false
//有个奇怪的现象,下面都返回true,这是为什么呢?//因为js中一切都继承自object,除了最顶层的null,//所以在function的原型链中能找到object.prototypeconsole.log(function instanceof object)//而object自身就是一个构造函数,因此在object的原型链中也能找到function.prototypeconsole.log(object instanceof function)
通过原型链实现继承由上面的分析,我们可以利用原型链实现继承的逻辑,继承是面向对象中的一个很重要的概念
function dog(name){    this.name = name;    this.say1 = function(){        console.log(this.name)    }}dog.prototype.say2 = function(){    console.log(this.name)}dog.prototype.test = 1//say本来应该是所有dog实例的共有方法,//如果放在构造函数中,那么就会导致没办法数据共享,每一个实例都有自己的属性和方法的副本,这是对资源的极大浪费//如果放在dog.prototype中,那么利用原型链的特性,就可以让所有实例共用一个方法,//需要注意的是,由于共用了一个方法,对属性的更改是对所有实例透明的var dog1 = new dog('lalala'); let dog2 = new dog('wahaha');dog1.test++;//2dog2.test++;//3console.log(dog1.say1 === dog2.say1)// falseconsole.log(dog1.say2 === dog2.say2)// true//现在,我们可以尝试着去实现继承了//我们是通过原型链去实现继承的,//之前的原型链是:dog实例 --> dog函数 --> object --> null//那么现在的原型链需要改成 dog实例 --> dog函数 --> dog父类(animal函数) --> object --> null//第一种方案,改变dog函数的prototype,让他指向animal的实例function animal(){    this.species = 'unknown';}dog.prototype = new animal();//这里改变后会导致prototype中的constructor改变dog.prototype.constructor = dog;//第二钟方案,改变dog函数的prototype,让他指向animal的prototypefunction animal(){}animal.prototype.species = 'unknown';dog.prototype = animal.prototype;//这里改变后会导致prototype中的constructor改变dog.prototype.constructor = dog;//第三种方案,调用apply或call,将animal的this绑定到dog中function animal(){    this.species = 'unknown';}function dog(name){    animal.apply(this, arguments);    this.name = name;}//第四种方法,通过object.create()方法实现继承,过滤掉了父类实例属性,dog.prototype中就没有了animal的实例化数据了//这种方法也是es6中class被babel编译成es5所用的方法function animal(){    this.species = 'unknown';}function dog(name){    animal.apply(this, arguments);    this.name = name;}//这里模拟了 dog.prototype = object.create(animal.prototype)var f = function(){};f.prototype = animal.pototype;dog.prototype = new f();dog.__proto__ = animal;//这里改变后会导致prototype中的constructor改变dog.prototype.constructor = dog;//现在就能访问到animal中的species属性了var dog = new dog('lalala');dog.species;//unknown
以上这些就是利用原型链实现继承的一些方法
es6的class类有了以上的知识,我们就可以研究一下es6的class类了,这个语法糖能让我们更容易的实现类和继承,其提供了extends,static,super等关键字
//这是es6的代码实现class parent {  static l(){    console.log(222)  }  constructor(m){    this.m = m  }  get(){    return this.m;  }}class child extends parent {  constructor(n){    super(4);    this.n = n;  }  get(){    return this.n  }  set(a){    this.n = a;  }}//这是利用babel编译之后的es5的实现//_createclass是一个自执行函数,作用给构造函数绑定静态方法和动态方法//对于静态的static关键字声明的变量,会直接绑定在函数对象上,作为静态属性(方法)//对于在class中声明的函数方法,则会绑定在构造函数的prototype上,通过object.definepropety方法var _createclass = function () {  function defineproperties(target, props) {    for (var i = 0; i < props.length; i++) {      var descriptor = props[i];      descriptor.enumerable = descriptor.enumerable || false;      descriptor.configurable = true;      if (value in descriptor) descriptor.writable = true;      object.defineproperty(target, descriptor.key, descriptor);    }  }  return function (constructor, protoprops, staticprops) {    if (protoprops) defineproperties(constructor.prototype, protoprops);    if (staticprops) defineproperties(constructor, staticprops);    return constructor;  };}();//如果父函数没有返回值或者返回值不为object或者function,则返回子类的thisfunction _possibleconstructorreturn(self, call) {  if (!self) {    throw new referenceerror(this hasn't been initialised - super() hasn't been called);  }  return call && (typeof call === object || typeof call === function) ? call : self;}//_inherits就是extends关键字发挥的作用,实现了继承的功能。利用&&的短路特性,对superclass做了容错性处理,然后将子类object.create()传了两个参数,一个参数是父类superclass.prototype,作用在上面解释继承的方法时讲过了,第二个参数是一个键值对,key代表着属性,value则和object.definepropety中descriptor一样,这里改变constructor的目的,也在解释继承时讲过了,最后将subclass.__proto__指向superclassfunction _inherits(subclass, superclass) {  //...省略  subclass.prototype = object.create(superclass && superclass.prototype, {    constructor: {      value: subclass,      enumerable: false,      writable: true,      configurable: true    }  });  if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass;}//_classcallcheck是保证构造函数不能被当成普通函数调用,需要用new关键字function _classcallcheck(instance, constructor) {  if (!(instance instanceof constructor)) {    throw new typeerror(cannot call a class as a function);  }}var parent = function () {  _createclass(parent, null, [{    key: l,    value: function l() {      console.log(222);    }  }]);  function parent(m) {    _classcallcheck(this, parent);    this.m = m;  }  _createclass(parent, [{    key: get,    value: function get() {      return this.m;    }  }]);  return parent;}();var child = function (_parent) {  _inherits(child, _parent);  function child(n) {    _classcallcheck(this, child);        //由于在_inherits中将subclass(child).__proto__指向了superclass(parent),所以这里即是parent.call(this,4),即这里执行的是super函数,super也可以调用父类的静态方法,    //如果父函数没有返回值或者返回值不为object或者function,则返回子类的this        var _this = _possibleconstructorreturn(this, (child.__proto__ || object.getprototypeof(child)).call(this, 4));    _this.n = n;    return _this;  }  _createclass(child, [{    key: set,    value: function set(a) {      this.n = a;    }  }]);  return child;}(parent);
总结通过以上分析,对原型和原型链有了更加深入和清晰的了解,也熟悉了constructor和instanceof的用法,加深了基于原型链的继承方式的了解,理清了这块知识。
在对es6的class通过babel编译后的源码的分析中,也了解到了object.create和object.setprototypeof的用法,挖掘了如何去模拟super,extends和static的实现。
相关推荐:
javascript面向对象-基于原型链实现继承
javascript的继承与原型链
以上就是javascript中通过原型链实现继承的解析(附代码)的详细内容。
其它类似信息

推荐信息