0. 类的创建
JavaScript是一种基于原型继承的面向对象语言。当然,很多时候我们把它当作一种面向过程的语言来看待,因为原型继承非常不常见,理解和使用都非常别扭。
《高级编程》一书提到了许多类的创建模式,比较推荐的是“构造函数和原型集成混合模式”。这种模式将类的构造函数(function)和 它的prototype 分开定义,兼顾了传统的类构造习惯和JS本身特点,应该算是一种最佳的折中方案。类似下面这段代码中所定义的 classA:
当我们对一个函数使用了 new 关键字后,JS会将这个函数作为类构造函数,并返回这个函数(或者类)的原型对象的“副本”。这时,函数本身的返回值会被忽略;尽管如此,我们在构造函数中也尽量不要返回什么东西,因为印象里,在某个浏览器中,构造函数 return this 的话,会造成溢出。
需要注意的是,在构造函数中的 this 虽然和 prototype 有某种对应关系,但 this 不是一个简单的对 prototype 的复制。在周爱民的《精髓》一书中,将实例中的 this 和 prototype 形容为两张表;在调用属性时,以 this 作为优先查询的表,查询不到时,再去 prototype 中查找。
我们现在可以在 Chrome 浏览器中log一下刚才的实例化的 a 变量,两者的关系能更明显一些。首先我们修改一下 classA ,在构造函数中为实例增加一个同名的 show 方法:
看一下控制台:
这里可以比较清楚的看到“两张表”:一个是实例本身,一个是 __proto__ 对象。虽然实例本身和原型中都有 show 方法,但由于实例自身的 show 层级较高,所以被优先执行了。
我们也可以理解为:构造函数通过 this 维护“优先表”,prototype 是基础对象库。
运行结果自然是 "in constructor" 。
1. 通过原型副本继承
先看一段“不好”的代码:
结合 classA 的代码,这段代码的输出结果是 “classB” 。你可能已经看出来了,这种继承有两个问题:
1) classB.prototype 是 classA.prototype 的指针,所以当我们修改 classB.prototype 时,也就是在修改 classA.prototype ;
2) classA 构造函数中对“优先表”的构造无法传递到 classB 中,所以b.show() 的结果不是我们期待的 “in constructor” 。
所以“好”的方式,应该满足两个条件:一是创建一个 classA.prototype 的副本作为 classB.prototype ,二是能兼顾到构造函数。如果仅仅是满足前者的话,我们做一次对象复制既可;同时兼顾后者的话,最佳做法就是:实例化一个 classA 作为 classB.prototype。
这次的输出结果就对了:当我们调用classB的实例 b.show 的时候,b自然是首先在“优先表”中查找,没找到后,在 __proto__ 中查找。而 __proto__ 是一个classA的实例,“优先表”中的show就被调用了。在show中,由于b的“优先表”优先级较高,b.name被输出,所以结果是 “classB”。
我们改写一下classB.prototype和构造函数,看一下对二者的修改都造成了哪些影响:
Zen CSS properties
Based on CSS 3 draft specification
Property AliasSpecial Rules
@import url(); @i@mediaprint{ @m}@font-face { @f
font-family:;
src:url();
}!important !expression() exp
Properties Groups
Sorting Methods
- Positioning
- Box behavior and properties
- Sizing
- Color appearance
- Special content types
- Text
- Visual properties
Positioning
position:; posposition:static; pos:s
position:absolute; pos:a
position:relative; pos:r
position:fixed; pos:ftop:; t
top:auto; t:aright:; r
right:auto; r:abottom:; b
bottom:auto; b:aleft:; l
left:auto; l:az-index:; z
z-index:auto; z:a
Box behavior and properties
float:; flfloat:none; fl:n
float:left; fl:l
float:right; fl:rclear:; cl
clear:none; cl:n
clear:left; cl:l
clear:right; cl:r
clear:both; cl:bdisplay:; d
display:none; d:n
display:block; d:b
display:inline; d:i
display:inline-block
用 js有很久了,但都没有深究过js的数组形式。偶尔用用也就是简单的string.split(char)。这段时间做的一个项目,用到数组的地方很多, 自以为js高手的自己居然无从下手,一下狠心,我学!呵呵。学了之后才知道,js数组的功能强大很,远比VB,C#强多了,大家慢慢看吧
1、数组的创建
var arrayObj = new Array([size]); //创建一个数组并指定长度,注意不是上限,是长度
var arrayObj = new Array([element0[, element1[, ...[, elementN]]]]); //创建一个数组并赋值
要说明的是,虽然第二种方法创建数组指定了长度,但实际上所有情况下数组都是变长的,也就是说即使指定了长度为5,仍然可以将元素存储在规定长度以外的,注意:这时长度会随之改变。
2、数组的元素的访问
arrayObj[1]= "这是新值"; //给数组元素赋予新的值
3、数组元素的添加
arrayObj.unshift([item1 [item2 [. . . [itemN ]]]]);// 将一个或多个新元素添加到数组开始,数组中的元素自动后移,返回数组新长度
arrayObj.splice(insertPos,0,[item1[, item2[, . . . [,itemN]]]]);//将一个或多个新元素插入到数组的指定位置,插入位置的元素自动后移,返回""。
4、数组元素的删除
arrayObj.shift(); //移除最前一个元素并返回该元素值,数组中元素自动前移
arrayObj.splice(deletePos,deleteCount); //删除从指定位置deletePos开始的指定数量deleteCount的元素,数组形式返回所移除的元素
5、数组的截取和合并
arrayObj.concat([item1[, item2[, . . . [,itemN]]]]); //将多个数组(也可以是字符串,或者是数组和字符串的混合)连接为一个数组,返回连接好的新的数组
6、数组的拷贝
arrayObj.concat(); //返回数组的拷贝数组,注意是一个新的数组,不是指向
7、数组元素的排序
arrayObj.sort(); //对数组元素排序,返回数组地址
8、数组元素的字符串化
toLocaleString 、toString 、valueOf:可以看作是join的特殊用法,不常用
二、数组对象的3个属性
1、length 属性
Length属性表示数组的长度,即其中元素的个数。因为数组的索引总是由0开始,所以一个数组的上下限分别是:0和length-1。和其他大多数语言不同的是,JavaScript数组的length属性是可变的,这一点需要特别注意。当length属性被设置得更大时,整个数组的状态事实上不会发生变化,仅仅是length属性变大;当length属性被设置得比原来小时,则原先数组中索引大于或等于length的元素的值全部被丢失。下面是演示改变length属性的例子: