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

原型模式

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

时间: 2024-12-17 21:25:13

javascript设计模式与开发实践 阅读笔记(1)的相关文章

javascript设计模式与开发实践阅读笔记(4)——单例模式

定义 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 具体来说,就是保证有些对象有且只有一个,比如线程池.全局缓存.浏览器中的window 对象等.在js中单例模式用途很广,比如登录悬浮窗,我希望无论我点击多少次这个浮窗都只会被创建一次,这里就可以用单例模式. 1.实现单例模式 思路:用一个变量来标志当前是否已经为某个类创建过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象:如果否就创建出那个对象. 1 var Singleton = function( nam

javascript设计模式与开发实践阅读笔记(3)——高阶函数的其他应用

高阶函数的其他应用 1.currying 函数柯里化,又称部分求值,一个currying 的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来.待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值. var cost = (function(){ var args = []; return function(){ if ( arguments.length === 0 ){ var money =

javascript设计模式与开发实践阅读笔记(7)——迭代器模式

迭代器模式:指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示. 迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺序访问其中的每个元素. 流行语言如Java.Ruby 等都已经有了内置的迭代器实现,许多浏览器也支持JavaScript的Array.prototype.forEach. jQuery中的迭代器 1 $.each( [1, 2, 3], function( i, n ){ 2 console.log

javascript设计模式与开发实践阅读笔记(6)——代理模式

代理模式:是为一个对象提供一个代用品或占位符,以便控制对它的访问. 代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对象.替身对象对请求做出一些处理之后,再把请求转交给本体对象.基本可以理解为粉丝(客户),经纪人(代理),偶像(对象).经纪人就相当于偶像的代理,需求直接提给经纪人,经纪人这边可以进行很多逻辑上的处理,比如可以帮助偶像过滤掉很多请求等等. 1.保护代理和虚拟代理 像上面那种,请求被代理拒绝掉就是保护代

javascript设计模式与开发实践阅读笔记(2)—— this,闭包与高阶函数

this this总是指向一个对象,有四种情况1. 作为对象的方法调用.2. 作为普通函数调用.3. 构造器调用.4. Function.prototype.call 或Function.prototype.apply 调用. 1. 作为对象的方法调用 当函数作为对象的方法被调用时,this 指向该对象: var obj = { a: 1, getA: function(){ alert ( this === obj ); // 输出:true alert ( this.a ); // 输出:

javascript设计模式与开发实践阅读笔记(5)——策略模式

策略模式:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换. 我的理解就是把各种方法封装成函数,同时存在一个可以调用这些方法的公共函数.这样做的好处是可以消化掉内部的分支判断,使代码效率更高. 使用策略模式计算奖金 现在要实现这样一个东西,年终奖是根据员工的工资基数和年底绩效情况来发放的.例如,绩效为S的人年终奖有4倍工资,绩效为A的人年终奖有3倍工资,而绩效为B的人年终奖是2倍工资.假设财务部要求我们提供一段代码,来方便他们计算员工的年终奖. 思路一:创建一个函数,接收两个参数,

javascript设计模式与开发实践阅读笔记(9)——命令模式

命令模式:有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么,此时希望用一种松耦合的方式来设计软件,使得请求发送者和请求接收者能够消除彼此之间的耦合关系. 说法很复杂,简单来说就是希望真正做事情的对象不要直接被调用,当我们下达一些命令之后, 希望对象已经间接的执行了.这样做的好处是可以解耦,代码可以更为灵活,还可以管理命令,甚至完成命令队列这样的操作. 实现思路 为了实现这种效果,我们需要通过一个函数,创造一个接口对象,调用接口对象的方法,就是调用对象真正的方

javascript设计模式与开发实践阅读笔记(10)—— 组合模式

组合模式:一些子对象组成一个父对象,子对象本身也可能是由一些孙对象组成. 有点类似树形结构的意思,这里举一个包含命令模式的例子 1 var list=function(){ //创建接口对象的函数 2 return { 3 arr:[], //执行列表 用来存储需要执行的对象 4 add:function(obj){ //往执行列表里添加对象 5 this.arr.push(obj); 6 }, 7 execute:function(){ //遍历执行列表,每个对象执行规定好的接口方法 8 fo

JavaScript 设计模式与开发实践读书笔记 http://www.open-open.com/lib/view/open1469154727495.html

JavaScript 设计模式与开发实践读书笔记 最近利用碎片时间在 Kindle 上面阅读<JavaScript 设计模式与开发实践读书>这本书,刚开始阅读前两章内容,和大家分享下我觉得可以在项目中用的上的一些笔记. 我的 github 项目会不定时更新,有需要的同学可以移步到我的 github 中去查看源码: https://github.com/lichenbuliren/design-mode-notes 1.currying 函数柯里化 currying 又称 部分求值 .一个 cu