资讯专栏INFORMATION COLUMN

JavaScript面向对象OOM 2(JavaScript 创建对象的工厂模式和构造函数模式)

liuchengxu / 598人阅读

摘要:都是构造函数模式创建的原生构造函数。使用构造函数创建对象经历了以下四个过程创建一个新对象构造函数的作用域交给新对象。

  在创建对象的时候,使用对象字面量和 new Object() 构造函数的方式创建一个对象是最简单最方便的方式。但是凡是处于初级阶段的事物都会不可避免的存在一个问题,没有普适性,意思就是说我要为世界上(程序中)的所有使用到的对象都使用一遍 var xxx = {} ,对于"懒惰"的程序员来讲是不可以接受的。即便你能接受这种创建的方式,也无法保证将所有对象归类这一哲学问题。

  由此,优秀的程序员们利用现有的规则,创造出了一种种优秀的解决方案 -- 这些优秀的解决方案统称为设计模式。

  在 JavaScript 中,设计模式由初级到高级的区别是他们的副作用的大小。依次可以分为:

工厂模式

构造函数模式

原型模式

others

  同时,使用设计模式也可以优雅的解决 JavaScript 在 ES6之前都是没有类的尴尬问题。

工厂模式

  工厂模式,顾名思义就是创建对象的一个工厂,工厂可以创造一类具有相似结构和功能的对象。这个模式的诞生也基本解决了:

创建多个对象的时候,需要大量重复代码

先看下在这种设计模式下,应该如何组织我们的代码:

function createPerson(name, age) {
    var obj = new Object();
    
    obj.name = name ;
    obj.age  = age;
    obj.say  = function() { console.log(this.name)}
    
    return obj;
}

var p1 = createPerson("ZhangSan", 12);
p1.say()  //ZhangSan

这种叫工厂模式的设计模式:是指使用统一的方法(函数,因为 Js 没有类)来描述对象创建的细节

把这个对象封装起来,每次使用类似的对象都使用这个工厂函数来创建。

它抽象了创建一个对象的过程。

当然,处于初级阶段的 工厂模式, 一定有它处于初级阶段的道理:

优势:

工厂函数可以解决创建多个类似功能对象的问题。

缺点:

工厂模式无法解决对象的识别问题: 不知道对象是什么类型的。

使用工厂函数创建的对象,只有开发者是知道它的类型的(通过工厂函数变量名),但是程序仍然认为它是一个普通的对象。

每个对象都是通过工厂造就的全新的对象。

构造函数模式

  在 JavaScript 的开发中,经常会听说和使用的一个词语叫做构造函数,这里的构造函数就是出自构造函数模式这一种设计模式。在长时间的传承中,文化或者其他的名词都会变成一种泛称,所以人们常说的构造函数,有的时候指的是构造函数模式,有的时候指的是构造函数模式创造的对象中的构造函数方法(实例的 constructor )。

  构造函数是用来创建特定的类型的对象的。比如Js原生提供的ObjectArray。都是构造函数模式创建的原生构造函数。

惯例,看下在这种设计模式下,该如何组织代码:

function Person (name, age) {

    this.name = name;
    this.age = age;
    this.say = function() {
        console.log(this.age);
    }
    
}

var p1 = new Person("ZhangSan", 12);
var p2 = new Person("LiSi", 22);
p1.say() // 12
p2.say() // 22

使用构建函数模式和工厂模式创建对象的区别:

没有明显的创建对象的过程: (new Object()的过程)

直接将参数赋值给了 this。(因为 没有创建明显的对象,就需要用 this 进行赋值)

没有 return 。

构造函数的首字母大写,这是代码风格上的变化(为了和其他的 OOM 语言的代码风格保持一致)

创建一个由构造函数创建的对象,需要使用 new Person() 进行创建。

使用构造函数创建对象经历了以下四个过程:

创建一个新对象

构造函数的作用域交给新对象。this指向新对象

执行内部代码,给新对象增加属性和方法

返回新对象

由构造函数创建的对象称为这个构造函数的实例,在实例中会存在一个 constructor 属性,这个属性指向创造它的构造函数。(证明自己从哪里来)

p1.constructor == Person;  // true
p2.constructor == Person;  // true

每一个实例都是可以被检测出来的,检测对象是否属于某一个类型,可以使用 instanceof XX

    p1 instanceof Person // true
    p1 instanceof Object // true

知道了构造函数模式创建实例的过程和方法,下面介绍一些使用构造函数方法中,一些不为人知的秘密(高级知识点):

使用构造函数的时候常规操作是:使用操作符new。但是也可以直接当做一个普通的函数使用。

// Person 在上个 Demo
    
var p3 = Person("Person3", 33);
p3; // undefined;
p3.say(); // undefined;
    
Person("Person4", 44);
window.say(); // 44;
    

如果把构造函数当做普通函数使用了,就不能构造实例了,即使构造了实例,也都是 undefined

直接使用 构造函数当做普通函数使用, 属性和方法会被添加到全局中(window/global)。

当然也可以使用 call把 this 指向其他对象。(不了解 call,可以先忽略。call 是改变 this 指针的方式之一)。

  了解了高级用法之后,细心的孩子已经发现了构造函数方法作为 Level 2的设计模式,一定有哪里不对。其实很简单,在构造函数创建的过程中,很好的解决了工厂模式创建对象不知道类型的问题(不知道自己从哪里来)。在构想上,实例的属性和方法应该都是唯一指向的,理想情况是都指向构造函数。但是差强人意的地方出现了:

属性都很好的指向了 构造函数。 this.name = name

方法又自己偷摸的创建了新的对象(函数也是对象)。这就不符合理想的情况了,因为这个时候:

p1.say === p2.say   // false

原理也很清楚啊:this.say = function() {} 就是 this.say = new Function() 啊。

这个时候,一个构造函数的补救措施出现了:

var Person = function(name, age) {
    this.name = name;
    this.age = age;
    this.say = sayFunc;
}

var sayFunc = function() {
    console.log(this.age)
}

使用额外的函数,将构造函数内的方法指向外部,这样就保证了实例方式的相同。

俗话说的好,补救措施终究是补救措施

在构造函数存在大量的方法的时候,外部会存在数量巨多的补救方法。

补救方法在构造函数的外部,毫无封装性可言。

外部方法也是一个普通的函数,也可以被其他方法或构造函数执行。

外部方法被添加到 全局(window/global)上,性能浪费。如果在 window 上调用,this 就指向了 window。造成 this 指向混乱(谁调用,this 指向谁)

所以,构造函数的方法仍然是一个不完美的方法。但是在开发速度上,构造函数的设计模式还是有很大优势的。

而且当你需要你的方法在全局被使用的时候,构造函数模式是最适合的,这也是 Object, Array原生构造函数出现的原因。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99004.html

相关文章

  • JavaScript面向对象OOM 2JavaScript 创建对象工厂模式构造函数模式

    摘要:都是构造函数模式创建的原生构造函数。使用构造函数创建对象经历了以下四个过程创建一个新对象构造函数的作用域交给新对象。   在创建对象的时候,使用对象字面量和 new Object() 构造函数的方式创建一个对象是最简单最方便的方式。但是凡是处于初级阶段的事物都会不可避免的存在一个问题,没有普适性,意思就是说我要为世界上(程序中)的所有使用到的对象都使用一遍 var xxx = {} ,...

    you_De 评论0 收藏0
  • JavaScript面向对象程序设计

    摘要:目录导语理解对象和面向对象的程序设计创建对象的方式的继承机制原型对象原型链与原型对象相关的方法小结导语前面的系列文章,基本把的核心知识点的基本语法标准库等章节讲解完本章开始进入核心知识点的高级部分面向对象的程序设计,这一部分的内容将会对对象 目录 导语 1.理解对象和面向对象的程序设计 2.创建对象的方式 3.JavaScript的继承机制 3.1 原型对象 3.2 原型链 3.3 与...

    gitmilk 评论0 收藏0
  • 我来重新学习 javascript 面向对象(part 1)

    摘要:其实在之前的工厂模式里面,也存在这个问题,不过工厂模式更彻底,直接完全创建一个新对象,而构造函数模式的话只是方法会被重新创建。 我来重新学习 javascript 的面向对象(part 1) 很多job 的描述都说要求精通 javascript 面向对象编程,但是根据一般的套路,写精通其实就是熟练,写熟练其实就是一般,写一般其实就是懵逼! showImg(https://segment...

    myshell 评论0 收藏0
  • 【9】JavaScript 面向对象高级——对象创建模式

    摘要:解决了构造函数模式不能共享方法的问题。六寄生构造模式流程创建一个构造函数,在这个函数内部创建一个对象,用返回对象。除了使用操作符并把使用的包装函数叫做构造函数以外,这个模式与工程模式其实是一模一样的。 JavaScript面向对象高级——对象创建模式 一、工厂模式 流程: 定义一个函数,函数返回对象。 适用场景: 需要创建多个对象,都是Object类型。 优点:完成了返回一个对象的...

    linkin 评论0 收藏0
  • JavaScript面向对象 - 创建对象(上)

    摘要:对象字面量创建对象张三学生这种方式的好处显而易见,就是解决了之前的缺点。构造函数模式张三学生李四学生与之前工厂模式的方法对比变量名首字母大写了在函数内没有显式的创建及返回对象而使用了创建时使用了关键字。 面向对象是JS的重点与难点,但也是走向掌握JS的必经之路,有很多的文章或书籍中都对其进行了详细的描述,本没有必要再写这些,但是对于学习来说,讲给别人听对自己来说是一种更好的受益方式。我...

    sourcenode 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<