zoukankan      html  css  js  c++  java
  • 【设计模式+原型理解】第二章:基于构造函数扩展出来的原型模式

           在第一章的时候,说过了单例模式、工厂模式、构造函数模式,你还记得构造模式是怎么样的吗?

    function CreateJsPerson(name, age) {
    	this.name = name;
    	this.age = age;
    	this.writeJs = function() {
    		console.log("my name is " + this.name + ", i can write js.");
    	}
    }
    var p1 = new CreateJsPerson("p1", 18);
    var p2 = new CreateJsPerson("p2", 17);
    p1.writeJs();
    p2.writeJs();
    console.log(p1.writeJs() === p2.writeJs()); //-> false
    // 构造函数模式中拥有了类和实例的概念,并且实例和实例之间是相互独立开的
    // -> 叫做实例识别

           上面的就是构造函数模式,你知道,为什么p1、p2的writeJs()方法为什么不相等吗?这是因为正如上面所说的,两个实例是相互独立的,也就是说,两个实例的属性都是各自私有属性。

       -> 问题来了,两个实例里面的属性都是私有的以外,是不是还得有公有的部分?

    一、【基于构造函数的原型模式

            使用基于构造函数模式的原型模式,能够实现把writeJs()方法变成公有的,代码如下:

    function CreateJsPerson(name, age) {
    	this.name = name;
    	this.age = age;
    	// this.writeJs = function() {
    	// 	 console.log("my name is " + this.name + ", i can write js.");
    	// }
    }
    CreateJsPerson.prototype.writeJsG = function() {
    	console.log("my name is " + this.name + ", i can write js.");
    };
    
    var p1 = new CreateJsPerson("p1", 18);
    var p2 = new CreateJsPerson("p2", 17);
    p1.writeJs();
    p2.writeJs();
    console.log(p1.writeJsG() === p2.writeJsG()); //->true
    

            为什么这样写,就能把属性变为公有的呢?

            基于构造函数模式扩展出来的原型模式:

                    ->它解决了方法或者属性公有的问题

                    ->即把实例之间公有的属性和方法提出成公有的属性和方法

                    ->想让谁公有,就把它放在prototype上即可

     

    二、【原型基础3句话】

             想要学习原型,要记住下面的三句话(不要问为什么~~):

             1)每一个函数数据类型(普通函数、类)都有一个天生自带的属性,prototype(原型),并且这个属性是一个对象数据类型的值。

              2)并且在prototype上浏览器会天生给它加上一个属性contructor(构造函数),属性值是当前函数(类)本身。

              3)每一个对象数据类型(普通对象,实例,prototype...)也天生自带一个属性:__proto__,属性值是当前实例所属类的原型(prototype)。

    下面这段代码,可以说明一下上面的3句话:

    function Fn() {
    	this.x = 100;
    };
    Fn.prototype.getX = function() {
    	console.log(this.x);
    };
    var f1 = new Fn;
    var f2 = new Fn;
    console.log(Fn.prototype.constructor === Fn); //->true
    // 堆内存:存储 对象、函数里面的代码字符串

    上面代码的原型链如下图所示,正方形代表栈内存(即函数作用域),椭圆正方形代表堆内存(即对象)

        从画图可以很清晰看到,整个基于构造函数扩展出来的原型链函数,类与实例的原型链,实例与JS基类Object的原型链关系,一览无遗。

        上图+代码,可以总结出:

         1、Object是JS中所有对象数据类型的基类(最顶层的类)

               1) f1 instanceof Object -> true,这是因为f1通过__proto__可以向上级查找,不管有多少级,最后总能找到Object

                2)在Object.prototype上没有__proto__这个属性(因为自己指向自己没意义)

          2、原型链模

                举个简单的例子,f1.hasOwnProperty("x");  //->hasWwnProperty是f1的一个属性,但是我们发现f1的私有属性上并没有这个方法,那如何处理的呢?

                通过 对象名.属性名 的方式获取属性值的时候,首先在对象的私有的属性上进行查找,如果私有中存在这个属性,则获取的是私有的属性值;

             ->如果私有的没有,则通过__proto__找到所属类的原型(类的原型上定义的属性和方法都是当前实例的公有的属性和方法),原型上存在的话,获取的是公有的属性值;

            -> 如果原型上也没有,则继续通过原型上的__proto__继续向上查找,一直找到Object.prototype为止...

             ->这种查找的机制就是我们的原型链模式

    三、【原型知识玩起来】

    cconsole.log(f1.getX === f2.getX); //->true
    console.log(f1.__proto__.getX === f2.getX); //->true 
    console.log(f1.getX === Fn.prototype.getX); //->true
    // f1.getX 跟 f1.__proto__.getX的区别
    // 前者是浏览器先找私有作用域,找不到再找公有作用域
    // 后者是浏览器直接查找公有作用域
    // 
    console.log(f1.hasOwnProperty === f1.__proto__.__proto__.hasOwnProperty);
    
    // 在IE浏览器中,我们原型模式也是同样的原理,但是IE浏览器怕你通过__proto__把公有的修改,
    // 禁止我们使用__proto__,下面的例子就可以很明显的说明为啥IE禁止了
    
    f1.sum == function() {
    	//修改自己私有的sum
    };
    f1.__proto__.sum = function() {
    	//修改所属类原型上的sum
    };
    // 所以修改公有的,IE只能通过prototype
    Fn.prototype.sum = function() {
    	// 修改公有的sum
    };
    

    四、【总结】

            在这一章中,主要说的是原型模式,但是原型模式是通过构造函数扩展出来的,同时也通过代码+图的方式,把原型模式的实现原理给画了出来。

            既然原型这个知识点出来了,我会在后面介绍一下,使用原型来实现类的封装、继承、多态(里面的重写),并且会介绍使用原型来实现7中继承方法,将会非常有趣。

  • 相关阅读:
    Spring框架总结(二)
    java.lang.ClassCastException: com.liuyang.annocation.UserAction cannot be cast to com.liuyang.annocation2.UserAction at com.liuyang.annocation2.App.test
    Spring框架总结(一)
    Error creating bean with name 'us' defined in class path resource [com/liuyang/test/DI/beans2.xml]: Cannot resolve reference to bean 'daoa' while setting bean property 'daoa'; nested exception is org.
    互联网系统架构的演进
    重新理解:ASP.NET 异步编程(转)
    Git初级使用教程(转)
    JavaScript开发规范要求
    大型网站架构演化发展历程(转)
    Bootstrap 学习(1)
  • 原文地址:https://www.cnblogs.com/pengshengguang/p/10416044.html
Copyright © 2011-2022 走看看