数组:push:从数组后面添加新元素;unshift:从数组前面添加新元素;shift:从数组前面删除元素;pop:从数组后面删除元素
concat:连接两个数组。不会改变数组,而只是返回一个连接后的副本。
join:将数组各元素通过指定的分隔符进行连接并构成一个字符串。
split:将字符串转换为数组。StringObject.split(char character,length)
appendchild(插入节点):将一个子元素添加到末尾
insertbefore(插入节点,参照节点):将一个子元素添加到参照节点的前面,若第二个参照节点为null,则默认插到最前面
removechild(要删除的子节点)
cloneNode(true||false) true:深层复制,还复制子节点;false:浅层复制,只复制本节点,不复制子节点。
《变量、作用域和内存问题》
JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。
只能给引用类型的值动态地添加属性。
引用类型在复制(或赋值)的时候仍指向堆内存中同一个对象。
@传递参数:
基本数据类型,参数传递属于按值传递。
引用数据类型,属于按地址传递。
@检测类型(不能检测类型的语言不是好语言)
result = variable instanceof class_name;
@垃圾收集
标记清除
变量进入环境时,就将这个变量标记为“ 进入环境”。变量离开环境,标记为“ 离开环境 ”
引用记数
跟踪每个值被引用的次数。如果引用次数变为0,则垃圾回收机制下次再运行的时候,它就会释放那些引用次数为零的值所占用的内存。
!!!!引用记数有一个问题:
function{
var objectA = new Object();
var objectB = new Object();
objectA.someOtherObject = objectB;
objectB.someOtherObject = objectA;
}
比如以上函数,objectA和objectB存在
循环引用,也就是说退出的时候A中仍有B的引用。B中也仍有A的引用。那么引用记数就永远不会释放这两个对象所占有的内存。
而标记清除方式则不会
《引用类型》
定义类时,属性名可以用字符串。即使定义时属性名用数值类型,解释器也会把它转化为字符串。
在访问对象的属性时不但可以用 class_name.variable 的形式,还可以用 class_name[string_name]的形式。第二种方法不仅使用于已知属性名,还适用于将用string类型保存属性名的情况。另外一种情况,比如属性名用到了空格(以及会导致语法错误的字符或关键字以及保留字),也可以使用方括号表示法。e.g.
person["first name"]="Mike";
@@@Array
数组中的每一项可以保存任何类型的数据,而且数组的大小是可以动态调整的。
在使用Array构造函数时也可以省去new操作符。数组有一个length属性,它不是只读的,通过设置这个属性,可以从数组的末尾移除项或向数组中添加新项。
array[array.length]=[(新添加的项)]
ECMAScript为Array提供了pop()和push()方法,以模仿栈数据类型
同时,也提供了shift()和push()方法,以模仿队列数据类型。
更有意思的是,Array也存在一个unshift()方法,它能在数组的末尾添加任意个项并返回新数组的长度。用处:与pop()函数合作,达到模仿反向队列数据类型.
值得注意的是Array的sort()函数,它比较的不是数组的元素值,而是将数组元素转变为字符串后再比较。但是sort可以接受一个比较函数作为参数。比较函数接受两个参数:如果第一个参数应该位于第二个参数之前则返回一个负数,如果第一个参数应该位于第二个参数之后则返回一个正数,二者相等则返回0.例如定义一个数值升序排序的比较函数:
function compare(value1,value2){
if(value1<value2){
return -1;
}else if(value1>value2){
return 1;
}
else{
return 0;
}
}
值得注意的还有concat、slice以及splice函数
concat会想创建当前数组的一个副本,然后将接受到的参数添加到这个副本的末尾,最后返回新构建的数组。
slice(m) 返回原数组从下标m起到末尾的子数组
slice(m,n)返回原数组从下标m到n的子数组。此种用法中其下标与python相同,即数组最后一个元素下标也可以认为是-1,往数组始位置负增长。
splice(m,n,"value1","value2",...,"valuen")返回原数组从下标m起删除n个元素后,并在删除位置插入任意个元素的数组。
@@@Function类型
函数名实际上是一个指向函数对象的指针,不会与某个函数绑定。
正因如此,JS没有函数重载机制。
函数内部拥有arguments参数。它是一个保存着所有传进来的参数的数组(是一个类数组对象),它还有一个callee属性,该属性是一个指针,指向拥有这个arguments对象的函数(即当前这个函数),比如经典的阶乘函数
function factorial(num){
if(num<=1){
return 1;
}else{
return num*factorial(num-1)
}
}
该函数表面上看上去没有问题,但是毫无疑问,这将函数体与函数名factorial紧紧耦合在了一起。改进:
function factorial(num){
if(num<=1){
return 1;
}else{
return num * arguments.callee(num-1);
}
}
《面向对象的程序设计》
ECMAScript中有两种属性:数据属性和访问器属性
@@@数据属性:
[[Configurable]]表示能否通过delete删除属性从而重新定义属性
[[Enumerable]]表示能否通过for-in循环返回属性。
[[Writable]]表示能否修改属性的值。
[[Value]]定义这个属性的数据值
var person={};
Object.defineProperty(person,"name",{
writable:false,
value:"Mike"
});
@@@创建对象
工厂模式:
function createPerson(name,age,job){
var o=new Object();
o.name=name;
o.age=age;
o.job=job;
o.sayName=function(){
alert(this.name);
};
return o;
}
构造函数模式:
function createPerson(name,age,job){
this.name=name;
this.age=age;
this.job=job;
this.sayName=function(){
alert(this.name);
};
}
原型模式:
function Person(){
}
Person.prototype.name=name;
Person.prototype.age=age;
Person.prototype.job=job;
Person.prototype.sayName=function(){
alert(this.name);
};
组合使用构造函数模式和原型模式:
function Person(name,age,job){
this.name=name;
this.job=job;
this.age=age;
this.friends=["Shelby","Court"];
}
Person.prototype={
constructor:Person,
sayName:function(){
alert(this.name);
}
}
动态原型模式
function Person(name,age,job){
this.name=name;
this.job=job;
this.age=age;
if(typeof this.sayName != "function"){
Person.prototype.sayName = function(){
alert(this.name);
}
};
}
寄生构造函数模型(parasitic)
寄生在“宿主类”的同时,又“生长”出自己特有的功能。比如我们想创建一个具有额外方法的特殊数组,由于不能直接使用Array构造函数,我们可以选择寄生模式:
function SpecialArray(){
var values = new Array();
values.push.apply(values,arguments);
values.toPipedString = function(){
return this.join("|");
};
return values;
}
稳妥构造函数模式
function Person(name,age,job){
var o = new Object();
o.sayName = function(){
alert(name);
};
return o;
}
@@@继承
要理解JavaScript中的继承离不开对prototype的理解:
prototype属性可算是JavaScript与其他面向对象语言的一大不同之处。prototype就是“一个给类的对象添加方法的方法”,使用prototype属性,可以给类动态地添加方法,以便在JavaScript中实现“继承”的效果。
具体来说,prototype 是在 IE 4 及其以后版本引入的一个针对于某一类的对象的方法,当你用prototype编写一个类后,如果new一个新的对象,浏览器会自动把prototype中的内容替你附加在对象上。这样,通过利用prototype就可以在JavaScript中实现成员函数的定义,甚至是“继承”的效果。
对于javascript本身而言是基于对象的,任何元素都可以看成对象。然而类型和对象是不同的,而我们所讲的prototype属性即是基于类型的一种属性。对于prototype的基本使用就如对象的创建及属性赋值一样的简单。直接通过赋值操作即可完成属性的创建。
prototype在继承中的使用:
1、将ClassA的一个实例赋值给ClassB.prototype,则 ClassB就继承了ClassA的所有属性。
2、js的原型继承是引用原型,而不是复制原型。当修改原型时会导致所有的实例变化。
3、每个子类对象都执行同一个原型的引用,所以子类对象中的原型成员实际是同一个.
4、子类对象的写操作只访问子类对象的成员,相互之间不产生影响。写一定是写子类,读则要看是否子类中有,若有则读子类,若无则读原型。
5、构造子类时,原型的构造函数不会被执行.
6、在子类对象中访问原型的成员对象,会影响到其它对象.