【设计模式+原型理解】第二章:基于构造函数扩展出来的原型模式

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

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
// 构造函数模式中拥有了类和实例的概念,而且实例和实例之间是相互独立开的
// -> 叫作实例识别

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

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

 

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

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

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

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

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

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

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

 

2、【原型基础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的原型链关系,一览无遗。

    上图+代码,能够总结出:

     一、Object是JS中全部对象数据类型的基类(最顶层的类)

           1) f1 instanceof Object -> true,这是由于f1经过__proto__能够向上级查找,无论有多少级,最后总能找到Object

            2)在Object.prototype上没有__proto__这个属性(由于本身指向本身没意义)

      二、原型链模

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

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

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

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

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

 

3、【原型知识玩起来】

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
};

 

4、【总结】

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

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

相关文章
相关标签/搜索