刚开始学习设计模式之前,我是没想说要学习设计模式的,我只是因为想学习JS中的原型prototype知识,一开始我想JS中为什么要存在原型这个东西?于是慢慢通过原型而接触到设计模式,后来发现我这个过程是非常正确的,即先学习设计模式,然后在剖析原型及其原理

我一开始,都是通过针对原型的知识点去看去学,发现还是理解不了,就算理解了原型,可以说只是停留在表面的知道,你并不懂得如何运用原型?后来,我通过用设计模式的角度去理解原型prototype,我才焕然大悟

但是在这一篇章里面,并没有说到原型、原型模式,因为如果你要进入设计模式的角度去理解原型,你就必须得了解一下用JS来实现单例模式、工厂模式和构造函数模式,看看Javascript是如果巧妙地实现各种设计模式。

    【单例模式】

var person1 = {
"name": "psg",
"age": 24
};
var person2 = {
"name": "fsf",
"age": 22
};
console.log(person1.name); // ->page
console.log(person1.age); // ->24
console.log(person2 .name); // ->fsf
console.log(person2 .age); // ->22

上面的person1与person2都不是基本数据类型,都是对象数据类型,对象数据类型的作用:把描述同一个事物(同一个对象)的属性和方法放在一个内存空间下,起到了分组的作用(例如person1与person2,都是两个独立开来的栈内存,里面的属性和方法互不影响) -> 于是,我们把这种分组编写代码的模式叫做“单例模式”。

    -> 在“单例模式”中,我们叫person1、person2叫做命名空间

单例模式是一种项目开发中经常使用的模式,因为项目中我们可以使用单例模式进行“模块化”开发。

命名空间的作用,看下面代码

// searchRender 是一个命名空间
var searchRender = {
change: function() {
this.clickEvent(); //这里this你暂时看不出来是谁,因为只有执行的时候,才知道
} ,
clickEvent: function() { }
};
// 但是想要使用searchRender里面的change方法,你必须如下调用
serachRender.clickEvent();
// 所以change方法里面的this,只能是searchRender

如果你学的比较深入,看上面的代码你就能看出命名空间的作用是什么了,就是能灵活运用this。

这里使用this的好处:当命名空间改名字的时候,你并不用改里面的调用者,因为this就代表命名空间。

总结

->单例模式解决了分组的问题

->但是单例模式的弊端也很明显,因为他仍然是手工作业模式,效率比较低,于是“工厂模式”就站出来解决了这个问题,因为工厂模式可以批量生产。

   【工厂模式】

function createJsPerson(name, age) {
var obj = {};
obj.name = name;
obj.age = age;
obj.writeJs = function() {
console.log("My name is " + this.name + ", i can write js.");
};
return obj;
}
var p1 = createJsPerson("psg", 24);
var p2 = createJsPerson("fsf", 22)
p1.writeJs(); // ->My name is psg, i can write js.
p2.writeJs(); // ->My name is fsf, i can write js.

这样写,可以减少重复代码的产出,你只需要写好公共的代码,把他放进一个方法里面,然后通过接受不同的参数,可以创建不同的对象,效率比单例模式高多了!

接下来,讲一下“构造函数模式”,它的样子跟“工厂模式”非常相似

【构造函数模式】

function CreateJsPerson(name, age) {
// var obj = {};
this.name = name;
this.age = age;
this.writeJs = function() {
console.log("My name is " + this.name + ", i can write js.");
}
// return obj;
}
var p = new CreateJsPerson("psg", 24);
p.writeJs(); // -> My name is psg, i can write js.

看到没有,CreateJsPerson这个方法,根本不会像工厂模式那样最后返回给你一个对象,它不需要,因为当你通过使用new关键字,浏览器会在后台中自己新建一个对象,然后通过this来指向该新建对象,最后自动默认返回一个对象给你

->其实我们有时也会不经意用到使用构造函数模式新进实例,例如创建一个数组

// 创建一个数组
var ary = []; // 字面量方式
var arry = new Array(); // 实例创建的方式-》构造函数模式执行的方式

  

->知识点一: 构造函数模式和工厂模式的区别?

1)执行的时候

普通函数执行 -> createJsPerson() -> 这时候,createJsPerson是一个普通函数名

构造函数模式 -> new CreateJsPerson() -> 通过new执行后,CreateJsPerson就是一个类 -> 开头大写是因为约定了,大写开头的函数就是表示一个类

new  出来的返回值(p),就是CreateJsPerson这个类的一个实例

2)在函数执行的时候

相同点 -> 都是形成私有作用域,然后形参赋值 -> 预解释 -> 代码从上到下执行(类和普通函数一样,它也有普通函数的一面)

不同点 -> 在代码执行之前, 不用自己再手动创建对象,浏览器会默认的创建一个对象数据类型的值(类的实例),并作为函数返回值自动返回。

->知识点二: 构造函数也是函数数据类型

在JS中,所有类都是函数数据类型,createJsPerson是函数数据类型, new CreateJsPerson也是函数数据类型,CreateJsPerson它通过new执行变成了一类,但它本身也是一个普通的函数。

但是,JS中所有类的实例都是对象数据类型。

 ->知识点三: 如果给构造函数里面添加私有变量,它返回值(实例)会存在此变量吗?

unction Fn() {
var num = 10;
}
var obj = new Fn;
console.log(num); // -> undefined
console.log(obj.num); // -> undefined

上面例子可以看出,这里的num只是函数私有作用域里面的一个私有变量,它跟实例没有任何关系。

 ->知识点四: 如果给构造函数直接返回一个对象,或者直接返回一个基本数据类型,那个实例到底还是不是浏览器默认返回的实例呢?

1)手动添加自动返回基本数据类型

function Fn() {
var num = 10;
return 100; // 代码无效
}
var f1 = new Fn;
console.log(f1); // -> Object,这个Object就是空的,也是浏览器默认返回的对象
// 也就是说,return 100 这句代码无效

2)手动添加自动返回对象数据类型

function Fn() {
var num = 10;
return {name: 'psg'}; // 代码有效
}
var f1 = new Fn;
console.log(f1); // -> Object,这个Object就是 {name: 'psg'}
// 也就是说,强制返回的手动添加的实例对象,完全KO覆盖掉浏览器默认返回的实例对象

总结上面两点在构造函数模式当中,浏览器会默认把我们的实例返回(返回的是一个对象数据类型的值)
    // 但是如果我们手动返回值,分两种情况
           // ******情况一,返回的是一个基本数据类型的值,当前实例不变
           // 例如: return 100
           // 那么浏览器返回的值仍然是浏览器默认创建的对象
           // ******情况二,返回的是一个引用数据类型的值,当前实例会被自己返回的值覆盖掉
           // 例如: return {name: "psg"}
           // 那么原先浏览器返回的默认值,将会被自己的手动创建返回的对象给覆盖掉。注意,一定要是对象哦

 

->知识点五: 检测某一个实例是否属于这个类 -> instanceof

下面这个例子很有意思!!结合了知识点四。

function Fn() {
var num = 10;
// return 100
return {name: 'psg'}
}
var f1 = new Fn;
console.log(f1 instanceof Fn); // ->false , 因为f1不是浏览器创建的默认实例

  

 ->知识点六:检测某个属性是否属于某个实例,检测某个属性是否为该对象的公有属性?

function Fn1() {
this.x = 100;
this.getX = function() {
console.log(this.x);
}
}
var fun1 = new Fn1;
var fun2 = new Fn1;
console.log(fun1.getX() === fun2.getX());
// -> fun1和fun2都是Fn1这个类的实例,都拥有x和getX这两个属性,但是这两个属性是各自私有的属性
// 但是如何检测某一个属性是否属于某一个实例
// in: 检测某一个属性是否属于某一个实例,不管是私有属性还是公有属性,用in都是用来检测这个属性是否属于这个对象
console.log("getX" in fun1); // -> true // hasOwnProperty: 用来检测某个属性是否为这个对象的私有属性,这个方法只能检测私有的属性
console.log(fun1.hasOwnProperty("getX")); // -> true // 思考,检测某一个属性是否为该对象的“公有属性”,自己写一个 hasPubProperty function hasPubProperty(obj, attr) {
// 首先保证它是一个对象的属性,并且不是私有属性,那就肯定就是公有属性了
return ((attr in obj) && !obj.hasOwnProperty(attr));
} console.log(hasPubProperty(fun1, "getX")); // -> false;

  

这一章,主要讲了单例模式、工厂模式和构造函数模式,同时也因为工厂模式与构造函数模式代码上非常相似,但是实现原理完全不相同,所以也讲了构造函数模式实例化对象的原理过程,以及他们两的区别。

下一章 的《【设计模式+原型理解】第二章:JS中为什么要存在原型prototype这个东西?》会讲到原型模式,准确来说是基于构造函数模式的原型模式,因为只有讲到构造函数模式,你才知道构造函数的优缺点,原型模式就是为了解决并改进构造函数的。

待续....

【设计模式+原型理解】第一章:使用Javascript来巧妙实现经典的设计模式的更多相关文章

  1. 《JavaScript高级程序设计(第3版)》阅读总结记录第一章之JavaScript简介

    前言: 为什么会想到把<JavaScript 高级程序设计(第 3 版)>总结记录呢,之前写过一篇博客,研究的轮播效果,后来又去看了<JavaScript 高级程序设计(第3版)&g ...

  2. JavaScript DOM编程艺术第一章:JavaScript简史

    本系列的博客是由本人在阅读<JavaScript DOM编程艺术>一书过程中做的总结.前面的偏理论部分都是书中原话,觉得有必要记录下来,方便自己翻阅,也希望能为读到本博客的人提供一些帮助, ...

  3. 为什么我要放弃javaScript数据结构与算法(第一章)—— JavaScript简介

    数据结构与算法一直是我算比较薄弱的地方,希望通过阅读<javaScript数据结构与算法>可以有所改变,我相信接下来的记录不单单对于我自己有帮助,也可以帮助到一些这方面的小白,接下来让我们 ...

  4. 第一章:Javascript语言核心

    本节是javascript语言的一个快速预览,也是本书的第一部分快速预览. 读此书之前,感谢淘宝技术团队对此javascript核心的翻译,感谢弗拉纳根写出此书.感谢你们无私的分享,仅以此笔记献给你们 ...

  5. 第一章:javascript: 数据结构与算法

    在前端工程师中,常常有一种声音,我们为什么要学数据结构与算法,没有数据结构与算法,我们一样很好的完成工作.实际上,算法是一个宽泛的概念,我们写的任何程序都可以称为算法,甚至往冰箱里放大象,也要通过开门 ...

  6. 【设计模式+原型理解】第三章:javascript五种继承父类方式

    [前言] 我们都知道,面向对象(类)的三大特征:封装.继承.多态 继承:子类继承父类的私有属性和公有方法 封装:把相同的代码写在一个函数中 多态: ->重载:JS严格意义上是没有重载,但可以通过 ...

  7. 第一章 --- 关于Javascript 设计模式 之 单例模式

    首先我们对单例模式先进行理论上的讲解,接下来,我们再通过具体的代码示例,来讲解,这个单例模式的使用场景和这种模式的优缺点 (这个系列的所有关于设计模式的都是面向Javascript) 一.理论定义: ...

  8. 第一章 : javaScript框架分类及主要功能

      从内部架构和理念划分,目前JavaScript框架可以划分为5类. 第一种是以命名空间为导向的类库或框架,如果创建一个数组用new Array(),生成一个对象用new Object(),完全的j ...

  9. 第一章:JavaScript简介

    1:JavaScript诞生于1995年 2:一个完整的JavaScript实现应该由三部分组成 * 核心(ECMAScript):提供核心语言功能 *文档对象模型(DOM):提供访问和操作网页内容的 ...

随机推荐

  1. sdoi 2009 HH去散步 矩阵乘

    如果没有题里的"不会立刻沿着刚刚走来的路走回"限制,那么直接矩乘计算k步的方案数 但加了这个限制,就不能以点来矩乘了,考虑边数<=60,如果以边建邻接矩阵呢?? 先拆边,再把 ...

  2. Java IO--字符流--BufferedReader和BufferedWriter

    从昨天开始没事情干时,决定梳理梳理Java IO流,因为觉得太混乱这个东西,妈的,咋就这么多类型,想累死谁啊,这里并不是埋怨创造者,而是气自己看着看着老跑偏,实在看不进去,太多了,想睡觉,所以现在决定 ...

  3. 一种非常巧妙的读取串口数据的方法--C#

    读取不完就一直等待,读完了就立刻走,之前都是设置一个溢出时间,不管是不是早就读取完了都要在这等着,有一定的时间浪费. 注意,用之前要设置好SerialPort类的TimeOut属性:

  4. MIP技术进展月报第2期: 数据绑定,异步脚本加速

    一. 功能更新 1. mip-bind 上线,实现复杂交互 MIP bind 双向绑定机制和组件上线,提供双向绑定的特性:能够允许页面实现数据驱动功能,开发者可以在任意场景修改数据,并驱动页面元素变动 ...

  5. 【Python3爬虫】常见反爬虫措施及解决办法(三)

    上一篇博客的末尾说到全网代理IP的端口号是经过加密混淆的,而这一篇博客就将告诉你如何破解!如果觉得有用的话,不妨点个推荐哦~ 一.全网代理IP的JS混淆 首先进入全网代理IP,打开开发者工具,点击查看 ...

  6. javaScript设计模式之----工厂模式

    什么是工厂模式?我们通过一个例子了解一下: 比如我们想要弹出几个字符串 function funA(){ alert('a'); } function funB(){ alert('b'); } fu ...

  7. .NET Core中使用AutoMapper

    何为AutoMapper AutoMapper是对象到对象的映射工具.在完成映射规则之后,AutoMapper可以将源对象转换为目标对象. 安装AutoMapper 这里我们在NuGet中下载安装Au ...

  8. 聊一聊C# 8.0中的await foreach

    AsyncStreamsInCShaper8.0 很开心今天能与大家一起聊聊C# 8.0中的新特性-Async Streams,一般人通常看到这个词表情是这样. 简单说,其实就是C# 8.0中支持aw ...

  9. Java设置PDF有序、无序列表

    文档中的设置有序或无序列表是一种反应内容上下级关系或者内容相同属性的方式,与单纯的文字叙述相比,它能有效增强文档内容的条理性,突出重点.因此,本文将分享通过Java编程在PDF文档中设置有序或无序列表 ...

  10. 基于weex的app开发脚手架weexplus学习笔记

    认识weexplus weexplus是基于weex官方的二次开发版本,weex和react native一样同属第2代跨平台技术,解决了第一代性能低下,体验不好的问题,同时保留了第一代 多平台一套代 ...