Skip to content

Latest commit

 

History

History
162 lines (109 loc) · 11.3 KB

ObjectOriented.md

File metadata and controls

162 lines (109 loc) · 11.3 KB

面向对象

JavaScript模块化编程,已经成为一个迫切的需求。理想情况下,开发者只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块。

JavaScript不是一种模块化编程语言,ES5不支持”类”(class),更遑论”模块”(module)了。ES6正式支持”类”和”模块”,但还没有成为主流。

”污染”了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系。 将私有变量封装在构造函数中,违反了构造函数与实例对象相分离的原则。

使用“立即执行函数”(Immediately-Invoked Function Expression,IIFE),将相关的属性和方法封装在一个函数作用域里面,可以达到不暴露私有成员的目的。

模块的放大模式

如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用“放大模式”(augmentation)。 在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用上面的写法,第一个执行的部分有可能加载一个不存在空对象,这时就要采用”宽放大模式”(Loose augmentation)。 与”放大模式”相比,“宽放大模式”就是“立即执行函数”的参数可以是空对象。

独立性是模块的重要特点,模块内部最好不与程序的其他部分直接交互。 为了在模块内部调用全局变量,必须显式地将其他变量输入模块。 module1模块需要使用jQuery库和YUI库,就把这两个库(其实是两个模块)当作参数输入module1。这样做除了保证模块的独立性,还使得模块之间的依赖关系变得明显。

个人觉得JavaScript是很文艺的一门语言,文艺范儿会更适合这门语言(个人观点,不喜勿喷) 有人说,JavaScript 语言“一切皆对象”。这是因为数组和函数本质上都是对象,就连三种原始类型的值——数值、字符串、布尔值——在一定条件下,也会自动转为对象,也就是原始类型的“包装对象”。

所谓“包装对象”,就是分别与数值、字符串、布尔值相对应的Number、String、Boolean三个原生对象。这三个原生对象可以把原始类型的值变成(包装成)对象。 JavaScript设计包装对象的最大目的,首先是使得JavaScript的“对象”涵盖所有的值。其次,使得原始类型的值可以方便地调用特定方法。 Number、String和Boolean如果不作为构造函数调用(即调用时不加new),常常用于将任意类型的值转为数值、字符串和布尔值。

包装对象实例的方法

valueOf方法返回包装对象实例对应的原始类型的值。 toString方法返回实例对应的字符串形式。 原始类型的值,可以自动当作对象调用,即调用各种对象的方法和参数。这时,JavaScript引擎会自动将原始类型的值转为包装对象,在使用后立刻销毁。 字符串可以调用length属性,返回字符串的长度。 这个临时对象是只读的,无法修改。所以,字符串无法添加新属性。 还包括三个包装对象各自定义在原型上的方法。

'abc'.charAt === String.prototype.charAt
# true

Boolean对象除了可以作为构造函数,还可以单独使用,将任意值转为布尔值。这时Boolean就是一个单纯的工具方法。

Boolean(undefined) 
# false
Boolean(null) 
# false
Boolean(0) 
# false
Boolean('') 
# false
Boolean(NaN) 
# false

使用双重的否运算符(!)也可以将任意值转为对应的布尔值。 如果包装对象与原始类型值进行混合运算,包装对象会转化为原始类型(实际是调用自身的valueOf方法)。

new Number(123) + 123 
# 246
new String('abc') + 'abc' 
# "abcabc"

Number对象是数值对应的包装对象,可以作为构造函数使用,也可以作为工具函数使用。 Number对象部署了自己的toString方法,用来将一个数值转为字符串形式。 还可以在10后面加两个点,JavaScript会把第一个点理解成小数点(即10.0),把第二个点理解成调用对象属性,从而得到正确结果。可以直接对一个小数使用toString方法。 通过方括号运算符也可以调用toString方法。

10['toString'](2) //"1010"

将其他进制的数,转回十进制,需要使用parseInt方法。 toFixed方法用于将一个数转为指定位数的小数,返回这个小数对应的字符串。

toExponential方法用于将一个数转为科学计数法形式。

toPrecision方法用于将一个数转为指定位数的有效数字。

charAt方法返回指定位置的字符,参数是从0开始编号的位置。 这个方法完全可以用数组下标替代。

charCodeAt方法返回给定位置字符的Unicode码点(十进制表示),相当于String.fromCharCode()的逆操作。

concat方法用于连接两个字符串,返回一个新字符串,不改变原字符串。

slice方法用于从原字符串取出子字符串并返回,不改变原字符串。

substring方法用于从原字符串取出子字符串并返回,不改变原字符串。它与slice作用相同,但有一些奇怪的规则,因此不建议使用这个方法,优先使用slice。

substr方法用于从原字符串取出子字符串并返回,不改变原字符串。

substr方法的第一个参数是子字符串的开始位置,第二个参数是子字符串的长度。

这两个方法用于确定一个字符串在另一个字符串中的位置,都返回一个整数,表示匹配开始的位置。如果返回-1,就表示不匹配。两者的区别在于,indexOf从字符串头部开始匹配,lastIndexOf从尾部开始匹配。

trim方法用于去除字符串两端的空格,返回一个新字符串,不改变原字符串。该方法去除的不仅是空格,还包括制表符(\t、\v)、换行符(\n)和回车符(\r)。

toLowerCase方法用于将一个字符串全部转为小写,toUpperCase则是全部转为大写。它们都返回一个新字符串,不改变原字符串。

match方法还可以使用正则表达式作为参数,详见《正则表达式》一节。search方法的用法等同于match

replace方法用于替换匹配的子字符串,一般情况下只替换第一个匹配(除非使用带有g修饰符的正则表达式)。

split方法按照给定规则分割字符串,返回一个由分割出来的子字符串组成的数组。

split方法还可以接受第二个参数,限定返回数组的最大成员数。

toISOString方法返回的总是UTC时区的时间。

toJSON方法返回一个符合JSON格式的ISO格式的日期字符串,与toISOString方法的返回结果完全相同。

Filter:对数组中的每个元素都执行一次指定的函数(callback),并且创建一个新的数组,该数组元素是所有回调函数执行时返回值为 true 的原数组元素。它只对数组中的非空元素执行指定的函数,没有赋值或者已经删除的元素将被忽略,同时,新创建的数组也不会包含这些元素。回调函数可以有三个参数:当前元素,当前元素的索引和当前的数组对象。 如参数 thisObject 被传递进来,它将被当做回调函数(callback)内部的 this 对象,如果没有传递或者为null,那么将会使用全局对象。 filter 不会改变原有数组,记住:只有在回调函数执行前传入的数组元素才有效,在回调函数开始执行后才添加的元素将被忽略,而在回调函数开始执行到最后一个元素这一期间,数组元素被删除或者被更改的,将以回调函数访问到该元素的时间为准,被删除的元素将被忽略。

map()

some(): 对数组中的每个元素都执行一次指定的函数(callback),直到此函数返回 true,如果发现这个元素,some 将返回 true,如果回调函数对每个元素执行后都返回 false ,some 将返回 false。它只对数组中的非空元素执行指定的函数,没有赋值或者已经删除的元素将被忽略。

every(): 对数组中的每个元素都执行一次指定的函数(callback),直到此函数返回 false,如果发现这个元素,every 将返回 false,如果回调函数对每个元素执行后都返回 true ,every 将返回 true。它只对数组中的非空元素执行指定的函数,没有赋值或者已经删除的元素将被忽略

forEach()

对象方法包括构造函数中的方法以及构造函数原型上面的方法;

类方法,其实这里的类就是一个函数,在js中由于函数也是一个对象,所以可以为函数添加属性以及方法,这种方法在node中用的比较多;

原型方法一般用于对象实例共享,比如Person.prototype.sayName=function(){console.log(this.name);};在原型上面添加该方法,就能实现共享。这样就不用每一次初始化一个实例的时候,为其分配相应的内存了。

Unicode

Unicode源于一个很简单的想法:将全世界所有的字符包含在一个集合里,计算机只要支持这一个字符集,就能显示所有的字符,再也不会有乱码了。

Unicode只规定了每个字符的码点,到底用什么样的字节序表示这个码点,就涉及到编码方法。 最直观的编码方法是,每个码点使用四个字节表示,字节内容一一对应码点。这种编码方法就叫做UTF-32 UTF-8是一种变长的编码方法,字符长度从1个字节到4个字节不等。

UTF-16的编码长度要么是2个字节(U+0000到U+FFFF),要么是4个字节(U+010000到U+10FFFF)。 当我们遇到两个字节,发现它的码点在U+D800到U+DBFF之间,就可以断定,紧跟在后面的两个字节的码点,应该在U+DC00到U+DFFF之间,这四个字节必须放在一起解读。

JavaScript用的是UCS-2! 就是UTF-16取代了UCS-2,或者说UCS-2整合进了UTF-16。所以,现在只有UTF-16,没有UCS-2。 因为在JavaScript语言出现的时候,还没有UTF-16编码。

函数的定义方式有三种

  1. 函数声明:function o(a,b){return a+b;}
  2. 函数表达式:var o = function(a,b){return a+b;};
  3. 构造函数式:var o = new Function("a","b","return a+b");

接口模式

接口模式,主要是模拟java接口检测函数,确保接口的实现类必须实现接口中的方法:

装饰者模式,给对象动态添加职责的方式称为装饰者(decorator)模式。

观察者的使用场合就是:当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象需要改变的时候,就应该考虑使用观察者模式。

总的来说,观察者模式所做的工作就是在解耦,让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响到另一边的变化。

适配器模式的原理很简单,就是新增一个包装类,对新的接口进行包装以适应旧代码的调用,避免修改接口和调用代码。

适用场景:存在较多代码调用旧接口,为了避免修改旧代码和更换新接口,不影响现有实现方式的应用场景。