JavaScript继承
一直对JS的继承概念有点模糊, 大体知道是怎么回事, 但也没有去深究过, 今天翻阅【JavaScript语言精髓】一书的第五章比较深刻进行认知, 特此记录一番。
构造一个伪类, 继承Person
JavaScript是一门基于原型的语言, 其对象是直接从其他对象继承的
伪类
当我们构造一个函数对象时, 会默认生成一个constructor属性, 其值就是自身var Person = function(name){ this.name = name;}Person.prototype.whoAmI = function(){ console.info(this.name);}
构造一个伪类, 继承Personvar Student = function(grade){ this.grade = grade;}Student.prototype = new Person('haolin'); 但这些伪类操作会让人觉得怪异, 我们需要隐藏这些prototype, 这是书中使用的通用代码片段Function.prototype.method = function(name, func){ this.prototype[name] = func; return this;} 上述代码片段, 为Function.prototype增加一个method方法,这样我们就可以通过String.method("newMethod", function(){...})(而不是String.prototype.newMethod = function(){...})来为String扩展新方法了。
于是我们也可以扩展一个方法, 用于继承:Function.method("extends", function(Parent){ this.prototype = new Parent; return this;}); 那么可以通过这样的来进行继承var Student = function(grade){ this.grade = grade;}.extends(Person); 现在我们基本达到了继承的目的, 但是也存在一些问题, 比如父类属性能公开访问, 在继承时需要加上new关键字等。
函数化构造器
我们将不使用new关键字, 进行对象构造, 基本分为四个步骤var constructor = function(spec, my){ var that, 其他私有实例变量 my = my || {}; 把共享的变量和函数添加到my中 that = 一个新对象 添加给that访问私有属性的方法 return that;} 按照这个原则, 我们试着重新构造之前的继承关系: var person = function(context){ var that = {}; var whoAmI = function(){ return context.name; }; that.whoAmI = whoAmI; var howOld = function(){ return context.age || 0; }; that.howOld = howOld; return that;}var p2 = person({"name" : "haolin", "age" : 24}); 之前通过伪类进行继承, 我们需要重复构造器Person已经完成的工作, 而通过函数化构造则不用关心父类构造, 只需调用父类构造即可var student = function(context){ var number = context.number || ""; // 调用父类构造方法, 并能访问父类暴露的接口whoAmI, howOld var that = person(context); // 子类扩展方法 var getNumber = function(){ return number; } that.getNumber = getNumber; var selfIntroduce = function(){ return "I am " + that.whoAmI() + ", I'm " + that.howOld() + " years old, My number is " + number; } that.selfIntroduce = selfIntroduce; return that;}var s2 = student({"name" : "haolin", "age" : 24, "number" : "123456"}); 现在, 我们就能直接调用父类方法, 并且防止了父类私有属性被直接访问。CoffeeScript中的类继承
现在的前端项目都使用CoffeeScript, 其支持类和继承, 想看看它是怎么理解JS的类和继承的。
class Person constructor: (@name, @age) ->getName: -> console.info @nameclass Student extends Person constructor: (@number) ->getNumber: -> console.info @number 编译后的JS为var Person, Student, __hasProp = {}.hasOwnProperty,__extends = function(child, parent) { //扩展函数 for (var key in parent) { if (__hasProp.call(parent, key)) //赋值父类属性 child[key] = parent[key]; } function ctor() { //子类构造函数 this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; //父类标识 return child;};Person = (function() { //使用闭包, 保护属性 function Person(name, age) { this.name = name; this.age = age; } Person.prototype.getName = function() { return console.info(this.name); }; return Person;})(); //发起一次调用Student = (function(_super) { __extends(Student, _super); function Student(number) { this.number = number; } Student.prototype.getNumber = function() { return console.info(this.number); }; return Student;