首页 > 代码库 > javascript设计模式与开发实践 阅读笔记(1)
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.prototypeconsole.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
原型模式
通过克隆来继承的设计模式
javascript设计模式与开发实践 阅读笔记(1)