《JavaScript高级程序设计》学习笔记

数组: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、在子类对象中访问原型的成员对象,会影响到其它对象.


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值