JavaScript 继承详解(五)

标签:新闻动态    日期:2017-11-01 11:39    录入:汇盛国际平台    浏览:

  

[JavaScript,继承]JavaScript 继承详解(五)

  

在本章中,我们将分析John Resig关于JavaScript继承的一个实现 - Simple JavaScript Inheritance。

  
  John Resig作为jQuery的创始人而声名在外。是《Pro JavaScript Techniques》的作者,而且Resig将会在今年秋天推出一本书《JavaScript Secrets》,非常期待。

  

  

调用方式  
  调用方式非常优雅:  
  注意:代码中的Class、extend、_super都是自定义的对象,我们会在后面的代码分析中详解。

  

  
  
  var Person = Class.extend({  // init是构造函数  init: function(name) {  this.name = name;  },  getName: function() {  return this.name;  }  });  // Employee类从Person类继承  var Employee = Person.extend({  // init是构造函数  init: function(name, employeeID) {  // 在构造函数中调用父类的构造函数  this._super(name);  this.employeeID = employeeID;  },  getEmployeeID: function() {  return this.employeeID;  },  getName: function() {  // 调用父类的方法  return "Employee name: " + this._super();  }  });  var zhang = new Employee("ZhangSan", "1234");  console.log(zhang.getName());  // "Employee name: ZhangSan"
  
  

说实话,对于完成本系列文章的目标-继承-而言,真找不到什么缺点。方法一如jQuery一样简洁明了。

  
  

  

代码分析  
  为了一个漂亮的调用方式,内部实现的确复杂了很多,不过这些也是值得的 - 一个人的思考带给了无数程序员快乐的微笑 - 嘿嘿,有点肉麻。

  
  不过其中的一段代码的确迷惑我一段时间:  

  
  
  fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; 
  
  

我曾在几天前的博客中写过一篇文章专门阐述这个问题,有兴趣可以向前翻一翻。

  

  
  
  // 自执行的匿名函数创建一个上下文,避免引入全局变量  (function() {  // initializing变量用来标示当前是否处于类的创建阶段,  // - 在类的创建阶段是不能调用原型方法init的  // - 我们曾在本系列的第三篇文章中详细阐述了这个问题  // fnTest是一个正则表达式,可能的取值为(/\b_super\b/ 或 /.*/)  // - 对 /xyz/.test(function() { xyz; }) 的测试是为了检测浏览器是否支持test参数为函数的情况  // - 不过我对IE7.0,Chrome2.0,FF3.5进行了测试,此测试都返回true。

  // - 所以我想这样对fnTest赋值大部分情况下也是对的:fnTest = /\b_super\b/;  var initializing = false, fnTest = /xyz/.test(function() { xyz; }) ? /\b_super\b/ : /.*/;  // 基类构造函数  // 这里的this是window,所以这整段代码就向外界开辟了一扇窗户 - window.Class  this.Class = function() { };  // 继承方法定义  Class.extend = function(prop) {  // 这个地方很是迷惑人,还记得我在本系列的第二篇文章中提到的么  // - this具体指向什么不是定义时能决定的,而是要看此函数是怎么被调用的  // - 我们已经知道extend肯定是作为方法调用的,而不是作为构造函数  // - 所以这里this指向的不是Object,而是Function(即是Class),那么this.prototype就是父类的原型对象  // - 注意:_super指向父类的原型对象,我们会在后面的代码中多次碰见这个变量  var _super = this.prototype;  // 通过将子类的原型指向父类的一个实例对象来完成继承  // - 注意:this是基类构造函数(即是Class)  initializing = true;  var prototype = new this();  initializing = false;  // 我觉得这段代码是经过作者优化过的,所以读起来非常生硬,我会在后面详解  for (var name in prop) {  prototype[name] = typeof prop[name] == "function" &&  typeof _super[name] == "function" && fnTest.test(prop[name]) ?

  (function(name, fn) {  return function() {  var tmp = this._super;  this._super = _super[name];  var ret = fn.apply(this, arguments);  this._super = tmp;  return ret;  };  })(name, prop[name]) :  prop[name];  }  // 这个地方可以看出,Resig很会伪装哦  // - 使用一个同名的局部变量来覆盖全局变量,很是迷惑人  // - 如果你觉得拗口的话,完全可以使用另外一个名字,比如function F()来代替function Class()  // - 注意:这里的Class不是在最外层定义的那个基类构造函数  function Class() {  // 在类的实例化时,调用原型方法init  if (!initializing && this.init)  this.init.apply(this, arguments);  }  // 子类的prototype指向父类的实例(完成继承的关键)  Class.prototype = prototype;  // 修正constructor指向错误  Class.constructor = Class;  // 子类自动获取extend方法,arguments.callee指向当前正在执行的函数  Class.extend = arguments.callee;  return Class;  };  })();

★★★小编:汇盛国际注册 整理文章,欢迎大家转载 ★★★
上一篇:JS定义类的六种方式详解
下一篇:没有了