JavaScript中创建对象的模式汇总


Posted in Javascript onApril 19, 2016

JavaScript中创建对象的模式汇总

**JavaScript创建对象模式:

对象字面量
工厂模式
构造函数模式
原型模式
结合构造函数和原型模式
原型动态模式
**

面向对象的语言大都有一个类的概念,通过类可以创建多个具有相同方法和属性的对象。虽然从技术上讲,javascript是一门面向对象的语言,但是javascript没有类的概念,一切都是对象。任意一个对象都是某种引用类型的实例,都是通过已有的引用类型创建;引用类型可以是原生的,也可以是自定义的。

1、对象字面量

var person = {
    name : 'Nicholas';
    age : '22';
    job :"software Engineer"
    sayName: function() {
      alter(this.name);
  }
}

例子中创建一个名为person的对象,并为它添加了三个属性(name,age,job)和一个方法(sayName()),其中,sayName()方法用于显示this.name(被解析为person.name)的值。

对象字面量可以用来创建单个对象,但这个方法有个明显的缺点:使用同一个接口创建很多对象,会产生大量重复的代码。

2、工厂模式

工厂模式是软件工程领域中一种广为人知的设计模式,工厂模式抽象了创建具体对象的过程,用函数来封装以特定的接口创建对象的细节。

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=creatPerson("Nicholas",22,"software Engineer");
var person2=creatPerson("Greg",24,"student");

函数creatPerson{}能够根据接受的参数构建一个包含所有必要信息的Person对象。可以无数次的调用这个函数,每次都会返回一个包含三个属性一个方法的对象。

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

3、构造函数模式

function Person(name,age,job) {
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function() {
    alert(this.name);
  }
}
//通过new操作符创建Person的实例
var person1 = new Person("Nicholas",22,"software Engineer");
var person2 = new Person("Greg",24,"student");
person1.sayName(); //Nicholas
person2.sayName(); //Greg

与工厂模式不同的是

没有显示的创建对象

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

没有return语句

创建Person的新实例,必须使用new操作符。调用构造函数的4个步骤:

创建一个新对象

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

执行构造函数中的代码

返回新对象

这个例子中创建的所有对象既是Object的实例,也是Person实例。可以通过instanceof操作符验证。

alert(person1 instanceof Object);//true

构造函数模式也有自己的问题,实际上,sayName方法在每个实例上都会被重新创建一次,需要注意的是,通过实例化创建的方法并不相等,以下代码可以证明

alert(person1.sayName == person2.sayName);//false

可以将方法移到构造器的外部作为全局函数来解决这个问题。

function Person(name,age,job) {
  this.name = name;
  this.age = age;
  this.job = job;  
}
function sayName() {
    alert(this.name);
  }

在全局下创建的全局函数实际上只能被经由Person创建的实例调用,这就有点名不副实了;如果对象需要定义很对方法,那么就要定义很多个全局函数,缺少封装性。

4、原型模式

JavaScript中创建的每个函数都有一个prototype(原型)属性,它是一个指针,指向一个对象,包含了可以由特定类型的所有实例共享的属性和方法(让所有的对象实例共享它的属性和方法)

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

以上代码做了这几件事情:

定义了一个构造函数Person,Person函数自动获得一个prototype属性,该属性默认只包含一个指向Person的constructor属性
通过Person.prototype添加三个属性,和一个方法

创建一个Person的实例,随后在实例上调用了sayName()方法

使用Person构造函数和Person.prototype创建实例的代码为例,展示个对象之间的关系

使用Person构造函数和Person.prototype创建实例的代码为例,展示个对象之间的关系

JavaScript中创建对象的模式汇总 

图中展示了Person构造函数、Person的原型属性以及Person的两个实例,之间的关系。Person.prototype指向了原型对象,Person.prototype.constructor有指回了Person。原型对象中除了包含constructor属性,还包含后来添加的其他属性和方法,Person的两个实例person1和person2都包含一个内部属性,该属性仅指向Person.prototype。

sayName()方法的调用过程:

在person1实例上查找logName()方法,发现没有这个方法,于是追溯到person1的原型

在person1的原型上查找sayame()方法,有这个方法,于是调用该方法

基于这样一个查找过程,我们可以通过在实例上定义原型中的同名属性,来阻止该实例访问原型上的同名属性,需要注意的是,这样做并不会删除原型上的同名属性,仅仅是阻止实例访问。

function Person() {}
  Person.prototype.name ="Nicholas";
  Person.prototype.age = 22;
  Person.prototype.job = "software Engineer";  
  Person.prototype.sayName(){
    alert(this.name);
  };
 var person1 = new Person();
 var person2 = new Person();
 person1.name="Greg"
alert(person1.name) //Greg 来自实例
alert(person2.name) //Nicholas 来自原型

使用delete操作符可以完全删除实例属性

delete person1.name;
alert(person1.name) //Nicholas 来自原型

使用hasOwnProperty()方法可以检测一个属性是存在于实例还是原型中

function Person() {}
  Person.prototype.name ="Nicholas";
  Person.prototype.age = 22;
  Person.prototype.job = "software Engineer";  
  Person.prototype.sayName(){
    alert(this.name);
  };
 var person1 = new Person();
 var person2 = new Person();
 alert(person1,hasOwnProperty("name"));//false
 person1.name="Greg"
alert(person1.name) //Greg 来自实例
 alert(person1,hasOwnProperty("name"));//true
alert(person2.name) //Nicholas 来自原型
 alert(person2,hasOwnProperty("name"));//false
 delete person1.name;
alert(person1.name) //Nicholas 来自原型
 alert(person1,hasOwnProperty("name"));//false

下图展示了在不同情况下实例与原型之间的关系

JavaScript中创建对象的模式汇总

简单的原型语法

function Person() {}
 Person.prototype={
 name :"Nicholas",
 age : 22,
 job : "software Engineer", 
 sayName:function(){
    alert(this.name);
    }
  };

在上面的代码中constructor属性不再指向Person了,通过constructor无法确定对象的类型了。可以像下面这样特意将他设置回适当的值

function Person() {}
 Person.prototype={
 constructor:Person,
 name :"Nicholas",
 age : 22,
 job : "software Engineer",  
 sayName:function(){
    alert(this.name);
    }
  };

重设constructor属性会导致它的[[Enumerable]]特性被设置为true,默认情况,原生的constructor属性是不可枚举的,可以使用Object.defineProperty()方法来改变

Object.defineProperty(Person.prototype,"constructor",{
  enumerable:false,
  value:Person
});

原型中查找值的过程是一次搜索,原型对象所做的任何修改都能从实例上立即反应出来

var friend=new Person();
Person.prototype.sayHi=function(){
  alert("hi);
}
friend,sayHi();//"hi"(没有问题)

person实例是在添加新方法之前创建的,但仍可以访问新添加的方法,原因是实例与原型之间的松散连接关系
重写原型对象后的情况

function Person() {}
var friend=new Person();
 Person.prototype={
 name :"Nicholas",
 age : 22,
 job : "software Engineer", 
 sayName:function(){
    alert(this.name);
    }
  };
  friend.sayName();//error

调用friend.sayName()时发生错误的原因是,friend指向的原型中不包含以该字段命名的属性,如下图。

JavaScript中创建对象的模式汇总 

原型对象的问题

原型对象省略了为构造函数传递初始化参数这一环节,所有势力在默认情况下都取得相同的属性值。原型模型最大的问题是有其共享本性所导致的。当原型模型包含引用类型的属性来说,问题就比较严重了。来看下面的例子。

function Person() {}
 Person.prototype={
 constructor:Person,
 name :"Nicholas",
 age : 22,
 job : "software Engineer",  
 friends:["Shelby","Court"],
 sayName:function(){
    alert(this.name);
    }
  };
  var person1=new Person();
  var person2=new Person();
  person1.friend.push("Van");
  alert(person1.friends);//"Shelby,Court,Van"
  alert(person2.friends);//"Shelby,Court,Van"
 alert(person1.friends==person2.friends);//true

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

组合使用构造函数模式和原型模式中,构造函数用于定义实例属性,原型模型用于定义方法和共享的属性。这样每个实例都会有自己的一份实例属性的副本,同时也可以共享对方法的引用,最大限度的节省了内存。

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",22,"software Engineer");
var person2 = new Person("Greg",24,"student");
person1.friend.push("Van");
  alert(person1.friends);//"Shelby,Court,Van"
  alert(person2.friends);//"Shelby,Court"
 alert(person1.friends==person2.friends);//false
 alert(person1.sayName==person2.sayName);//true

6、动态原型模式

原型动态模式将需要的所有信息都封装到构造函数中,通过if语句判断原型中的某个属性是否存在,若不存在(在第一次调用这个构造函数的时候),执行if语句内部的原型初始化代码。

function Person(name,age) {
  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','22','Software Engineer');//初次调用构造函数,此时修改了原型
var person2 = new Person('amy','21');//此时sayName()方法已经存在,不会再修改原型

推荐阅读:

以上所述是小编给大家介绍的JavaScript中创建对象的模式,希望对大家有所帮助!

Javascript 相关文章推荐
jQuery 常见学习网站与参考书
Nov 09 Javascript
JavaScript 闭包在封装函数时的简单分析
Nov 28 Javascript
jquery.jstree 增加节点的双击事件代码
Jul 27 Javascript
js预载入和JavaScript Image()对象使用介绍
Aug 28 Javascript
JS关闭窗口或JS关闭页面的几种代码分享
Oct 25 Javascript
jQuery头像裁剪工具jcrop用法实例(附演示与demo源码下载)
Jan 22 Javascript
javaScript语法总结
Nov 25 Javascript
JS实现的JSON序列化操作简单示例
Jul 02 Javascript
vue router 源码概览案例分析
Oct 09 Javascript
jQuery实现根据身份证号获取生日、年龄、性别等信息的方法
Jan 09 jQuery
简单了解JavaScript弹窗实现代码
May 07 Javascript
js+for循环实现字符串自动转义的代码(把后面的字符替换前面的字符)
Dec 24 Javascript
使用PHP+JavaScript将HTML页面转换为图片的实例分享
Apr 18 #Javascript
简单讲解jQuery中的子元素过滤选择器
Apr 18 #Javascript
举例讲解jQuery中可见性过滤选择器的使用
Apr 18 #Javascript
html5+javascript实现简单上传的注意细节
Apr 18 #Javascript
jQuery的内容过滤选择器学习教程
Apr 18 #Javascript
原生JS和jQuery版实现文件上传功能
Apr 18 #Javascript
基于Bootstrap实现Material Design风格表单插件 附源码下载
Apr 18 #Javascript
You might like
php下使用无限生命期Session的方法
2007/03/16 PHP
PHP join()函数用法与实例讲解
2019/03/11 PHP
JavaScipt基本教程之JavaScript语言的基础
2008/01/16 Javascript
js一组验证函数
2008/12/20 Javascript
js抽奖实现随机抽奖代码效果
2013/12/02 Javascript
jQuery使用prepend()方法在元素前添加内容用法实例
2015/03/26 Javascript
js实现跨域的几种方法汇总(图片ping、JSONP和CORS)
2015/10/25 Javascript
在js里怎么实现Xcode里的callFuncN方法(详解)
2016/11/05 Javascript
前端页面文件拖拽上传模块js代码示例
2017/05/19 Javascript
Webpack常见静态资源处理-模块加载器(Loaders)+ExtractTextPlugin插件
2017/06/29 Javascript
解决vue-cli创建项目的loader问题
2018/03/13 Javascript
Angularjs实现数组随机排序的方法
2018/10/02 Javascript
jQuery利用cookie 实现本地收藏功能(不重复无需多次命名)
2019/11/07 jQuery
vue监听键盘事件的相关总结
2021/01/29 Vue.js
Python 可爱的大小写
2008/09/06 Python
Python使用scrapy抓取网站sitemap信息的方法
2015/04/08 Python
Ruby元编程基础学习笔记整理
2016/07/02 Python
python+matplotlib绘制3D条形图实例代码
2018/01/17 Python
8种用Python实现线性回归的方法对比详解
2019/07/10 Python
Python使用itchat模块实现群聊转发,自动回复功能示例
2019/08/26 Python
python 实现绘制整齐的表格
2019/11/18 Python
基于python实现上传文件到OSS代码实例
2020/05/09 Python
Python requests上传文件实现步骤
2020/09/15 Python
详解pandas赋值失败问题解决
2020/11/29 Python
python中xlrd模块的使用详解
2021/02/01 Python
Bibloo罗马尼亚网站:女装、男装、童装及鞋子和配饰
2019/07/20 全球购物
俄罗斯隐形眼镜和眼镜在线商店:Cronos
2020/06/02 全球购物
学校司机岗位职责
2013/11/14 职场文书
社区活动邀请函范文
2014/01/29 职场文书
安全演讲稿大全
2014/05/09 职场文书
学习作风建设心得体会
2014/10/22 职场文书
留学推荐信怎么写
2015/03/26 职场文书
2016特色励志班级口号
2015/12/24 职场文书
2016读书月活动心得体会
2016/01/14 职场文书
如何写一份具有法律效力的借款协议书?
2019/07/02 职场文书
使用css样式设计一个简单的html登陆界面的实现
2021/03/30 HTML / CSS