JS面向对象的程序设计_创建对象之组合使用模式-2

2018-10-14 admin

1. 组合使用构造函数模式和原型模式

创建自定义类型的最常见方式,就是组合使用构造函数模式与原型模式。

构造函数,用于定义实例对象的属性。

原型模式,用于定义方法和共享的属性。

这样的话, 每个实例对象都有属于自己属性的一份副本, 但同时又共享着对方法的引用,最大程度地节省了内存。

这种混合模式还支持向构造函数传递参数, 可谓集两种模式之长。

//构造函数模式与原型模式, 应用示例

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Sharon", "Sandy"];
}

Person.prototype = {
    constructor: Person,
    sayName: function(){
        console.log(this.name);
    }
}

var person1 = new Person("Shaw", 28, "Designer");
var person2 = new Person("Roc", 27, "Doctor");

console.log(person1.sayName()); // "Shaw"
console.log(person2.sayName()); // "Roc"

person1.friends.push("Vans");

console.log(person1.friends); // ["Sharon", "Sandy", "Vans"]
console.log(person2.friends); // ["Sharon", "Sandy"]

console.log(person1.friends === person2.friends); // false
console.log(person1.sayName === person2.sayName); // true

在这个例子中,实例对象的属性都是在构造函数中定义的, 所有实例对象共享的属性constructor和sayName()方法则是在原型中定义的。 修改person1.friends并不会影响到person2.friends, 因为person1和person2实例对象分别引用不同的数组。

==这种构造函数与原型模式混合使用的模式,是目前在ECMAScript中使用最广泛、认同度最高的一种创建自定义类型的方法。 可以说, 这是定义引用类型的一种默认模式。==

2. 动态原型模式

有其他OO语言经验的开发人员在看到独立的构造函数和原型时,很可能会感觉到困惑。

动态原型模式正是致力于解决这个问题的一个方案,它把所有信息都封装在了构造函数中。

通过在构造函数中初始化原型(在一些必要的情况下),又保持了同时使用构造函数和原型的优点。

==换句话说,可以通过检查某个存在的方法是否有效, 来决定是否需要初始化原型。==

//动态原型模式示例代码

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    if(typeof this.sayName != 'function') {
        Person.prototype.sayName = function() {
            console.log(this.name);
        }
    }
}
4
var person1 = new Person("Shaw", 18, "Designer");
person1.sayName(); // "Shaw"

注意构造函数代码中的这一部分。


if(typeof this.sayName != 'function') {
    Person.prototype.sayName = function() {
        console.log(this.name);
    }
}

没有像原型模式一样,显式的定义原型的属性和方法。而是调用构造函数时才会完全原型的初始化。

如:

function Person(){
}

Person.prototype.sayName = function() {
    console.log(this.name);
}

这段代码只会在初次调用构造函数时才会执行。此后,原型完成初始化,不需要在做什么修改了。 不够要记住,这里对原型所做的修改,能够立即在所有实例对象中得到反映。 因此,这种做法可以说非常完美。 其中if语句检查的可以是初始化之后,应该存在的任何属性或方法- 不必用一大堆if语句检查每个属性和方法; 只需要检查其中一个即可。

对于采用这种模式创建的对象,还可以使用instanceof操作符确定它的类型。

注意: 使用动态原型模式,不能使用对象字面量重写原型。 如果在已经创建了实例对象的情况重写原型,那么会切断已经创建的实例对象与新原型之间的联系。

3. 寄生构造函数模式(不建议使用)

通常,在前述的几种模式都不适用的情况下,可以使用(parasitic)构造函数模式。

这种模式的基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后返回新创建的对象。

从表面上看,这个函数又很像是典型的构造函数。


function Person(name, age, job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        console.log(this.name);
    }
    return o;
}

var friend = new Person("Shaw", 18, "Engineer");

friend.sayName(); // "Shaw"

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

除了使用new操作符,并把使用的包装函数叫做构造函数之外,这个模式跟工厂模式是一模一样的。

构造函数在不返回值的情况下,使用new操作符,默认返回一个实例对象。

而通过在构造函数的末尾添加一个return语句, new操作符 + 构造函数 可以重写返回的值。


这个模式可以在特殊的情况下用来为对象创建构造函数。

假设我们想创建一个具有额外方法的特殊数组。

由于不能直接修改Array构造函数, 因此可以使用这个模式。

function SpecialArray() {

    var values = new Array();

    values.push.apply(values, arguments);

    values.toPipedString = function() {
        return this.join("|");
    }

    return values;

}

var colors = new SpecialArray("red", "blue", "green");

console.log(colors.toPipedString()); //red|blue|green

在这个例子中,我们创建了一个名叫SpecialArray的构造函数。

在这个构造函数内部,首先创建了一个数组,然后push()方法(用构造函数接收到的所有参数)初始化了数组的值。

虽然又给数组添加了一个toPipedString()方法, 该方法返回以竖线分隔的数组值。

最后返回整个数组。( [arguments, toPipedString: ƒ]

接着,我们调用了SpecialArray构造函数,向其中传入了用于初始化数组的参数。([“red”, “blue”, “green”, toPipedString: ƒ])。

最后,调用了toPipedString()方法。

==关于寄生构造函数模式,需要注意:==

返回的对象与构造函数或构造函数的原型没有关系。 也就是说,寄生构造函数模式下,构造函数创建的对象与在构造函数外创建的对象没有什么不同。

所以不能依赖instanceof操作符来确定对象的类型。

由于存在上述问题,我们建议在可以使用其他模式的情况下,不要使用这种模式。

4. 稳妥构造函数模式

道格拉斯 克罗克福德(Douglas Crockford)famine了JavaScript中的稳妥对象(durable objects)这一概念。

所谓稳妥对象, 指的是没有公共属性,而且其方法也不引用this的对象。

稳妥对象最适合在一些安全的环境中(这些环境中会禁止使用this和new),或者在防止数据被其他应用程序(如Mashup 程序)改动时使用。

稳妥构造函数,遵循与寄生构造函数类似的模式,但有两点不同:

  • 新创建对象的实例方法不引用this;
  • 不使用new操作符调用构造函数。

按照稳妥构造函数的要求,可以将前面的Person构造函数重写如下

function Person(name, age, job) {
    //创建要返回的对象
    var o = new Object();

    //可以在这里定义私有变量和函数

    //添加方法
    o.sayName = function() {
        console.log(name);
    }

    //返回对象
    return o;
}

var friend = Person("Shaw", 18, "Designer");

friend.sayName(); // "Shaw"

注意,以这种模式创建的对象中,除了使用sayName()方法之外,没有其他方法访问name的值。

这样,变量friend中保存的是一个稳妥对象。

即使有其他代码会给这个对象添加方法或数据成员,但也不可能有别的办法访问传入到构造函数中的原始数据。

稳妥构造函数模式提供的这种安全性,使得他非常适合在某些安全执行环境-例如,ADsafe(www.adsafe.org)和Caja (http://code.google.com/p/goog…) 提供的环境下使用。

与寄生构造函数模式类似,使用稳妥构造函数模式创建的对象与构造函数之间也没有什么关系,因此instanceof操作符对这种对象也没有意义。

原文链接:https://segmentfault.com/a/1190000016674347

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-42624.html

文章标题:JS面向对象的程序设计_创建对象之组合使用模式-2

相关文章
bootstrap PrintThis打印插件使用详解
bootstrap PrintThis打印效果图: 如图,这个是调用了谷歌的打印,使用很方便,可以自己調样式,需要的可以研究一下,这边贴出使用方法。 附上GitHub:https://github.com/jasonday/printTh...
2017-03-16
为什么要选择Nodejs?Nodejs有什么好处?
什么?JavaScript还能用作服务器编程! Caleb Madrigal是来自美国密尔沃基市的一名软件顾问。四年前,他在听说“将JavaScript用作服务器端语言”这样的说法时,认为那是一个荒唐的想法。有那么多服务器端语言可供选择,为...
2015-11-12
js性能优化 如何更快速加载你的JavaScript页面
确保代码尽量简洁 不要什么都依赖JavaScript。不要编写重复性的脚本。要把JavaScript当作糖果工具,只是起到美化作用。别给你的网站添加大量的JavaScript代码。只有必要的时候用一下。只有确实能改善用户体验的时候用一下。 ...
2015-11-12
10个强大的纯CSS3动画案例分享
我们的网页外观主要由CSS控制,编写CSS代码可以任意改变我们的网页布局以及网页内容的样式。CSS3的出现,更是可以让网页增添了不少动画元素,让我们的网页变得更加生动有趣,并且更易于交互。本文分享了10个非常炫酷的CSS3动画案例,希望大家...
2015-11-16
2015年JavaScript或“亲库而远框架”
2014年过去了,作为一个JavaScript开发者很难满怀信心的去“挽回”一个特定的库或技术,即便是强大的Angular,似乎也因为最近的一些事情而动摇。 2014年10月的ng-europe会议上,Angular开发者团队透露了一个关于...
2015-11-12
Node.js 2014这一年发生了什么
Node.js 的 2014 年充满了不幸和争议. 这一年 Noder 们经历了太多的伤心事, 经历了漫长的等待, 经历了沉重的分裂之痛. 也许 Noder 们不想回忆14年 Node.js land 发生的事情, 但正因为痛才更有铭记的价...
2015-11-12
Angular2-primeNG文件上传模块FileUpload使用详解
近期在学习使用Angular2做小项目,期间用到很多primeNG的模块。 本系列将结合实战总结angular2-primeNG各个模块的使用经验。 文件上传模块FileUploadModule 首先要在使用该组件的模块内导入文件上传模块 ...
2017-03-09
React.js编程思想
JavaScript框架层出不穷,在很多程序员看来,React.js是创建大型、快速的Web应用的最好方式。这一款由Facebook出品的JS框架,无论是在Facebook还是在Instagram中,它的表现都非常出色。 使用React.j...
2015-11-12
YouTube正式默认使用HTML5视频播放器
YouTube视频网站现在默认使用HTML5播放器,这意味着更好的性能、 稳定性、 电池寿命和甚至是更好的安全性。现在用户通过Chrome、IE 11、Safari 8和Beta版本的Firefox进行浏览的时候都默认使用HTML5视频播放...
2015-11-12
css布局的各种FC简单介绍:BFC,IFC,GFC,FFC
什么是FC? Formatting Context,格式化上下文,指页面中一个渲染区域,拥有一套渲染规则,它决定了其子元素如何定位,以及与其他元素的相互关系和作用。 BFC 什么是BFC Block Formatting Context,块...
2018-05-17
回到顶部