JavaScript之面向对象学习七(动态原型模式、寄生构造函数模式、稳妥构造函数模式创建自定义类型)
一、动态原型模式
在面向对象学习六中的随笔中,了解到组合构造函数模式和原型模式创建的自定义类型可能最完善的!但是人无完人,代码亦是如此!
有其他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之面向对象学习七(动态原型模式、寄生构造函数模式、稳妥构造函数模式创建自定义类型)的更多相关文章
- JavaScript之面向对象学习六原型模式创建对象的问题,组合使用构造函数模式和原型模式创建对象
一.仔细分析前面的原型模式创建对象的方法,发现原型模式创建对象,也存在一些问题,如下: 1.它省略了为构造函数传递初始化参数这个环节,结果所有实例在默认的情况下都将取得相同的属性值,这还不是最大的问题 ...
- JavaScript之面向对象学习五(JS原生引用类型Array、Object、String等等)的原型对象介绍
1.原型模式的重要性不仅仅体现在创建自定义类型方面,就连所有的原生的引用类型(Obejct.Array.String等等)都在构造函数的原型上定义方法和属性.如下代码可以证明: alert(typeo ...
- JavaScript之面向对象学习一
1.通过Object构造函数和对象字面量来创建对象缺点:使用同一个接口创建很多的对象,会产生大量的重复代码.比如我需要创建人的对象,并且需要三类人,医生.工程师.老师,他们可以抽象出很多属性,比如姓名 ...
- JavaScript之面向对象学习八(继承)
简介:继承是OO语言中的一个最为人津津乐道的概念.许多OO语言都支持两种继承方式:接口继承和实现继承.接口继承只继承方法签名,而实现继承则继承实际的方法. 但是JS的函数并没有签名,所以在ECMASc ...
- PHP面向对象学习-属性 类常量 类的自动加载 构造函数和析构函数 访问控制(可见性)
在类的成员方法里面,可以用 ->(对象运算符):$this->property(其中 property 是该属性名)这种方式来访问非静态属性.静态属性则是用 ::(双冒号):self::$ ...
- JavaScript之面向对象学习二(原型属性对象与in操作符)获取对象中所有属性的方法
1.原型属性对象于in操作符之in单独使用 有两种方式使用in操作符:单独使用和在for-in循环中使用.在单独使用中,代码如下: function Person(){ } Person.protot ...
- JavaScript之面向对象学习四原型对象的动态性
1.由于在原型中查找值的过程是一次搜索,因此我们对原型对象所做的任何修改都能够立即从实例上反映出来---即便是先创建了实例后修改原型也是如此.代码如下: function Person(){ } va ...
- JavaScript之面向对象学习三原型语法升级
1.到目前为止,我们是时候分析下前面的使用原型语法来定义对象有哪些不足的地方,代码如下: function Person(){ } Person.prototype.name="张三&quo ...
- PHP面向对象学习七 总结
1.对象描述的配置 方法名 __tostring() 我们可以直接打印对象句柄,从而获得该方法的基本信息或其他内容. class My{ function __tostring ( ){ echo & ...
随机推荐
- docker 容器管理常用命令
Docker 容器管理: docker create -it centos //这样可以创建一个容器,但该容器并没有启动: create Create a new container 创建一个容器: ...
- 服务器:RAID、AHCI、IDE
RAID 独立磁盘冗余阵列(RAID,redundant array of independent disks)是把相同的数据存储在多个硬盘的不同的地方(因此,冗余地)的方法.通过把数据放在多个硬盘上 ...
- C# 类型的创建
类 类是最普通的引用类型,最简单的声明如下所示: class YourNameClass { } 更复杂的类可以拥有以下这些选项: 置于关键字class前面的:属性(attributes)与class ...
- 随滚动条滚动的居中div
<!-- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...
- html系列教程--nav noscript option optgroup object
<nav> 标签:html5用来定义导航部分的标签,与div无异,html5推荐用nav. <noframes> 标签:定义当浏览器不支持frameset时显示的提示性语言 d ...
- 理解JS闭包
从事web开发工作,尤其主要是做服务器端开发的,难免会对客户端语言JavaScript一些概念有些似懂非懂的,甚至仅停留在实现功能的层面上,接下来的文章,是记录我对JavaScript的一些概念的理解 ...
- java.lang.ArithmeticException: / by zero
- PO状态为“处理中”的处理方法
EBS中经常会出现PO提交审批后状态为“处理中”的情况,此时PO创建人无法打开,审批人也无法打开,工作流等查看也无异常,可以使用一下SQL处理再进行审批: --set serveroutput on ...
- JAVA 初识类加载机制 第13节
JAVA 初识类加载机制 第13节 从这章开始,我们就进入虚拟机类加载机制的学习了.那么什么是类加载呢?当我们写完一个Java类的时候,并不是直接就可以运行的,它还要编译成.class文件,再由虚拟机 ...
- EC读书笔记系列之6:条款11 在operator=中处理自我赋值
记住: ★确保当对象自我赋值时operator=有良好行为.有三种方法:比较“来源对象”和“目标对象”的地址.精心周到的语句顺序.以及copy-and-swap技术 ★确定任何函数若操作一个以上对象, ...