面向对象的三大特性是:封装、继承、多态。其中继承是最难理解的,也是最重要的部分。 JS中本身没有专门继承的语法,它是使用各种代码的模拟来实现的。即使ES6有了正真的继承语法,其本质也是ES5中继承的语法糖。目前ES5继承最被人津津乐道的就是尼古拉斯的著名书籍《JavaScript高级程序设计》中记录的6中方法。本文也是摘自这本本书的这部分的核心内容,并整理给大家呈现出来。
lufei已经拥有父类的方法,说明继承成功了。上面最重要的一行代码是第14行,印证了子类的原型指向父类的实例。原型继承其实就是利用原型链来实现的,如果在子类中没有找到某个属性和方法就会去子类的原型中去找,如果父类的实例没有又会去父类的原型去找,直到找到Object的原型为止。
 原型继承是最简单最长用的一种继承方式,但是它有自己的缺点:
  缺点1:父类中引用类型的属性,会被子类共享。
 如上例中的hobbies属性,每个子类的实例都指向了同一个hobbies属性。如果某个子类不重写hobbies并且给他添加了一个值,那么所有的没有重写hobbies的子类的这个值都将会改变(同一个对象)。
缺点2:创建子类的时候,无法调用父元素的构造函数。
 如上例中的this.name = name;在父类中已有相同的代码无法做到复用。
 
 lufei和nami都拥有了父类的属性,所以继承成功。我们可以看到子类可以调用父类的构造方法,同时父类的引用属性也不再共享。
 这种方法的缺点:
  缺点1:父类原型中的属性和方法无法继承。
缺点2:对每个子类对象来说,父类中的函数属性都是不同的函数,代码无法复用。
 
 lufei和nami都拥有了父类的属性,所以继承成功。组合继承是最常用的继承方式之一,但是我们可以看到子类可以调用父类的构造方法,同时父类的引用属性也不再共享。
  缺点:调用了两次父类构造函数,比较消耗内存。
 一次在第10行,一次再第14行。
 
 lufei拥有了父类的方法,继承成功。但是我们每次得自己写一个类似于上面的object方法。ES5考虑到这个问题,把这个方法规范化了,就是大名鼎鼎的Object.create()方法,其本质就是上面的object函数。这个函数接受2个参数,一个是要复制的对象,一个是Object.defineProperties()函数第二个参数相同的结构。所以上面第13行和第14行可以改写为:
 var lufei = Object.create(person,{     name : {//这个对象是属性描述符里面那样的对象         value:"路飞"     } });  这种方式比较方便,它跳过了创建子类这一步,直接创建了子类对象。
  缺点1:子类自己独特的属性或方法,是无法复用的。
缺点2:没有子类的概念,直接创建了子类对象。
 
 Object.create了,你可以理解成原型式继承里面的object函数:
 var person = {     name: "人",     sayName: function (){         console.log("我是:" + this.name);     } };  function createObject(obj){// 创建子类对象一个方法     var newObj = Object.create(obj);// 原型式继承     newObj.sayHello = function (){ // 这里给每个子对象添加方法         console.log("大家好!!!")     }     // ... 这里可以添加其他的属性或方法     return newObj; }  var lufei = createObject(person); lufei.name = "路飞"; lufei.sayName();// 我是:路飞 lufei.sayHello();// 大家好!!!  var nami = createObject(person); nami.name = "娜美"; nami.sayName();// 我是:娜美 nami.sayHello();// 大家好!!!  由上可知,子类的对象lufei和nami即拥有了父类的方法也拥有了子类自己独特的方法sayHello,继承成功。但是它也是直接创建了子对象的。
  缺点:没有子类的概念,直接创建了子类对象。