解析John Resig Simple JavaScript Inheritance代码

解析 John Resig 在 Simple JavaScript Inheritance 代码的思路可以分为以下几个部分:

简介

这是 John Resig 在 2008 年发布的一个 JavaScript 类继承的库,用来实现类的继承。

源代码及解析

下面我们来逐行分析源代码实现:

首先,定义了一个匿名函数,并将其赋值给 Class 变量。

var Class = (function() {
    // ...
})();

这里利用了函数声明的特性,定义了一个 IIFE,返回一个对象。

1. Fn.prototype.extend

接下来就是对象的方法,其中,最重要的就是 extend 方法,这个方法有两个参数,第一个是一个对象,表示新的类的原型对象,第二个是一个对象,表示新的类的静态属性和方法。

// 添加方法和静态属性
Function.prototype.extend = function(prop) {
  var _super = this.prototype;

  function F() {};
  F.prototype = _super;

  var prototype = new F();

  for(var name in prop) {
    if(typeof prop[name] === "function" &&
       typeof _super[name] === "function" &&
       fnTest.test(prop[name])) {

      prototype[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]);

    } else {
      prototype[name] = prop[name];
    }
  }

  function Class() {
    if (this.init) {
      this.init.apply(this, arguments);
    }
  }

  Class.prototype = prototype;
  Class.constructor = Class;
  Class.extend = arguments.callee;

  return Class;
};

在这个方法的内部中,核心部分就是以下这段代码:

var _super = this.prototype;
function F() {};
F.prototype = _super;
var prototype = new F();

这里定义了一个代理函数 F,这个函数的作用是一个中间代理层,可以用来保存原型对象 _super 的引用,从而避免对父类对象的修改。

接下来,将代理函数 F 的原型属性指向当前对象的原型属性,这样代理函数 F 就成为了一个新的对象,这个新的对象有原型属性继承自当前对象。

接着定义一个 for 循环,遍历新的类的原型对象上的属性,将方法保存至新的原型对象上。

其中,最重要的部分在于这样的一个条件判断:

typeof prop[name] === "function" &&
typeof _super[name] === "function" &&
fnTest.test(prop[name])

如果当前对象和父类对象上都拥有相同名称的方法,并且这个方法符合正则表达式 fnTest 规定的格式,则使用 closure 的思想实现闭包函数。

这里 closure 函数在 arguments 对象中做了一个小的修改,简单来说就是是利用 arguments 对象保存 this 的引用,并在函数返回的时候计算出方法的返回值。

对于非方法的属性,直接将属性保存到新的原型对象上。

最后,定义并返回一个改写过的函数 Class,用来定义新的类。

在 Class 中,还增加了一个新的方法 init,用来在对象创建时初始化对象的属性。

2. _super 属性

另外一个重要的功能就是函数中的 _super 属性,这个属性用来在子类中调用父类中相同名称的方法。

var _super = this._super || function() {};

这个属性也是利用了 closure 函数的思想,每一次将 _super 模拟为当前方法的上一个版本,避免对父类对象进行操作。

3. 对象的创建

Class 这个对象是通过原型属性来定义的,因此可以用 new 关键字来创建新的对象。在对象创建的时候,可以传递参数给 init 方法初始化对象的属性。

示例说明

示例 1:

// 父类
var Person = Class.extend({
  init: function(name, age) {
    this.name = name;
    this.age = age;
  },
  sayName: function() {
    console.log("name: " + this.name);
  },
  sayAge: function() {
    console.log("age: " + this.age);
  }
});

// 子类
var Student = Person.extend({
  init: function(name, age, stuNo) {
    this._super(name, age);
    this.stuNo = stuNo;
  },
  sayStuNo: function() {
    console.log("student number: " + this.stuNo);
  }
});

// 创建父类对象
var p = new Person("Tom", 20);
console.log(p); // Person {name: "Tom", age: 20}

// 创建子类对象
var s = new Student("Jhon", 18, 20210001);
console.log(s); // Student {name: "Jhon", age: 18, stuNo: 20210001}

s.sayName(); // name: Jhon
s.sayAge(); // age: 18
s.sayStuNo(); // student number: 20210001

以上是一个简单 class 继承的示例,通过相同的名称的方法实现了类的继承。

示例 2:

var Animal = Class.extend({
  makeSound: function() {
    console.log("Animal sound...");
  }
});

var Cat = Animal.extend({
  makeSound: function() {
    console.log("Mew...");
    this._super();
  }
});

var cat = new Cat();
cat.makeSound(); // Mew... \n Animal sound...

这是一个更加直观的 _super 方法的使用示例。通过先在子类中重写方法,再显示调用父类的方法实现了在子类方法中调用父类方法的使用。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:解析John Resig Simple JavaScript Inheritance代码 - Python技术站

(0)
上一篇 2023年6月10日
下一篇 2023年6月10日

相关文章

  • 学习JavaScript设计模式(策略模式)

    学习JavaScript设计模式之策略模式 什么是策略模式?策略模式是一种行为设计模式,它能让你定义一系列算法,将它们封装到一个个独立的类中,可以使它们相互替换。策略模式使得算法可以独立于使用它们的客户端而变化。 在JavaScript中,策略模式通常是通过定义不同的函数来实现的。根据需要,你可以将算法添加到一个对象中,然后把这个对象传递给执行某个方法的函数…

    JavaScript 2023年5月18日
    00
  • js实时获取系统当前时间实例代码

    下面是详细的讲解“js实时获取系统当前时间实例代码”: 1. 获取系统当前时间 使用JavaScript获取系统当前时间可以使用Date对象及其方法来实现。我们可以使用new关键字创建一个Date对象,然后调用它的相关方法来获取当前时间。以下是获取当前时间的代码示例: var now = new Date(); var hours = now.getHour…

    JavaScript 2023年5月27日
    00
  • 简介JavaScript中charAt()方法的使用

    简介JavaScript中charAt()方法的使用 什么是charAt()方法? JavaScript中的charAt()是一个字符串方法,用于返回指定索引处的字符。索引从0开始,即第一个字符的索引为0,第二个字符的索引为1,以此类推。如果索引超过了字符串的长度,则返回空字符串。 如何使用charAt()方法? 使用charAt()方法的语法如下: str…

    JavaScript 2023年5月28日
    00
  • 探讨JavaScript语句的执行过程

    我们来详细讲解一下“探讨JavaScript语句的执行过程”的完整攻略: 什么是JavaScript语句的执行过程? 在JavaScript中,语句的执行过程是指将代码逐行解释并执行的过程,然后将执行结果返回到执行环境中。JavaScript语句执行的过程是从上到下进行的。 在执行JavaScript代码时,代码的执行被分为两个步骤:编译和执行。编译是指将代…

    JavaScript 2023年5月18日
    00
  • JavaScript事件学习小结(一)事件流

    JavaScript事件学习小结(一)事件流 前言 JavaScript 是一种基于事件驱动的编程语言,而事件机制也是 JavaScript 中非常重要的一部分。本篇笔记介绍的是事件流的相关知识,对于理解事件机制起着重要的作用。 什么是事件流? 当一个事件发生时,JavaScript 引擎会按照一定的顺序处理事件。这个顺序就是事件流。 事件流分为两种:冒泡流…

    JavaScript 2023年6月10日
    00
  • javascript阻止浏览器后退事件防止误操作清空表单

    下面我将详细讲解如何使用JavaScript阻止浏览器后退事件,以防止误操作清空表单。 什么是阻止浏览器后退事件? 在浏览器中,当我们按下”后退”按钮或点击浏览器的返回箭头时,浏览器会自动回退到上一个页面,这就是浏览器的后退事件。 但是,在某些情况下,我们不希望用户回退到上一个页面,比如在填写表单时,用户误操作点击了后退按钮,导致表单数据丢失。此时,我们可以…

    JavaScript 2023年6月11日
    00
  • Javascript创建类和对象详解

    Javascript创建类和对象详解 在Javascript中,我们可以使用构造函数和原型对象的方式来创建类和对象。 构造函数 构造函数是一个普通的函数,用于初始化一个对象。在使用new运算符生成一个对象时,会自动创建一个空对象,并将该对象传递到构造函数中,最终返回这个对象。构造函数的命名规则是约定俗成的首字母大写。 示例1 function Person(…

    JavaScript 2023年5月27日
    00
  • javascript实现加载xml文件的方法

    下面是关于 javascript 实现加载 XML 文件的方法的完整攻略。 准备工作 在 JavaScript 中实现了加载 XML 文件之后,我们需要对其进行解析处理,因此我们需要一个能够方便操作 XML 文档的 API,推荐使用 DOM 解析器。它可以让我们快速地获取 XML 文件中的节点、属性等信息。 方法一:使用 XMLHttpRequest 对象加…

    JavaScript 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部