博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
面向对象与原型4---原型
阅读量:7016 次
发布时间:2019-06-28

本文共 3381 字,大约阅读时间需要 11 分钟。

原型模式创建对象也有自己的缺点,它省略了构造函数传参初始化这一过程,带来的缺

点就是初始化的值都是一致的。而原型最大的缺点就是它最大的优点,那就是共享。
原型中所有属性是被很多实例共享的,共享对于函数非常合适,对于包含基本值的属性
也还可以。但如果属性包含引用类型,就存在一定的问题:

1.

//原型的缺点

function Box() {};

Box.prototype = {
constructor : Box,
name : 'Lee',
age : 100,
family : ['父亲', '母亲', '妹妹'], //添加了一个数组属性
run : function () {
return this.name + this.age + this.family;
}
};
var box1 = new Box();

alert(box1.name);  // Lee  假设你想输出Jack 是无法输出Jack  第一个缺点

alert(box1.family);  //父亲 母亲 妹妹

box1.family.push('哥哥'); //在实例中添加'哥哥'    在第一个实例box1修改后,引用类型保持了共享

alert(box1.family);  //父亲 母亲 妹妹 哥哥

var box2 = new Box();
alert(box2.family);  //父亲 母亲 妹妹 哥哥   共享了box1添加后的引用类型的原型,共享带来的麻烦,也有'哥哥'了  第二个缺点
PS:数据共享的缘故,导致很多开发者放弃使用原型,因为每次实例化出的数据需要
保留自己的特性,而不能共享。

2.

为了解决构造传参和共享问题,可以组合构造函数+原型模式:我需要独立的部分使用构造函数,我需要共享的部分使用原型

function Box(name, age) { //不共享的、保持独立的,使用构造函数

this.name = name;
this.age = age;
this. family = ['父亲', '母亲', '妹妹'];
};
Box.prototype = { //共享的使用原型模式
constructor : Box,
run : function () {
return this.name + this.age + this.family;
}
};

var box1=new Box('Lee',100);

alert(box1.run());  //Lee100

var box2=new Box('Jack',200);

alert(box2.run());  //Jack200

alert(box1.family);  //父亲  母亲 妹妹

box1.family.push('弟弟')

alert(box1.family);  //父亲  母亲 妹妹 弟弟

alert(box2.family);  //父亲  母亲 妹妹  引用类型没有使用原型,所以没有共享

PS:这种混合模式很好的解决了传参和引用共享的大难题。是创建对象比较好的方法。

3. 封装起来

原型模式,不管你是否调用了原型中的共享方法,它都会初始化原型中的方法,并且在

声明一个对象时,构造函数+原型部分让人感觉又很怪异,最好就是把构造函数和原型封装
到一起。为了解决这个问题,我们可以使用动态原型模式。

//动态原型模式

//可以 将原型封装到构造函数里

function Box(name ,age) { //将所有信息封装到函数体内

this.name = name;
this.age = age;

alert('原型初试化开始');

Box.prototype.run = function () {
return this.name + this.age + '运行中...';
};

alert('原型初试化结束');

}
var box1 = new Box('Lee', 100);

var box2 = new Box('Lee', 100);

刷新浏览器会依次出现:

原型初试化开始  原型初试化结束   原型初试化开始  原型初试化结束

说明原型初始化了两次。但是原型的初始化,只要第一次初始化就可以了,没有必要每次构造函数实例化的时候都初始化

//解决方式如下:仅在第一次调用的时候初始化  

function Box(name ,age) { //将所有信息封装到函数体内
this.name = name;
this.age = age;
if (typeof this.run != 'function') { //仅在第一次调用的初始化  判断this.run 是否存在

alert('原型初试化开始');

Box.prototype.run = function () {
return this.name + this.age + '运行中...';
};

alert('原型初试化结束');

}
}

var box1 = new Box('Lee', 100);

var box2 = new Box('Lee', 100);

刷新浏览器会依次出现:

原型初试化开始  原型初试化结束  

说明两次实例化,原型初始化了1次

当第一次调用构造函数时,run()方法发现不存在,然后初始化原型。当第二次调用,就
不会初始化,并且第二次创建新对象,原型也不会再初始化了。这样及得到了封装,又实现
了原型方法共享,并且属性都保持独立。

PS:使用动态原型模式,要注意一点,不可以再使用字面量的方式重写原型,因为会

切断实例和新原型之间的联系。

4.

以上讲解了各种方式对象创建的方法,以上方法就够用了。如果这几种方式都不能满足需求,可以使用一开

始那种模式:寄生构造函数。

//寄生构造函数=工厂模式+构造函数

function Box(name, age) {

var obj = new Object();
obj.name = name;
obj.age = age;
obj.run = function () {
return this.name + this.age + '运行中...';
};
return obj;
}

var box1 = new Box('Lee',100);

var box2 = new Box('Jack',200);

alert(box1.run());

寄生构造函数,其实就是工厂模式+构造函数模式。这种模式比较通用,但不能确定对
象关系,所以,在可以使用之前所说的模式时,不建议使用此模式。

在什么情况下使用寄生构造函数比较合适呢?假设要创建一个具有额外方法的引用类

型。由于之前说明不建议直接 String.prototype.addstring,可以通过寄生构造的方式添加。
function myString(string) {
var str = new String(string);
str.addstring = function () {
return this + ',被添加了!';
};
return str;
}
var box = new myString('Lee'); //比直接在引用原型添加要繁琐好多
alert(box.addstring());

5.

在一些安全的环境中,比如禁止使用 this 和 new,这里的 this 是构造函数里不使用 this,

这里的 new 是在外部实例化构造函数时不使用 new。这种创建方式叫做稳妥构造函数。
function Box(name , age) {
var obj = new Object();
obj.run = function () {
return name + age + '运行中...'; //直接打印参数即可
};
return obj;
}
var box = Box('Lee', 100); //直接调用函数
alert(box.run());
PS:稳妥构造函数和寄生类似

转载于:https://www.cnblogs.com/mabelstyle/p/3720778.html

你可能感兴趣的文章
python中使用 xpath
查看>>
集中管理:领导者,不能不考虑的几件事之—— 拿什么辅助你,我的决策?(一)...
查看>>
关于VirtualBox虚拟机安装GhostXP出现蓝屏proce***.sys 的解决办法
查看>>
JSP如何在servlet将一个数据模型对象传递给jsp页面
查看>>
PHP 实现“贴吧神兽”验证码
查看>>
根据一个表的数据情况显示另一个表的数据
查看>>
TP4056大电流1A使用注意事项
查看>>
Java常考面试题(四)
查看>>
学习Javascript闭包(Closure)
查看>>
你性格那么软,总是经常改变想法
查看>>
NeHe OpenGL教程 第十七课:2D图像文字
查看>>
学习SpringMVC——从HelloWorld开始
查看>>
awk打印指定列以后的所有内容
查看>>
用 kGDB 调试 Linux 内核
查看>>
vuejs2.0子组件改变父组件的数据
查看>>
P1019 单词接龙
查看>>
git的版本回退探索
查看>>
H3c 配置ssh acl
查看>>
Dedecms判断当前栏目下是否有子栏目
查看>>
【PIC学习第2例】PIC16F877A LED闪烁
查看>>