关于JavaScript中的创建对象的学习总结
一、最简单的对象创建方法
在JavaScript中,直接使用Object构造函数或对象字面量都可以很轻易地创建单个对象,缺点是:创建具有同一个接口(标准的OO中的接口概念)的多个对象时,会有大量重复代码。为解决这个问题,引出了工厂模式。
二、工厂模式
工厂模式是GoF的23中设计模式中比较简单的模式,简单总结就是定义一个用于创建对象的接口,让子类决定具体实例化那一个类。具体到JavaScript中,因为根本就没有标准OO里面类的概念,开发人员发明了一种函数,用函数来封装以特定接口来创建对象的细节。
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("Haha", 34, "Doctor"); var person2 = createPerson("Hehe", 23, "worker");
使用工厂模式创建对象解决了代码重复的问题,却没有解决对象识别的问题:所有由createPerson函数创建的对象都是Object构造函数的实例。为了解决这个问题,引入了构造函数模式。
三、构造函数模式
通过创建自定义的构造函数,从而定义自定义对象类型的属性和方法。
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = function() { alert(this.name); }; } var person1 = new Person("Haha", 34, "Doctor"); var person2 = new Person("Hehe", 23, "Worker");
此处,我们必须使用new操作符来调用构造函数Person()。这样就会有以下四个步骤:
1)创建一个新对象;
2)将新对象赋给构造函数的作用域(因此this就指向了这个新对象);
3)执行构造函数中的代码(为这个新对象添加属性);
4)返回新对象(没有明确return其他对象,默认返回新对象);
现在,person1和person2不仅仅都是Object构造函数的实例,而且都是Person构造函数的实例。构造函数模式的缺点是:每个构造函数中定义的方法在其生成的每个实例上都重新创建一遍,如果生成的实例比较多或者每个方法都比较大,这种模式会非常消耗资源。有一种变通方法如下:
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName() { alert(this.name); } var person1 = new Person("Haha", 34, "Doctor"); var person2 = new Person("Hehe", 23, "Worker");
通过把方法转移到构造函数外部,对象person1和person2实现了共享函数sayName()。带来的问题是sayName()函数处在全局作用域中,从而失去封装性问题和大量类似函数的数量膨胀问题。为此,我们想到了原型模式。
四、原型模式
我们创建的每个函数都有一个 prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型(指向这个对象的函数)的所有实例共享的属性和方法。注意:这个对象是在创建函数的同时,就已经自动被创建了,而且通过函数的prototype属性和对象的constructor属性进行了相互指向。在对函数调用了new操作符之后,所有生成的实例把函数的prototype属性指向的对象作为自己的原型对象。
function Person() { } Person.prototype.name = "Haha"; Person.prototype.age = 34; Person.prototype.job = "Doctor"; Person.prototype.sayName = function() { alert(this.name); }; var person1 = new Person(); var person2 = new Person(); person1.sayName === person2.sayName;
各个对象之间的关系:
注意一:实例对象和构造函数没有直接的关联,它们只是在生成时,把自己的内部属性[[Prototype]]指向了Person Prototype对象,而和Person构造函数之间并没有之间联系起来。造成的影响是:当实例生成后去改变Person构造函数的prototype属性,使之重新指向一个对象的话,实例的[[Prototype]]属性不会跟随变化。
注意二:原型对象带来的对象属性的读和写的不对等性。
注意三:原型的动态性,本质是实例与原型之间的松散连接关系。
原型模式的问题是:1、没有了构造函数传递初始化参数这一环节;2、引用类型值的共享带来的问题。
五、组合使用构造函数模式与原型模式
因为构造函数模式和原型模式的优缺点互补性,创建自定义类型的最常见方式,就是组合使用构造函数模式与原型模式。构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。
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("Haha", 34, "Doctor"); var person2 = new Person("Hehe", 23, "Worker");
到了这一步,JavaScript中创建对象的方法应该学习的差不多了,但是,总会有一些特殊需求。
六、动态原型模式
如果你对上面第五种方法中的组合模式感到困惑或者不爽,那么你可以试试这个动态原型模式。它把所有的信息都封装在构造函数中,而通过在构造函数中初始化原型(仅在必要的情况下),保存了组合模式的优点。
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); }; } }
七、寄生构造函数模式
该模式的基本思想是:创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后在返回新创建的对象。
function Person(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 friend = new Person("Haha", 34, "Doctor"); friend.sayName();
此处与工厂模式的区别仅仅是:使用new去调用构造函数。注意在构造函数中没有去使用默认生成的新对象this,并且通过显式的return语句改写了构造函数的默认返回对象。
这个模式可以在特殊的情况下用来为对象创建构造函数。
八、稳妥构造函数模式
JavaScript中的稳妥对象(durable objects),指的是没有公共属性,而且其方法也不引用this的对象。稳妥对象适合在一些安全的环境中(禁止this和new),或者防止数据被其他应用程序改动时使用。
function Person(name, age, job) { var o = new Object(); // 可在此处定义室友变量和函数 // 添加方法 o.sayName = function() { alert(name); }; return o; }
注意:此种模式创建的对象中,除了使用sayName()方法之外,没有其他办法访问name的值。
关于JavaScript中的创建对象的学习总结的更多相关文章
- JavaScript 中 关于 this 的学习笔记
今天上午主要学习了js中的 this ,因为之前学习面向对象时,this这个东西出现的还是很频繁的,理解的很不透彻,感觉老被JAVA的思想带进坑里,所以对它特别关注. 首先贴一个大神的一篇博客,我是通 ...
- JavaScript中关于创建对象的笔记
1,最基本的两种创建对象的方式:构造函数|| 字面量 构造函数: var person = new Object(); person.name = "chen1zee1"; per ...
- Javascript中回调函数的学习笔记
function a_b(kkis){ document.body.style.background ='red'; kkis(); } function fli(){ alert('######## ...
- 详解JavaScript中的Object对象
Object是在javascript中一个被我们经常使用的类型,而且JS中的所有对象都是继承自Object对象的.虽说我们平时只是简单地使用了Object对象来存储数据,并没有使用到太多其他功能,但是 ...
- 全面理解Javascript中Promise
全面理解Javascript中Promise 最近在学习Promise的时候,在网上收集了一些资料,发现很多的知识点不够系统,所以小编特意为大家整理了一些自认为 比较好的文章,供大家更好地学习js中非 ...
- Javascript中的Object对象
Object是在javascript中一个被我们经常使用的类型,而且JS中的所有对象都是继承自Object对象的.虽说我们平时只是简单地使用了Object对象来存储数据,并没有使用到太多其他功能,但是 ...
- 深入理解JavaScript中创建对象模式的演变(原型)
深入理解JavaScript中创建对象模式的演变(原型) 创建对象的模式多种多样,但是各种模式又有怎样的利弊呢?有没有一种最为完美的模式呢?下面我将就以下几个方面来分析创建对象的几种模式: Objec ...
- Javascript中String对象的的简单学习
第十一课String对象介绍1:属性 在javascript中可以用单引号,或者双引号括起来的一个字符当作 一个字符对象的实例,所以可以在某个字符串后再加上.去调用String 对象 ...
- Javascript学习1 - Javascript中的类型对象
原文:Javascript学习1 - Javascript中的类型对象 1.1关于Numbers对象. 常用的方法:number.toString() 不用具体介绍,把数字转换为字符串,相应的还有一个 ...
随机推荐
- 深入理解css中的margin属性
深入理解css中的margin属性 之前我一直认为margin属性是一个非常简单的属性,但是最近做项目时遇到了一些问题,才发现margin属性还是有一些“坑”的,下面我会介绍margin的基本知识以及 ...
- e_msg_c_gs_enter_gs_req
e_msg_c_gs_enter_gs_req 就是到GS上验证客户端发送的token是否存在,如果存在返回成功,并把该token删除
- 注释(Annotation)
J2SE 5.0提供了很多新的特征.其中一个很重要的特征就是对元数据(Metadata)的支持.在J2SE 5.0中,这种元数据称为注释(Annotation).通过使用注释,程序开发人员可以在不改变 ...
- C++中public,protected,private派生类继承问题和访问权限问题
C++中public,protected,private派生类继承问题和访问权限问题 当一个子类从父类继承时,父类的所有成员成为子类的成员,此时对父类成员的访问状态由继承时使用的继承限定符决定. 1. ...
- imageserver
https://bitbucket.org/tamtam-nl/tamtam-nuget-imageserver/overview https://www.nuget.org/packages/Tam ...
- osharp3 操作日志之数据日志 控制增强
osharp3 原来的数据日志,有配置文件中有这总开关,DataLoggingEnabled,原来的程序是,这个总开关关了,就无法记录数据日志了,,如果开了,,他不管记录不记录数据日志,系统都会存数据 ...
- PetaPoco dynamic
PetaPoco最初的灵感来自Massive-通过dynamic Expando objects返回一切.对于大多数情况我觉得这比较麻烦,更喜欢强类型的类.但是有些时候支持dynamic也是有用的-特 ...
- Haproxy安装配置及日志输出问题
简介: 软件负载均衡一般通过两种方式来实现:基于操作系统的软负载实现和基于第三方应用的软负载实现.LVS就是基于Linux操作系统实现的一种软负载,HAProxy就是开源的并且基于第三应用实现的软负载 ...
- git push.default is unset
warning: push.default is unset; its implicit value is changing inGit 2.0 from 'matching' to 'simple' ...
- python快排算法
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列. ...