惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Latest
Security Latest
Recorded Future
Recorded Future
人人都是产品经理
人人都是产品经理
S
SegmentFault 最新的问题
Hacker News - Newest:
Hacker News - Newest: "LLM"
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园 - 三生石上(FineUI控件)
博客园 - 聂微东
P
Privacy & Cybersecurity Law Blog
WordPress大学
WordPress大学
Know Your Adversary
Know Your Adversary
Spread Privacy
Spread Privacy
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
量子位
L
LINUX DO - 热门话题
L
Lohrmann on Cybersecurity
博客园 - Franky
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Tor Project blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
雷峰网
雷峰网
阮一峰的网络日志
阮一峰的网络日志
V
Visual Studio Blog
T
Threatpost
T
Tenable Blog
有赞技术团队
有赞技术团队
大猫的无限游戏
大猫的无限游戏
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI
C
Cisco Blogs
H
Heimdal Security Blog
Attack and Defense Labs
Attack and Defense Labs
A
About on SuperTechFans
Last Week in AI
Last Week in AI
N
News and Events Feed by Topic
T
Threat Research - Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
I
Intezer
V
V2EX
Cyberwarzone
Cyberwarzone
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
B
Blog RSS Feed
V
Vulnerabilities – Threatpost
N
Netflix TechBlog - Medium
T
The Blog of Author Tim Ferriss
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
U
Unit 42
PCI Perspectives
PCI Perspectives
P
Privacy International News Feed
D
Docker

博客园 - 匆匆

Grunt常见问题 一个小型的类库 HTML5常见问题 改版提示,新手指南 前端开发规范文档 常用正则表达式 JavaScript String 对象扩展方法 JavaScript String 对象常用方法 JavaScript Array 对象扩展方法 JavaScript Array 对象常用方法 JavaScript 常见基础问题二 JavaScript 常见基础问题一 JavaScript与网页性能 跨浏览器的本地存储解决方案 页面中添加事件、阻止事件传播、事件删除 常用CSS书写技巧 Gridview用法大总结(牛年珍藏版) 总结一些常用功能源码 JS类库
JavaScript 设计模式
匆匆 · 2012-12-16 · via 博客园 - 匆匆

1、工厂(Factory)模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。 考虑到ECMAScript中无法创建类,开发人员发明了这么一种函数,用函数来封装以特定接口创建对象的细节。 以下是例子,函数createPerson()能够根据接受的参数来构建一个包含所有必要信息的对象,可以无数次 地调用这个函数,而每次它都会返回一个包含三个属性和一个方法的对象。 工厂模式虽然解决了创建多个类似对象的问题,但却没有解决对象识别的问题(我们无法知道一个对象的类型)

function createPerson(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 person1 = createPerson('karl', 29, 'Software Engineer');
person1.sayName(); //karl
var person2 = createPerson('Jack', 35, 'Teacher');
person2.sayName(); // Jack

2、构造函数(constructor)模式:ECMAScript中的构造函数可用来创建特定类型的对象。在下面的案例中,先创建了一个新的对象, 然后将构造函数的作用域赋给新对象(this指向了新对象),再执行构造函数中的代码,最后返回新对象。person1和person2分别保存 着Person的一个不同的实例。这两个对象都有一个constructor属性,该属性指向Person。

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function () {
        console.log(this.name);
    }
}
var person1 = new Person('karl', 29, 'Software Engineer');
person1.sayName(); //karl
var person2 = new Person('Jack', 35, 'Teacher');
person2.sayName(); //Jack
console.log(person1.constructor == Person); //true
console.log(person2.constructor == Person); //true
console.log(person1.constructor == Object); //false
console.log(person2.constructor == Object); //false
console.log(person1 instanceof Object); //true
console.log(person1 instanceof Person); //true
console.log(person2 instanceof Object); //true
console.log(person2 instanceof Person); //true

构造函数的缺点是:每个方法都要在每个实例 上重新创建一遍。ECMAScript中的函数就是对象,因此每定义一个函数,就是实例化了一个对象。从逻辑角度讲,此时的构造函数也可以这样定义。

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = new Function('console.log(this.name)');
}

 从这个角度来看构造函数,更容易明白每个Person实例都包含了一个不同的Function实例,以下的代码可以证明这一点。

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

 3、原型(prototype)模式:我们创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象, 而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法,通俗地说,prototype就是通过调用构造函数 而创建的那个对象实例的原型对象。使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。换句话说, 不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中,如下面的例子所示。

function Person() { }
Person.prototype.name = 'karl';
Person.prototype.age = 29;
Person.prototype.job = 'software engineer';
Person.prototype.sayName = function () {
    console.log(this.name);
};
var person1=new Person();
person1.sayName(); //karl
var person2=new Person();
person2.sayName(); //karl

在此,我们将sayName()方法和所有的属性直接添加到了Person的prototype属性中,构造函数变成了空函数。 即便如此,也仍然可以通过调用构造函数来创建新对象,而且新对象还会具有相同的属性和方法。但与构造函数不同的是, 这些属性和方法是由所有实例共享的。所以,person1和person2访问的都是同一组属性和同一个sayName()方法。

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

原型模式的缺点,第一:原型模式省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值。 第二:原型中所有属性是被很多实例共享的,这种共享对于函数非常合适。对于那些包含基本值的属性倒也说得过去,毕竟通过 在实例上添加一个同名属性,可以隐藏原型中的对应属性。然而,对于包含引用类型值的属性来说,问题就很突出了。

function Person() { }
Person.prototype = {
    constructor: Person,
    name: 'karl',
    friends: ['Jack', 'Bill'],
    sayName: function () {
        console.log(this.name);
    }
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push('John');
console.log(person1.friends); //['Jack', 'Bill', 'John']
console.log(person2.friends); //['Jack', 'Bill', 'John']
console.log(person1.friends == person2.friends) //true;

 如果实例中添加了同名属性,可以隐藏原型中的对应属性。

function Person() { }
Person.prototype = {
    constructor: Person,
    name: 'karl',
    friends: ['Jack', 'Bill'],
    sayName: function () {
        console.log(this.name);
    }
};
var person1 = new Person();
var person2 = new Person();
person1.name = 'Bob';
person1.friends = [];
person1.sayName = function () { };
console.log(person1.friends); //[]
console.log(person2.friends); //['Jack', 'Bill']
console.log(person1.name == person2.name) //false;
console.log(person1.friends == person2.friends) //false;
console.log(person1.friends == person2.friends) //false;

 4、组合使用构造函数和原型模式,是创建自定义类型的最常见方式。构造函数用于定义实例属性,而原型模式用于 定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地 节省了内存。另外,这种混成模式还支持向构造函数传递参数;可谓集两种模式之长。这种构造函数和原型运城的模式, 是目前在ECMAScript中使用最广泛、认同度最高的一种创建自定义类型的方法。

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['Jack', 'Bill'];
}
Person.prototype = {
    constructor: Person,
    sayName: function () {
        console.log(this.name);
    }
};
var person1 = new Person('karl', 29, 'software engineer');
var person2 = new Person('John', 30, 'doctor');
person1.friends.push('van');
console.log(person1.friends); //['Jack', 'Bill', 'van']
console.log(person2.friends); //['Jack', 'Bill']
console.log(person1.friends == person2.friends); //false
console.log(person1.sayName == person2.sayName); //true