面型对象之设计模式(浅谈)

  这篇文章是根据高程中的相关章节总结的,看了几遍,在这里总结一下笔记。感觉面向对象这一篇,最重要的就是理清思路,理解一下各个设计模式的机理以及优缺点。

  在学习之初,首先要明白一点,为何要学习JS的各种设计模式?这个问题要归咎于JS本身了,JS本身并没有“类”的概念(这里不考虑ES6),因此不可能像其他强类型的编程语言一样,通过“类”创建对象。这里只能通过几种设计模式创建。

一、工厂模式

  首先,JS提供了Object引用类型,可根据构造函数或者对象字面量创建对象,比如:

利用object构造函数创建两个属性相同,方法一致的对象:

         var person1 = new Object();
         person1.name = "shane";
         person1.age = 25;
         person1.sayName = function(){
            console.log(this.name);
         };
        var person2 = new Object();
         person2.name = "Peter";
         person2.age = 30;
         person2.sayName = function(){
            console.log(this.name);
         };

这种创建方式的问题是:如果要创建n个属性相同,方法一致的对象,是否要像上述一样写n次?这也太麻烦了,也不符合实际。那么如何去解决这种问题?引出了工厂模式

  概念:工厂函数通俗的说就是利用函数的方式将特定的创建对象的步骤封装起来,提高复用性。

那么此时上述的利用Object创建的两个相同属性以及方法的对象,就可用工厂函数封装起来:

         function person(name,age){
            var o = new Object();
                o.name = name;
                o.age = age;
                o.sayName = function(){
                    console.log(this.name);
            };
            return o;
         }
         //调用函数以创建对象实例
         var person1 = person("shane",25);
         var person2 = person("Peter",30);

瞧!是不是只是利用函数的封装,使用时直接调用即可,很简单。

  缺点:工厂函数的简单的封装并未解决对象识别的问题--创建的自定义的构造函数意味着可以将其作为一种特定的类型。因此引出了“构造函数模式”。

二、构造函数模式

  概念:构造函数模式通俗来讲就是自定义一个构造函数,然后利用new操作符创建这个构造函数对应的实例。

例如:

        //定义自定义构造函数       function Person(name,age){
            this.name = name;
            this.age = age;
            this.sayName = function(){
                console.log(this.name);
            }
         }     //利用new操作符创建构造函数实例      var person1 = new Person("shane",25);      var person2 = new Person("peter",30);

注意到:这里并没有显式写出return语句,但是为何能够创建出对象的实例?这就要简单了解一下new操作符在这个过程中起到了什么作用。

  利用自定义构造函数创建对象的过程:

  1. 使用new操作符创建对象;
  2. 调用构造函数,将新创建的对象赋值给构造函数内部的this;
  3. 在构造函数内部使用this为新创建的对象添加成员(属性或方法);
  4. 默认的返回新创建的对象。

注意:由于利用自定义构造函数创建对象时,不必显式添加return语句,但是如果不小心添加上了return语句,那么对结果会有什么影响?

  • 如果添加的return语句返回的是空值(return;)或者返回的是基本类型值或null,那么最终返回的依然是默认的新创建的对象;
  • 如果添加的return语句返回的是引用类型的值,那么这是要注意最终返回的是新添加的return语句。

  那么利用自定义构造函数模式,那么其对应的实例都会属于自定义的类型,这个解决了工厂模式遗留的问题。(验证方式:可利用instanceof,有些内容涉及到后面的原型链以及继承知识)

缺点:构造函数模式虽然解决了自定义类型的识别问题,但是也不完善,无法做到共享的属性和方法以及每个实例独有的属性和方法分离。因此,引出了“原型模式”。

三、原型模式

  概念:原型模式就是利用每个函数的prototype属性(其是一个指向函数原型的指针)访问原型中的属性和方法,从而致力于解决实例之间成员“共享问题”。

例如:

         //自定义一个构造函数
         function Person(){}
         //利用对象的动态特性,给原型对象添加成员(属性和方法)
         Person.prototype.name = "shane";
         Person.prototype.age = 25;
         Person.prototype.sayName = function(){
            console.log(this.name);
         };
         //利用new操作符创建实例
         var person1 = new Person();
         person1.sayName();
         var person2 = new Person();
         person2.sayName();

但是要注意的是:这里只能使用共享的属性和方法,暂时还不能独立使用每个实例一些特殊属性和方法。也即是说,上述代码,sayName返回的内容一样。

  那么既然提到了原型的使用,那么也要了解一下原型内部的一些原理

首先,只要是定义了一个函数,那么这个函数就有prototype属性,该属性指向函数的对象(在这里是Person.prototype)。接着对于函数Person的原型来说,其内部有一个constructor属性,该属性值指向prototype属性所在的函数的指针(在这里是Person,注意:这里说法很严谨,并不是直接说指向其构造函数指针,因为还要涉及原型链,有可能constructor指向构造函数原型的原型)。对于两个实例来说,每个实例都有内部属性prototype,指向的是构造函数的原型对象。

这里补充一个内容:

  在拥有原型的情况下,要访问属性以及方法时,JS的查找顺序是什么样的?(这里先不考虑原型链,假设就是有一个构造函数的原型,不包含原型的原型Object,只是为了简化,研究方便)以查找属性为例

  • 首先会从实例中的属性进行查找,如果有直接返回;如果没有进行下一步;
  • 此时,直接在实例对应的原型中查找该属性,如果有返回,如果没有则返回undefined。(如果是方法,则报错)

这里有一个例子:

        function Person(){

         }
         Person.prototype.name = "shane";
         Person.prototype.books = {
            book1: "JavaScript"
         };
         //实例
         var person1 = new Person();
         person1.name = "peter";
         console.log(person1.name);

         var person2 = new Person();
         person2.books.book1 = "Economist";
         console.log(person2.books.book1);
         console.log(person2.books);

解释:

创建的第一个实例中,想要给name属性赋值,注意“赋值”而不是“获取”。因此,此时会直接在实例person1,新创建一个名为name的属性,其值为"peter"。但是原型中存在了同样属性名的属性,那么在JS中,会直接将原型中的同名属性屏蔽掉。因此,利用person1.name访问时,返回的是“peter”。

创建的第二个实例中,则与第一个实例相反。会先通过person2.books去访问,如果在实例中没有books对象,那么会向上查找。可知,在原型中找到了books对象;接着修改其中的book1的值,因此,此时通过这种方式修改了原型中的属性值。

  缺点:原型最大的劣势是,其所有的实例的属性以及属性值都是相同的,因此原型的“共享性”。因此,仅仅有原型还不行,因为实例自身拥有的属性和方法也需要访问到。=>引出了“组合使用构造函数模式和原型模式”。

三、组合使用构造函数模式和原型模式

  概念:显而易见,组合模式就是结合了构造函数模式以及原型模式的优点。实例之间既可以利用原型模式共享的属性和方法,也可以使用实例自身拥有的属性和方法。

例如:

        //定义自定义构造函数,并且传参
         function Person(name,age){
            this.name = name;
            this.age = age;
         }      //给对应的原型添加成员
         Person.prototype = {
            constructor: Person,
            sayName: function(){
                console.log(this.name);
            }
         };
         //创建实例
         var person1 = new Person(‘shane‘,25);
         var person2 = new Person(‘peter‘,30);

  注意:重写原型时,原型中的constructor不再指向原构造函数,而是指向Object,因此可以通过属性重新使得原型指向原构造函数。

  这种模式应该是使用最广泛、认同度最高的一种创建自定义类型方法。

四、动态原型模式

  概念:动态原型模式感觉是组合模式的一种变形,一种优化模式。因为这种模式通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型。

        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(‘shane‘,25);
         person1.sayName();
         var person2 = new Person(‘peter‘,30);
         person2.sayName();

五、寄生构造函数模式

  概念:通俗讲寄生构造函数模式就是创建一个函数,然后封装创建对象的代码,最后利用return语句返回在构造函数内部新创建的对象。

例如:

       //寄生构造函数模式
         function Person(name,age){
            var o = new Object();
            o.name = name;
            o.age = age;
            o.sayName = function(){
                console.log(this.name);
            };
            return o;
         }

         var person1 = new Person(‘shane‘,24);
         person1.sayName();

         //比较构造函数模式
         function Person(name,age){
            this.name = name;
            this.age = age;
            this.sayName = function(){
                console.log(this.name);
            };
         }

         var person1 = new Person(‘peter‘,30);
         person1.sayName();

         //相比较工厂模式
         function person(name,age){
            var o = new Object();
            o.name = name;
            o.age = age;
            o.sayName = function(){
                console.log(this.name);
            };
            return o;
         }

         var person1 = person(‘bob‘,20);
         person1.sayName();

  看到这个概念,我联想到了“工厂函数模式”,作为设计模式的“初始者”,工厂函数模式也是利用函数将创建对象的代码封装起来,提高复用性。但是两者的区别是调用方式不同,工厂函数模式是利用普通函数的调用模式;而寄生构造函数模式利用你new操作符调用,并且寄生构造函数模式在构造函数的内部也是用了return语句进行返回。工厂函数模式尽然与寄生构造函数模式如此相像,那么为何还创造。书上说,这种模式在上述几种模式不适用的情况下的一种模式。然后我又联想到了“噶构造函数模式”,进行这三者的比较。(So, stupid,huh?)

劣势:

  由于是在构造函数内部重新定义了一个对象,因此返回的这个对象与构造函数后者构造函数的原型之间没有任何关系。因此,不能依赖instanceof操作符确定对象的类型。因此,这和“工厂函数模式”很相似啊!

六、稳妥构造函数模式

  概念:稳妥构造函数模式有一个与“工厂函数模式”类似的,这个模式没有公共属性,不能使用this与new操作符,因此最适合在安全环境中使用。

  这种模式与“构造函数模式”不同的是除了不能使用this之外,也不能使用new操作符。

例如:

       //稳妥构造函数模式
         function Person(name,age){
            var o = new Object();
            o.sayName = function(){
                console.log(name);
            };
            return o;
         }

         //调用
         var person1 = Person(‘shane‘,25);
         person1.sayName();

         //工厂函数模式
         function Person(name,age){
            var o = new Object();
            o.name = name;
            o.age = age;
            o.sayName = function(){
                console.log(this.name);
            };
            return o;
         }
         var person1 = Person(‘peter‘,30);
         person1.sayName();

         //构造函数模式
         function Person(name,age){
            this.name = name;
            this.age = age;
            this.sayName = function(){
                console.log(this.name);
            };
         }
         var person1 = new Person(‘bob‘,20);
         person1.sayName();

劣势:

  这种类似于“工厂函数模式”的模式,自然不能够利用instanceof检测类型。

时间: 2024-10-02 20:47:10

面型对象之设计模式(浅谈)的相关文章

.net中对象序列化技术浅谈

.net中对象序列化技术浅谈 2009-03-11 阅读2756评论2 序列化是将对象状态转换为可保持或传输的格式的过程.与序列化相对的是反序列化,它将流转换为对象.这两个过程结合起来,可以轻松地存储和传输数 据.例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象.反之,反序列化根据流重新构造对象.此外还可以将对象序列化后保存到本地,再次运行的时候可以从本地文件 中“恢复”对象到序列化之前的状态.在.net中有提供了几种序列化的方式:二进制序列化

设计模式浅谈之----设计模式简介

1.何为设计模式 设计模式是一个通过定义.使用和测试去解决特定问题的方法,并且由于设计模式是在面向对象之后为人所知的,基本思想与面向对象不可分割. 在软件工程中,设计模式是一般只在给定条件下会重复性发生问题而提出的一种通用的解决方案. 2.设计模式简史 设计模式的概念在计算机科学领域的普及主要归功于1994年<设计模式:可复用面向对象的软件的基础>,作者GoF(即Erich Gamma.Richard Helm.Ralph Johnson 和 John Vlissides 四人) 3.设计模式

设计模式浅谈

模式最早起源于建筑业而非软件业,经大量研究发现人们对舒适住宅和周边环境存在一些共同的认同规律,通过这些规律,可以归纳出设计模式来解决建筑时出现的一般性问题.不同的模式描述了在我们环境中不断出现的问题,然后描述了该问题的解决方案的核心,通过这种方式,我们可以无数次的重用那些已有的解决方案,无须再重复相同的工作.对于软件行业的设计模式大体也是这个意思.通过对代码分类编目,总结代码设计经验,来设计解决一些特定问题的方案,实现代码复用的目的.设计模式一般包含四个基本要素:模式名称.问题.解决方案和效果.

ThreadLocal 设计模式浅谈

部分代码:ThreadLocal中 的get方法, 获得的是当前线程相关的对象 /** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of t

PHP设计模式浅谈

1.单例模式 顾名思义,单例模式定义了一个对象只能有一个实例,相当于把类的控制权给到了一个单点上. 要求: a.private的构造函数,使类无法被随意new实例化: private function __construct{ ...... } b.有一个静态变量,用来保存类的实例: static public $instance; c.有一个公共的静态方法,来访问这个实例,通常命名为getInstance: static public function getInstance(){ if(em

JavaWeb学习之路-------对象,构造方法浅谈

%5B%E7%B3%BB%E7%BB%9F%E5%BC%80%E5%8F%91%5D%20%E5%9F%BA%E4%BA%8EAnsible%E7%9A%84%E4%BA%A7%E5%93%81%E4%B8%8A%E7%BA%BF%E7%B3%BB%E7%BB%9F http://auto.315che.com/lufengx7/qa23940308-2.htm ????IBcGx6Km???????F? ?????4eSPHCWq???????????? http://auto.315che.

浅谈设计原则和设计模式

文章结构: 1.前言 2.设计原则       3.设计模式 3.1 创建型模式 3.2 结构型模式 3.3 行为型模式 前言 设计原则和设计模式旨在帮助我们设计出一个可复用.可扩展.可维护的应用. 设计原则:设计OR重构系统的指导方针. 设计模式:解决某类问题性质有效的方法. 设计原则和设计模式要实现的目标是:在需求变动或者系统升级时,尽可能少的改变代码,尽可能多的实现新的功能. 设计原则是设计模式的"背后的故事",要深入理解设计模式必先深入理解设计原则. 设计原则 1.开闭原则(O

浅谈iOS面试所遇问题

今天面试的公司之前在百科搜索了解了一些信息,一家专业拉手媒体运营商,付费通方便了用户出行,很喜欢公司的氛围. 言归正传,面对面试官的时候还是多少会有点小紧张,有几个问题回答的也是很笼统,现在做出总结.如下: 自我面试轻轻飘过~ 这个是常识 个人信息稍作了解,常识+1 浅谈MVC框架设计模式 浅谈单例设计模式 KVC/KVO Switch开关点击出错(on状态点击依旧on状态,解决方法) cell单元格重用出现的错误(解决方法) 怎样实现代理传值 怎样实现ImageView的点击事件处理 HTTP

《浅谈JavaScript系列》系列技术文章整理收藏

<浅谈JavaScript系列>系列技术文章整理收藏 1浅谈JavaScript中面向对象技术的模拟 2浅谈javascript函数劫持[转自xfocus]第1/3页 3浅谈javascript 面向对象编程 4老鱼 浅谈javascript面向对象编程 5浅谈javascript的数据类型检测 6浅谈Javascript嵌套函数及闭包 7根据一段代码浅谈Javascript闭包 8浅谈JavaScript编程语言的编码规范 9浅谈Javascript面向对象编程 10浅谈JavaScript