js之工厂构造函数模式(译)

本文为译文,初次翻译,若有误导,请多多包含,如阅读英文,可直接戳连接便可js之工程构造函数模式编程

若想听音频内容,可戳连接js之工厂构造函数模式bash

类模式

前言

在面向(oriented)对象编程中,一个类是一个可扩展的程序代码的模板,用于建立对象,为状态(成员变量)和行为实现(implementations)(成员函数或方法)提供初始值ide

JavaScript中有一个特殊的语法结构和关键字类。但在学习以前,咱们应该考虑“类”这个术语来自于面向对象编程的理论。定义在上面引用,它是语言无关独立的函数

在JavaScript中有几个众所周知的编程模式,即便不使用class关键字也能够编写类。在这里,咱们首先来谈谈他们性能

这个类的构造将在下一章中描述,可是在JavaScript中它是一个“语法糖”,是咱们在这里学习的一种模式的扩展学习

功能类模式

根据定义,下面的构造器函数能够被认为是“类ui

/*
   *
   *  用new关键字+函数名(),那么这个函数为构造器函数
   *  @construtor: User
   *  @methods:sayHi
   *
   *
    */
   functoin User(name){
        this.sayHi = function(){
        alert(name);
     }
   }
   let user = new User("john");
   user.sayHi();  // john
复制代码

结果以下所示:this

功能类模式
它遵循定义的全部部分

  1. 它是一个用于建立对象的“程序代码模板”(能够用new来调用)
  2. 它提供了状态的初始值(参数名称)
  3. 它提供了方法(sayHi)

在函数类模式中,用户内部的局部变量和嵌套函数,没有分配给它,从内部可见,但在外部代码没法访问spa

因此咱们能够很容易地添加内部函数和变量,好比calcAge()prototype

/*
*  添加内部函数和变量
*  @constructor: User
*  @parameter: 参数name,birthday
*  @function calcAge
*  @methods: sayHi
*  @return 时间戳
*
 */
function User(name,birthday){
    // only visible from other methods inside User
    function calcAge(){
        return new Date().getFullYear()-birthday.getFullYear();
    }
    this.sayHi = function(){
        alert(`${name,age:${calcAge()}}`);
    }
}
let user = new User("john",new Date(2000,0,1));
user.sayHi();  // john,age:18
复制代码

结果以下所示:

内部函数与变量
在这个代码中,变量名,生日和函数calcAge()是内部,对象是私有的。他们只能从里面看到

另外一方面,说Hi就是外在的,公开的方法。建立用户的外部代码能够访问它

这样咱们就能够从外部代码中隐藏内部实现(internal implementation)细节和辅助方法。只有分配给这个构造函数才能够看得见外面的

工厂类模式

咱们能够建立一个班级,而不使用新的

像这样

/*
* 工厂类模式
* @constructor User
* @parameter 形式参数:name,birthday
* @function calcAge
* @return 当前的年份-出生的年份
* @return User函数返回一个sayHi函数,将名字和年龄结果进行输出
*
*
 */
function User(name,birthday){
    // only visible from other methods inside User
    function calcAge(){
        return new Date().getFullYear()-birthday.getFullYear();
    }
    return{
        sayHi(){
            alert(`${name},age:${calcAge()}`);
        }
    }
}
let user = User("john",new Date(2000,0,1)); // 函数名的调用,函数表达式赋值
user.sayHi();  

复制代码

实现的效果以下所示

工厂类模式
正如咱们所看到的,函数User返回一个具备公共属性和方法的对象。这种方法的惟一好处是咱们能够省略new:write let user = User(...)而不是let user = new User(...)。在其余方面,它几乎与功能模式相同

基于原型的类

基于原型的课程是最重要的,也是最好的。功能和工厂类模式在实践中不多使用

不久你就会明白为何

这是用原型重写的同一个类

/*
*
* 基于原型重写的一个类
* @function User
* @parameter name,birthday
* @prototype 
* @methods: _calcAge,sayHi
* 
*
 */
function User(name,birthday){
    this._name = name;
    this._birthday = birthday;
}

User.prototype._calcAge = function(){
    return new Date().getFullYear()-this._birthday.getFullYear();
}

User.prototype._calcAge = function(){
    return new Date().getFullYear()-this_birthday.getFullYear();
}

User.prototype.sayHi = function(){
    alert(`${this._name},age:${this._calcAge()}`);
}

let user = new User("john",new Date(2000,0,1));
user.sayHi();

复制代码

实现效果以下所示:

基于原型的类
代码结构

  1. 构造函数User仅初始化当前的对象状态
  2. 方法被添加到User.prototype中

正如咱们所看到的,方法在词法做用域上不在函数User内部,它们并不共享一个通用的做用域环境.若是咱们在函数User中声明变量,那么它们将不会被方法看到

因此,有一个众所周知的协议,内部属性和方法前缀为下划线“”。像_name或_calcAge()。从技术上讲,这只是一个协议,外部代码仍然能够访问它们。但大多数开发人员认识到“”的含义,并尽可能不要触摸外部代码中的前缀属性和方法

如下是功能模式的优势:

  1. 在功能模式中,每一个对象都有本身的每一个方法的副本。咱们在构造函数中分配了this.sayHi = function(){...}和其余方法的单独副本

  2. 在原型模式中,全部的方法都是在全部用户对象之间共享的User.prototype中。一个对象自己只存储数据

因此原型模式更具备记忆效率

但不只如此。原型容许咱们以很是有效的方式设置继承。内置的JavaScript对象都使用原型。还有一个特殊的语法结构:“类”,为他们提供漂亮的语法。还有更多,因此让咱们继续他们

类基于原型的继承

假设咱们有两个基于原型的类

兔子:

/*
*
* 类基于原型的继承
* 
* @function Rabbit
* @paraterm name  
* @method jump
* @constructor: Rabbit
* 
*/
   function Rabbit(name){
      this.name = name;
   }
   Rabbit.prototype.jump = function(){
      alert(`${this.name}jimp!`);
   }
   let rabbit = new Rabbit("my rabit");
   rabbit.jump();  // my rabit jimp

复制代码

实现的效果图以下

类基于原型的继承

过程图解
和动物

/*
   *  @constructor:Animal
   *  @methods:eat
   *
   *    
    */
   function Animal(name){
       this.name = name;
   }
   Animal.prototype.eat = function(){
       alert(`${this.name}eats`);
   }
   let animal = new Animal("My animal");
   animal.eat();
复制代码

代码实例效果以下:

类的继承
如今他们彻底独立了

可是咱们但愿兔子能扩展动物。换句话说,兔子应该以动物为基础,可使用动物的方法,并用本身的方法扩展它们

原型语言是什么意思?

如今兔子对象的方法在Rabbit.prototype中。若是在Rabbit.prototype中找不到方法,咱们但愿兔子使用Animal.prototype做为“后备”

因此原型链应该是RabbitRabbit.prototypeAnimal.prototype

像这样

原型链
要实现的代码

/*
   * @constructor Animal,Rabbit
   * @paraterm name
   * @methods:eat,jump
   * 
   *
   *
    */
   // same Animal as before
   function Animal(name){
      this.name = name;
   }
   // All animals can eat,right?
   Animal.prototype.eat = function(){
      alert(`${this.name}eats`);
   }
   // same Rabbit as before
   function Rabbit(name){
      this.name = name;
   }
   Rabbit.prototype.jump = function(){
      alert(`${this.name}jumps`);
   }
   // setup the inheritance chain
   Rabbit.prototype._proto_= Animal.prototype; // (*)

   let rabbit = new Rabbit("white Rabbit");

   rabbit.eat();  // rabbits can eat too
   rabbit.jump();  
复制代码

该行(*)设置了原型链。因此兔子首先在 Rabbit.prototype中搜索方法,而后是 Animal.prototype。而后,为了完整起见,若是在Animal.prototype中没有找到该方法,则继续在 Object.prototype中进行搜索,由于 Animal.prototype是一个普通的普通对象,因此它继承了它

因此这是完整的画面

过程图解

小结

术语“类”来自面向对象编程。在JavaScript中,它一般意味着功能类模式或原型模式。原型模式更强大,更高效,因此它建议坚持下去

根据原型模式

  1. 方法存储在Class.prototype中
  2. 原型相互继承

总结

在本节当中,主要讲的是工厂构造函数模式,用于建立对象的模板,其中模板能够粗俗的理解模具,它是基于一份模具建立不少个不一样的对象,工厂构造函数就是用于建立多个共享特性和行为的对象,经过构造函数生成的对象具备默认的属性和方法,而原型就是更改对象下面公用的属性和方法,让公用的属性和方法达到共用一份,一是为了减小内存的开销,提升性能,另外一方面是为了拓展,当须要在代码的其他全部部分经过屏蔽较为复杂的的对象建立方法来简化某些特定对象的建立过程时,使用工厂模式最为合适,其实它也就是面向对象的一种写法

相关文章
相关标签/搜索