一、动态原型模式

在面向对象学习六中的随笔中,了解到组合构造函数模式和原型模式创建的自定义类型可能最完善的!但是人无完人,代码亦是如此!

有其他oo语言经验的开发人员在看到独立的构造函数和原型时,很可能会感到非常困惑。因为对象在其他oo语言中往往是封装在一块的,而构造函数确是和原型分开的,所以并没有真正意义上的封装,所以动态原型模式正是致力与解决这一问题的一个方案!

动态原型模式将所有的信息都封装在构造函数中(包括原型和实例属性),通过在构造函数中实例化原型(仅在必要的情况下)实现封装,又保持了同时使用构造函数和原型的优点。

    function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
this.friends=["小超","大超"];
if(typeof this.sayName!="function") {//这段判断语句的作用是限制Person.prototype属性(原型属性对象)只生成一次,要不然每次实例化一个Person对象都会去写一遍原型对象
Person.prototype.sayName = function () {
alert(this.name);
}
Person.prototype.sayHello=function(){
alert("Hello");
}
}
}
var person=new Person("张三",22,"coder");
person.sayName();

注意:typeof this.sayName!="function" 中的this,因为创建Person构造函数时,会创建一个prototype属性,该属性实际上就是Person.prototype的原型对象,prototype属性是一个指针,指向Person.prototype的原型对象,所以构造函数拥有所有Person.prototype的原型对象的属性和方法,而创建Person.prototype圆形对象时,会生成一个constructor属性,该属性也是一个指针,指向Person构造函数,用于判断对象实例的类型!

因为Person构造函数够拥有Person.prototype的原型对象的所有属性和方法,所以可以用this判断原型中是否存在该方法!

当第一次实例化Person对象的时候,原型就已经完成初始化,所以当第二次实例化的时候,原型就不会初始化,而且if语句检查的可以是原型的任意属性和方法,不需要每一个都检查,只需要检查其中一个,对于采用这种模式创建的自定义类型,可以同时使用constructor和instanceof来检查他们的类型,代码如下:

    function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
this.friends=["小超","大超"];
if(typeof this.sayName!="function") { //这段判断语句的作用是限制Person.prototype属性(原型属性对象)只生成一次,要不然每次实例化一个Person对象都会去写一遍原型对象
Person.prototype.sayName = function () {
alert(this.name);
}
Person.prototype.sayHello=function(){
alert("Hello");
}
}
}
var person=new Person("张三",22,"coder");
var person1=new Person("李四",22,"coder");
alert(person.constructor); //输出: Person构造函数所对应的方法体
alert(person instanceof Person); //输出:true 说明person是Person对象的实例
alert(person.constructor==person1.constructor); //输出:true 说明两个实例的原型对象的constructor属性都指向Person构造函数即他们是同一类型

二、寄生构造函数模式

当你需要创建一个自定义类型的时候,当前面的随笔中的模式都不适用的情况下,可以使用寄生构造函数模式。这种模式的基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码。

代码如下:

//寄生构造函数模式
function Person(age,name) {
var o=new Object();
o.age=age;
o.name=name;
o.sayName=function(){
alert(this.name);
}
return o;
}
var person=new Person(22,"张三");
person.sayName(); //工厂模式
function createPeron(name,age,job){
var object=new Object();
object.name=name;
object.age=age;
object.job=job;
object.sayName=function(){
alert(this.name);
}
object.sayForm=function(){
alert(typeof this);
}
return object;
}
var person=createPeron("张三",22,"coder");
person.sayName();
person.sayForm();

在上面寄生模式的例子中,Person函数创建了一个新对象,并以相应的属性和方法初始化该对象,然后又返回这个对象。

然后分析其与工厂模式的区别:

1、寄生模式创建对象时使用了New关键字

2、寄生模式的外部包装函数是一个构造函数

除了上面这2个区别寄生模式和工厂模式几乎一样,构造函数在不返回值的情况下,默认返回对象的新实例。而通过在构造函数的末尾添加一个return 语句,可以重写调用构造函数是返回的值

作用:寄生模式可以在特殊的情况下为对象来创建构造函数,原因在于我们可以通过构造函数重写对象的值,并通过return返回  重写调用构造函数(创建的对象的实例)之后的对象实例的新的值。

假设我们想创建一个具有额外方法的特殊数组。由于不能直接修改Array构造函数,所以我们可以使用寄生模式。代码如下:

function SpecialArray() {
//创建数组
var array=new Array();
//添加值 arguments获取的是实参,不是形参,所以SpecialArray()并没有形参接收传递过来的参数
array.push.apply(array,arguments);
array.toPipedString=function(){
return this.join("|");
}
return array;
}
var colors=new SpecialArray("red","blue","black");
alert(colors.toPipedString()); //输出:red|blue|black

我们利用寄生构造函数模式,在不修改Array构造函数的情况下,通过为Array对象创建构造函数达到修改Array对象的目地;

在分析上面的代码:

1、var array=new Array();创建了一个Array对象

2、return array;在经过一系列的修改之后返回修改之后的Array对象

3、var colors=new SpecialArray("red","blue","black"); 创建了一个SpecialArray对象,接收的确是修改之后的Array对象的实例值

所以return array;返回的对象是Array类型,而且colors接收了这个返回的对象,所以colors并不是SpecialArray构造函数的实例,而是Array的实例,下面的代码可以说明:

alert(colors instanceof SpecialArray); //输出:false
alert(colors instanceof Array); //输出:true

所以,由于存在上述问题,如果能使用其他的模式的情况下,建议不要使用这种模式.

三、稳妥构造函数模式

道格拉斯 *  克罗克福德 发明了JavaScript中的稳妥对象这个概念.所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this的对象。稳妥对象最适合用在一些安全的环境中(这些环境会禁止使用new和this),或者防止数据被其他的应用改动。

稳妥构造函数与寄生构造函数模式类似,但是也有两点区别:

1、稳妥模式不使用new操作符调用构造函数

2、新创建对象的实例方法不引用this

其代码如下:

function Person(name,age) {
//创建要返回的对象
var o=new Object();
//可以在这里定义私有变量和函数
//添加方法
o.sayName=function(){
alert(name);
}
//返回对象
return o;
}
var person=Person("张三",22);
person.sayName(); //使用稳妥构造函数模式只能通过其构造函数内部的方法来获取里面的属性值

上面的代码定义了一个person变量,里面保存的是一个稳妥对象,而除了吊用他的sayName()方法外,没有别的方法可以访问其数据成员。即使有其他的代码会给这个对象添加方法和数据成员,但也不可能有别的方法访问到传入到构造函数中的原始数据。稳妥构造函数模式提供的这种安全性。是的它非常适合在某些安全执行环境中。

JavaScript之面向对象学习七(动态原型模式、寄生构造函数模式、稳妥构造函数模式创建自定义类型)的更多相关文章

  1. JavaScript之面向对象学习六原型模式创建对象的问题,组合使用构造函数模式和原型模式创建对象

    一.仔细分析前面的原型模式创建对象的方法,发现原型模式创建对象,也存在一些问题,如下: 1.它省略了为构造函数传递初始化参数这个环节,结果所有实例在默认的情况下都将取得相同的属性值,这还不是最大的问题 ...

  2. JavaScript之面向对象学习五(JS原生引用类型Array、Object、String等等)的原型对象介绍

    1.原型模式的重要性不仅仅体现在创建自定义类型方面,就连所有的原生的引用类型(Obejct.Array.String等等)都在构造函数的原型上定义方法和属性.如下代码可以证明: alert(typeo ...

  3. JavaScript之面向对象学习一

    1.通过Object构造函数和对象字面量来创建对象缺点:使用同一个接口创建很多的对象,会产生大量的重复代码.比如我需要创建人的对象,并且需要三类人,医生.工程师.老师,他们可以抽象出很多属性,比如姓名 ...

  4. JavaScript之面向对象学习八(继承)

    简介:继承是OO语言中的一个最为人津津乐道的概念.许多OO语言都支持两种继承方式:接口继承和实现继承.接口继承只继承方法签名,而实现继承则继承实际的方法. 但是JS的函数并没有签名,所以在ECMASc ...

  5. PHP面向对象学习-属性 类常量 类的自动加载 构造函数和析构函数 访问控制(可见性)

    在类的成员方法里面,可以用 ->(对象运算符):$this->property(其中 property 是该属性名)这种方式来访问非静态属性.静态属性则是用 ::(双冒号):self::$ ...

  6. JavaScript之面向对象学习二(原型属性对象与in操作符)获取对象中所有属性的方法

    1.原型属性对象于in操作符之in单独使用 有两种方式使用in操作符:单独使用和在for-in循环中使用.在单独使用中,代码如下: function Person(){ } Person.protot ...

  7. JavaScript之面向对象学习四原型对象的动态性

    1.由于在原型中查找值的过程是一次搜索,因此我们对原型对象所做的任何修改都能够立即从实例上反映出来---即便是先创建了实例后修改原型也是如此.代码如下: function Person(){ } va ...

  8. JavaScript之面向对象学习三原型语法升级

    1.到目前为止,我们是时候分析下前面的使用原型语法来定义对象有哪些不足的地方,代码如下: function Person(){ } Person.prototype.name="张三&quo ...

  9. PHP面向对象学习七 总结

    1.对象描述的配置 方法名 __tostring() 我们可以直接打印对象句柄,从而获得该方法的基本信息或其他内容. class My{ function __tostring ( ){ echo & ...

随机推荐

  1. Linux网络设备驱动架構學習(三)

    Linux网络设备驱动架構學習(三) 接下來會從以下幾個方面介紹網絡設備驅動的編寫流程: 1.網絡設備的註冊與註銷 2.網絡設備的初始化 3.網絡設備的打開與釋放 4.網絡數據發送流程 5.網絡數據接 ...

  2. Eclipse:使用findBugs预先检测错误

    FindBugs是用于Java的另一种静态分析工具,它在某些方面与Checkstyle和PMD类似,但是侧重点不同.FindBugs不关心格式或编码标准,对最佳实践也不太感兴趣:事实上,它专注于检查潜 ...

  3. hdu 2768

    求最大留下的观众,观众之间存在不能同时满足的关系,就是矛盾关系, 矛盾关系建边,建边是双向的所以最大匹配要/2 还有一种建图的方法:把观众分成两个集合,一个是投留下猫的,一个是投留下狗的 每个集合间没 ...

  4. 数据存储(三)--JSON数据处理

    JSON是一种轻量级的数据交换格式,具有良好的可读和便于高速编写的特性,从而能够在不同平台间进行数据交换.JSON採用兼容性非常高的文本格式,同一时候也具备类似于C语言体系的行为.JSON能够将Jav ...

  5. html系列教程--nav noscript option optgroup object

    <nav> 标签:html5用来定义导航部分的标签,与div无异,html5推荐用nav. <noframes> 标签:定义当浏览器不支持frameset时显示的提示性语言 d ...

  6. Myeclipse 常用操作(待补充)

    1.更改背景色 进入myeclipse工作区,选择window->Preferences->General->Editors->Text Editors->Backgro ...

  7. 图片延时加载jquery.inview.js用法详解

    我们在网站上总能见到这样的效果,若是有图片,图片都是先用loading加载一小段时间,然后紧接着出来要显示的图片,即效果如下: v2_loading.gif,几秒钟时间过渡到v2_pic_01_s.j ...

  8. 我用的php开发环境是appserv一键安装,通过http://localhost测试成功,但是我有点不清楚的就是为什么访问.php文件要在地址栏上加上localhost(即http://localhost/text.php)才能成功访问?

    这类似于一个域名地址. 因为默认localhost 就是指向本机.所以就用这个来访问自己本地的网页.比如你也可以输入 http://127.0.0.1/text.php http://192.168. ...

  9. 我来讲讲在c#中怎么进行xml文件操作吧,主要是讲解增删改查!

    我把我写的四种方法代码贴上来吧,照着写没啥问题. 注: <bookstore> <book> <Id>1</Id> <tate>2010-1 ...

  10. Pthon MySQLdb 的安装

    说明: 要用python 去连接MySQL我们需要一个驱动程序这个程序就是MySQL-python,所以我们首先就是要下一个对应版本的MySQL-python (注意这个驱动程序只有32位版本的,所以 ...