《javascript设计模式与开发实践》阅读笔记(1)—— 多态和原型

动态类型语言和静态类型语言的区别

根据数据类型的区别划分,静态语言在编译时已经确定变量的类型,动态语言在程序运行时,变量被赋予某个值之后,才具有某种类型。

静态语言在实际开发中为什么比动态语言繁琐

静态语言在编译时要进行类型检测,也就是说函数之类只能定好接收什么类型的变量。为了实现多态,可能的取值须放在一个类里面,函数接受这个类,而具体的变量则继承这个类的类型。
动态语言则不需要这么繁琐,因为他没有严格的类型检测,不过这样也会带来一些莫名其妙的问题。各有优缺点。

何为多态

接收不同参数,执行结果不一样
即把“做什么”和“谁去做”分离开来,也可以理解为“做什么”和“怎么去做”是分开的。

多态的作用

消化掉过程化的条件分支语句,不用通过if语句检测类型,直接调用行为即可。

封装

狭义上是隐藏变量,让外部无法访问;广义上是隐藏所有实现细节,只提供输入和输出的接口。
变化的需要封装起来,剩下的就是可复用的。

原型继承

实质是克隆另一个对象,而不是实例化一个类(类继承)。

原型链

找到一个对象作为原型,并克隆它,没有的方法和变量,会向上查找,委托自己的原型。

Object.getPrototypeOf

Object.getPrototypeOf(obj)可以获得obj的原型,和obj.__proto__ 完全等价

1 console.log(Object.getPrototypeOf(obj)===obj.__proto__)// true

JS的原型继承

创建的对象是克隆Object.prototype实现的,也就是说,克隆的是某个对象的原型,而不是这个对象本身。
但考虑一下内存分配会发现,新对象并没有占去和原型一样的内存,也就是说,这里的克隆实质更类似于引用,需要调用这种方法时就会到祖先这里调用。所以为了提高性能,减少内存的浪费,添加公用方法时,多数添加到原型(prototype)上,这样可以被别的对象很好的继承。

prototype和__proto__

JS 是基于原型继承,也就是说真正继承的东西都在prototype里,如果obj是个对象,那obj.prototype也是个对象,我们继承或者说克隆的就是这个对象的属性和方法,这里我们把它叫做原型对象。

而__proto__是所有对象都具有的属性,指向其构造器的原型对象,也就是指向构造器的prototype;或者换个好理解的方式就是指向继承的对象,也就是说,__proto__指向的就是自己克隆的对象,是自己的原型,这里我们把__proto__称为原型或者是原型指针。

核心的一句话,所有对象的__proto__都指向其构造器的prototype,即所有对象的原型就是其构造函数的原型对象。

例子:

function Person(){};
var p=new Person();
console.log(p.prototype);
//undefined 构造函数才有原型对象(prototype),普通对象寻找原型应该用__proto__ console.log(p.__proto__===Person.prototype); //true p(对象)的原型(__proto__)就是Person(构造函数)的原型对象(prototype)

对象有一个属性 constructor,可以返回它的构造函数

console.log(p.constructor===Person)  //true   

console.log(Person.prototype.constructor===Person) //true   原型对象也是对象,也能指向自己的构造函数

所以下面的都成立

console.log(Person.prototype.constructor===p.constructor) //true

console.log(p.__proto__.constructor===Person.prototype.constructor); //true
console.log(p.constructor===p.__proto__.constructor) //true 自己和原型的构造函数是同一个

所以说白了,继承的东西就是原型对象,__proto__就是指向继承的原型对象

那么问题一:对象的原型对象有原型对象么?

console.log(Person.prototype.prototype)  //undefined

结论:构造函数才有原型对象,然后没了,原型对象是没有原型对象的。

问题二:原型对象也是对象,那它有原型么?

console.log(Person.prototype.__proto__===Object.prototype)  //true

结论:有的,原型对象的原型(.__proto__)还是一个原型对象

问题三:所有对象的原型是什么?

var a={};

console.log(a.__proto__===Object.prototype)   //true   对象的原型是 Object.prototype
console.log(Object.prototype.__proto__);   //null

结论:Object.prototype处于原型链的最上端,包含很多方法,属性,可以理解为所有对象的原型,而它的原型为null,即空,不存在。

 

比较有意思的是Object这个构造器,它既是构造器也是对象,是对象就有原型

console.log(Object.__proto__===Function.prototype);  //true    Object的原型Function的原型对象

console.log(Object.prototype===Function.prototype.__proto__); // true 而Object的原型对象是Function原型对象的原型,这里有点绕,换下面这种写法
console.log(Object.prototype===Object.__proto__.__proto__); //true 可以看到Object的原型对象是它原型的原型

我们说过,原型意味着克隆继承,也就是说Object绕了一圈继承了自己的原型对象,原型链应该是条链子,__proto__连接继承的对象,prototype给别人继承,而Object这里打了个结,这种特殊性说明了它的特殊地位,而实现“打结”的关键则是Function对象,再看一个可能会更清楚

console.log(Function.constructor===Function)  //true 

console.log(Function.__proto__===Function.prototype) //true

一切就源于这里,Function自己是自己的构造器,所以__proto__(原型)就指向自己的prototype(原型对象)

Function同时也是Object 的构造器

console.log(Object.constructor===Function) //true

所以Object的__proto__指向Function的prototype,那么整理一下就是这样的

Object,

Object.__proto__ /Function.__proto__ =>Function.prototype,

Function.prototype.__proto__ => Object.prototype,

Object.prototype.__proto__ => null

原型模式

通过克隆来继承的设计模式

 

posted @ 2016-09-27 17:31  出世Sunny  阅读(234)  评论(0编辑  收藏  举报