一、工厂模式

  工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程。

   考虑到在 ECMAScript 中无法创建类,开发人员就发明了一种函数,用函数来封装以特定接口创建对象的细节。

function createPerson(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
};
return o; }
var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");
console.log(person1);
console.log(person2);

  运行结果如下图所示:

  函数 createPerson()能够根据接受的参数来构建一个包含所有必要信息的 Person 对象。

  可以无数次地调用这个函数,而每次它都会返回一个包含三个属性一个方法的对象。

  工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型)。

二、构造函数模式

  ECMAScript 中的构造函数可用来创建特定类型的对象,像 Object 和 Array 这样的原生构造函数,在运行时会自动出现在执行环境中。

  此外,也可以创建自定义的构造函数,从而定义自定义对象类型的属性和方法。

   可以使用构造函数模式将前面的例子重写如下:

function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
}; }
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
console.log(person1);
console.log(person2);

  运行结果如下图所示:

    在这个例子中,Person()函数取代了 createPerson()函数。

   我们注意到,Person()中的代码 除了与 createPerson()中相同的部分外,还存在以下不同之处:

1.没有显式地创建对象;

2.直接将属性和方法赋给了 this 对象;

3.没有 return 语句。

  要创建 Person 的新实例,必须使用 new 操作符。以这种方式调用构造函数实际上会经历以下 4 个步骤:

  (1) 创建一个新对象;

  (2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);

  (3) 执行构造函数中的代码(为这个新对象添加属性);

  (4) 返回新对象。

  构造函数与其他函数的唯一区别,就在于调用它们的方式不同。

  不过,构造函数毕竟也是函数,不存在定义构造函数的特殊语法。

  任何函数,只要通过 new 操作符来调用,那它就可以作为构造函数。

  而任何函数,如果不通过 new 操作符来调用,那它跟普通函数也不会有什么两样。

  使用构造函数的主要问题,就是每个方法都要在每个实例上重新创建一遍。

三、原型模式

  我们创建的每个函数都有一个 prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。如果按照字面意思来理解,那么 prototype 就是通过调用构造函数而创建的那个对象实例的原型对象。

  使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。

function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.sayName(); //"Nicholas"
var person2 = new Person();
person2.sayName(); //"Nicholas"
alert(person1.sayName == person2.sayName); //true

  在此,我们将 sayName()方法和所有属性直接添加到了 Person 的 prototype 属性中,构造函数变成了空函数。

  即使如此,也仍然可以通过调用构造函数来创建新对象,而且新对象还会具有相同的属性和方法。

  但与构造函数模式不同的是,新对象的这些属性和方法是由所有实例共享的。

  换句话说, person1 和 person2 访问的都是同一组属性和同一个 sayName()函数。

  缺点:原型中所有属性是被很多实例共享的,这种共享对于函数非常合适。 但是实例一般都是要有属于自己的全部属性,实力属性不能共享。

四、 组合使用构造函数模式和原型模式

  创建自定义类型的最常见方式,就是组合使用构造函数模式与原型模式。

  构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。

  结果,每个实例都会有自己的一份实例属性的副本, 但同时又共享着对方法的引用,最大限度地节省了内存。

  另外,这种混成模式还支持向构造函数传递参数,可谓是集两种模式之长。

function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Shelby", "Court"];
}
Person.prototype = {
constructor : Person,
sayName : function(){
alert(this.name);
}
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
console.log(person1.friends); //"Shelby,Count,Van"
console.log(person2.friends); //"Shelby,Count"
console.log(person1.friends === person2.friends); //false
console.log(person1.sayName === person2.sayName); //true

   在这个例子中,实例属性都是在构造函数中定义的,而由所有实例共享的属性 constructor 和方法 sayName()则是在原型中定义的。

  而修改了 person1.friends(向其中添加一个新字符串),并不会影响到 person2.friends,因为它们分别引用了不同的数组。

五、动态原型模式

  有其他 OO 语言经验的开发人员在看到独立的构造函数和原型时,很可能会感到非常困惑。动态原型模式正是致力于解决这个问题的一个方案。

  动态原型模式把所有信息都封装在了构造函数中,而通过在构造函数中初始化原型(仅在必要的情况下),又保持了同时使用构造函数和原型的优点。换句话说,可以通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型。

function Person(name, age, job){
//属性
this.name = name;
this.age = age;
this.job = job;
//方法
if (typeof this.sayName != "function"){
Person.prototype.sayName = function(){
alert(this.name);
};
}
}
var friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName();

   这里只在 sayName()方法不存在的情况下,才会将它添加到原型中。

  这段代码只会在初次调用构造函数时才会执行。此后,原型已经完成初始化,不需要再做什么修改了。

  不过要记住,这里对原型所做的修改,能够立即在所有实例中得到反映。

六、class模式

  ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

class Point {
constructor(x, y) {
this.x = x;
this.y = y;
} toString() {
console.log(this.x + ', ' + this.y );
}
}
let point = new Point(1,2);
point.toString();//结果为1,2

  上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。

  也就是说,ES5 的构造函数Point,对应 ES6 的Point类的构造方法。

  Point类除了构造方法,还定义了一个toString方法。注意,定义“类”的方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了。

JavaScript创建对象的方式的更多相关文章

  1. javascript——创建对象的方式

    对象:在JavaScript中,对象是拥有属性和方法的数据. JavaScript自定义对象方式有以下7种:直接创建方式.对象初始化器方式.构造函数方法.prototype原型方式.混合的构造函数/原 ...

  2. JavaScript创建对象的方式汇总

    1.Object构造函数创建 // 1.Object构造函数创建 var Obj = new Object(); Obj.name='saoge'; Obj.say=function(){ conso ...

  3. JavaScript 创建对象的七种方式

    转自:xxxgitone.github.io/2017/06/10/JavaScript创建对象的七种方式/ JavaScript创建对象的方式有很多,通过Object构造函数或对象字面量的方式也可以 ...

  4. javascript创建对象的几种方式

    javascript创建对象简单的说,无非就是使用内置对象或各种自定义对象,当然还可以用JSON:但写法有很多种,也能混合使用.主要为下面几种:1.对象字面量的方式 person={firstname ...

  5. javascript中创建对象的方式总结

    javascript中创建对象的方式总结 具体代码如下: //创建对象的方式: //创建方式一 var person=new Object(); person.name='jack'; person. ...

  6. JavaScript创建对象的6种方式

    JavaScript创建对象简单的说,无非就是使用内置对象(Object)或各种自定义对象,当然还可以用JSON,但写法有很多种,也能混合使用. 1.对象字面量的方式 person = {name : ...

  7. JavaScript创建对象的几种 方式

    //JavaScript创建对象的七种方式 //https://xxxgitone.github.io/2017/06/10/JavaScript%E5%88%9B%E5%BB%BA%E5%AF%B9 ...

  8. JavaScript 常见创建对象的方式

    JavaScript 有哪几种创建对象的方式? javascript创建对象简单的说,无非就是使用内置对象或各种自定义对象,当然还可以用JSON:但写法有很多种,也能混合使用. (1)对象字面量的方式 ...

  9. javascript创建对象的几种方式?

    javascript创建对象简单的说,无非就是使用内置对象或各种自定义对象,当然还可以用JSON:但写法有很多种,也能混合使用. 1.对象字面量的方式 person={ firstname:" ...

随机推荐

  1. javascript 中的number

    大家都知道javascript中有五种简单数据类型,number,string,boolean,null,undefined,复杂数据类型是object.本文主要记录下number类型的一些可能不太常 ...

  2. C++学习笔记:多态篇之虚函数

    一.类型 在引入多态之前,我们先来看一下多态的两种类型: 二.多态性的概念 多态一词最初来源于希腊语,意思是具有多种形式或形态的情形,在C++中是指同样的消息被不同类型的对象接收时导致不同的行为,这里 ...

  3. linux下socket connect 阻塞方式 阻塞时间控制

    同事今天问我,如何在linux下的c代码里面控制connect的阻塞时间.应用的背景是:linux下的c程序有两个目标IP需要connect,如果用阻塞方式,当其中一个IP不能连接的情况下,程序将阻塞 ...

  4. 内嵌tomcat最简单用法

    maven项目引入内嵌tomcat依赖 <dependency> <groupId>org.apache.tomcat.embed</groupId> <ar ...

  5. SQLite3的MFC使用

    SQLite,是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,支持跨平台,操作简单,能够使用很多语言直接创建数据库.官方网站:www.sqlite.org 在VC环境下编写连接SQLite的 ...

  6. 自己动手写CPU——寄存器堆、数据存储器(基于FPGA与Verilog)

    上一篇写的是基本的设计方案,由于考研复习很忙,不知道下一次什么时候才能打开博客,今天就再写一篇.写一写CPU中涉及到RAM的部件,如寄存器堆.数据存储器等. 大家应该在大一刚接触到计算机的时候就知道R ...

  7. vue axios上传文件实例

    <head> <title></title> <meta charset="UTF-8"> <meta name=" ...

  8. Oracle常用sql命令

    1.查看数据库归档是开启还是关闭SQL> archive log list 更改数据库归档模式: SQL> shutdown immediateSQL> startup mountS ...

  9. 使用IdentityServer4,在一个ASPNetCore项目中,配置oidc和api的AccessToken两种认证授权

    1.配置两种认证方式 JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); services.AddAuthentication(op ...

  10. OpenGL绘制一个四边形

    学习自:https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/ OpenGL没有直接绘制四边形的a ...