时间:2021-05-25
工厂模式
function createPerson(name, age){ var o = new Object(); // 创建一个对象 o.name = name; o.age = age; o.sayName = function(){ console.log(this.name) } return o; // 返回这个对象}var person1 = createPerson('ccc', 18)var person2 = createPerson('www', 18)工厂函数的问题:
工厂模式虽然解决了创建多个相似对象的问题,但是没有解决对象识别问题(即怎样知道一个对象的类型)。如下
构造函数模式
function Person(name , age){ this.name = name; this.age = age; this.sayName = function(){ console.log(this.name) }}var person1 = new Person('ccc', 18)var person2 = new Person('www', 18)person1.sayName() // --> 'ccc'person1 和person2 分别保存着Person的一个不同的实例。这两个对象都有一个constructor(构造函数)属性指向Person。这正是构造函数模式胜过工厂模式的地方。如下:
console.log(person1 instanceof Person) // --> trueconsole.log(person1 instanceof Object) // --> trueconsole.log(person2 instanceof Person) // --> trueconsole.log(person2 instanceof Object) // --> true构造函数模式与工厂模式的区别:
要创建Person的新实例,必须使用new操作符。以这种方式调用构造函数实际上会经历一下4个步骤:
构造函数的问题:
使用构造函数的重要问题,就是每个方法都要在每个实例上重新创建一遍。person1和person2中都有一个名为sayName()的方法,但那两个方法不是同一个Function实例。因为在ECMAscript中函数就是对象,因此每定义一个函数,也就是实例化了一个对象。从逻辑角度上讲,此时的构造函数也可以你这样定义:
function Person(name , age){ this.name = name; this.age = age; this.sayName = new Function('console.log(this.name)') // eslint: The Function constructor is eval. (no-new-func)}这会导致,创建的不同的实例上的同名函数是不相等的,比如:console.log(person1.sayName() === person2.sayName()) // -->false,然而创建两个完全相同的任务的Function实例是没有必要的。可以通过把函数定义转移到构造函数外部来解决这个问题。
function Person(name , age){ this.name = name; this.age = age; this.sayName = sayName}function sayName(){ console.log(this.name)}var person1 = new Person('ccc', 18)var person2 = new Person('www', 18)这样,由于sayName包含的是一个指向函数的指针,因此person1和person2对象就共享了在全局作用域中定义的同一个sayName()函数。这样做确实解决了两个函数做同一件事的问题,可是新问题又来了:在全局作用域中定义的函数实际上只能被某个对象调用,这让全局作用域有点名不副实。
带来的新问题:
如果对象需要定义很多方法,那么就要定义很多个全局函数,于是我们这个自定义的引用类型就丝毫没有封装性可言。
原型模式
关于原型,原型链内容不在此描述,只讨论原型设计模式
我们创建的每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。即不必在构造函数中定义对象实例的信息,而是将这些信息直接添加到原型对象中。
原型模式的问题:
它省略了为构造函数传递参数初始化参数的环节,结果所有的实例在默认情况下都将取得相同的属性值。另外,原型模式的最大问题是由其共享的本性所导致的。看如下问题:
function Person(){}Person.prototype = { constructor: Person, name: 'ccc', age: 18, friends:['www', 'aaa'], sayName: function () { console.log(this.name) }}var person1 = new Person()var person2 = new Person()person1.friends.push('bbb')console.log(person1.friends) // --> ["www", "aaa", "bbb"]console.log(person2.friends) // --> ["www", "aaa", "bbb"]console.log(person1.friends === person2.friends) // --> true带来的新问题:
如果我们的初衷就是这样,所有的实例共用一个数组,那么这个结果就是想要的。可是,实例一般都是要有属于自己的全部属性的,这个问题正是我们很少看到有人单独使用原型模式的原因所在。
组合使用构造函数模式和原型模式
创建自定义类型的最常见方式,就是组合使用构造函数模式与原型模式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。这种方式还支持向构造函数传递参数。
function Person(name, age){ this.name = name; this.age = age; this.friends = ['aaa', 'bbb']}Person.prototype = { constructor: Person, sayName: function(){ console.log(this.name) }}var person1 = new Person('ccc', 18)var person2 = new Person('www', 18)person1.friends.push('ddd')console.log(person1.friends) // --> ["aaa", "bbb", "ddd"]console.log(person2.friends) // --> ["aaa", "bbb"]console.log(person1.friends === person2.friends) // --> falseconsole.log(person1.sayName === person2.sayName) // --> true这种构造函数与原型混成的模式,是目前ECMAscript中使用最广泛、认同度最高的一种创建自定义类型的方法。可以说,这是用来定义引用类型的一种默认方式。
动态原型模式
动态原型模式就是可以通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型。
function Person(name, age){ // 属性 this.name = name this.age = age // 方法 if(typeof this.sayName !== 'function'){ Person.prototype.sayName = function(){ console.log(this.name) } }}var person1 = new Person('ccc', 18)person1.sayName() // --> ccc这里只有在sayName()方法不存在的情况下,才会将它添加到原型中。这段代码只会在初次调用构造函数时才会执行。
注意:
其它模式
还有寄生构造函数模式和稳妥构造函数模式,可自行了解。以上所以知识内容来自《JavaScript高级程序设计》(第三版)。
以上就是详解js中的几种常用设计模式的详细内容,更多关于JS 设计模式的资料请关注其它相关文章!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
整理一下js面向对象中的封装和继承。1.封装 js中封装有很多种实现方式,这里列出常用的几种。1.1原始模式生成对象 直接将我们的成员写入对象中,用函数
参照prototype.js中getElementsByClassName的思想,扩展出几种在DEOM操作中可经常用到的获取对象的方法,使用获取对象变得更方便、
MySQL设计和命令行模式下建立详解系列文章:MySQL设计和命令行模式下建立详解C++利用MySQLAPI连接和操作数据库实例详解1.数据表的设计MySQL数
参考阅读:详解js中Number()、parseInt()和parseFloat()的区别详解JS转换数值函数Number()、parseInt()、parse
本文实例讲述了JS几个常用的函数和对象定义与用法。分享给大家供大家参考,具体如下:js几种常见的函数//string类中的函数varstr="clannad";