1. javascript 伪协议
javascript: document.write("use js in browser address bar directly"); void(0);
利用 javascript 伪协议可以在浏览器地址栏中直接写 javascript 进行测试。默认情况下, javascript 伪协议会将程序执行结果在一个新的页面中显示,要阻止这种情况的话,程序需要返回 undefined, 而 void(0) 的作用就是返回 undefined.
2. undefined
undefined 是 js 中的一个特殊值,它代表 ' 无 ' ;因为 js 没有强制检验对象存在的机制,所以任何一个未经定义和使用的标识,都可以用 " 无 " 来表示。这个 " 无 " 在 Javascript 文法中就是 undefined 。这种情况在 Java 中是不存在的,所以 Java 中没有类似 undefined 的机制。
2.1 产生 undefined 变量的情形
1) 变量未声明,
2) 变量声明了但未赋值
3) 任何一个不带 return 指令的函数运算的默认返回值都是 undefined 。
4) 使用了 return, 但缺省了 return 的表达式,那么函数的返回值依然是 undefined
5) 使用 void, void(0);
6) 由于 JS 中函数的实参和形参的数量可以不相同,如果实参量少于形参数量,那么多出来的形参的值就是 undefined;
2.2 undefined 变量的使用
一个类型为 undefined 的变量,如果直接使用,通常会抛出一个系统级别的 Error, 只有 delete 和 typeof 例外。
所以如果要判断一个变量是否是 undefined 的,不能使用
if(x) {}; // 假定 x 是一个 undefined 类型的变量,这条语句会抛出异常
而要使用
if(typeof(x)=="undefined") {}
但是,如果是下面这种情况,
var x; //x 定义了但是没有赋值,所以是 undefined 。
if(x) {}; //x 是 undefined, 但这条语句不会抛出异常。
但是,如果是一个类型为 undefined 的对象的属性,是可以直接使用的
例:
var a = new Object();
if (!a.x) { // 虽然 a.x 是 undefined 的,但是这种情况下不会出错 , !a.x 返回 true, 详见 14 条
alert(typeof(a.x)); // 输出 undefined
}
函数的形参也有同样的特性
function add(a, b){
if(!b) b=30; // 如果在调用时, b 没有被赋值, b 就是 undefined, 但这种情况下, b 依然可以使用。
return a+b;
}
alert(add(3));
3. null
null 代表 " 空 " ,它和 undefined 不同, " 空 " 依然是一种存在,而 " 无 " 则是存在的对立面。
x=null; typeof(x); // 返回 object , 注意 null 可以理解为将要引用对象,但它本身不是对象,不要把它看作特殊的对象。
4. typeof
根据上面对 undefined 和 null 的认识,可以得到如下结论 , 注意返回 undefined 的两种情况, 1. 变量未声明, 2. 变量声明了但未赋值
typeof(x); // 变量未声明, 返回 "undefined"
var x; typeof(x); // 变量声明了但未赋值,返回 "undefined"
var x=null; typeof(x); // 返回 "object"
x=null; typeof(x); // 返回 "object" , 注意 null 可以理解为将要引用对象,但它本身不是对象,不要把它看作特殊的对象。
Ø typeof 返回值
typeof 对数值,字符串或者布尔值三种原始类型分别返回: "number", "string" 和 "boolean" 。对对象,数组和 null, 它返回的是 "object" 。对函数,类和闭包,它返回 "function" 。
由于 typeof 对所有对象和数组类型返回的都是 "object" ,所以它只有在区别对象和原始类型时才有效;要区别一种对象和另一种对象,必须使用其他方法,例如
instanceof 运算符和 constructor 属性。
例:
if(typeof(object)=="type") || this.constructor == type || this instanceof type) return true;
5. constructor 属性
constructor 可以获得一个对象的构造函数, typeof(objectX.constructor)=="function" 。
例:
function Point(x,y) {
this.x=x;
this.y=y;
this.f = function(){alert(typeof(this.constructor));
}
var p = new Point(1,2);
p.f(); // 输出: "function"
alert(typeof(p.constructor));// 输出: "function"
p.add = function (x, y) {
new this.constructor(this.x+x, this.y+y); //contructor 可以直接进行函数调用
}
6. JS 中的文件的依赖关系
js 中的函数的定义需要放在使用的前面。如果函数的定义和使用被放置在了不同的文件中,需要把这些文件都包含在网页中,如下所示:
<script type="text/javascript" src="js/testjs.js"/></script>
<script type="text/javascript" src="js/test2js.js"/></script>
这种情况下,就需要使用者对各个文件的依赖关系要很清楚,在复杂的项目里面就比较吃力。
Dojo 框架实现了包的机制,可以自动处理依赖关系,非常方便。
7. 客户端生命周期
客户端生命周期起始于浏览器开始装载某个请求的特定数据,结束于浏览器发起的一个新的请求 ( 页面跳转或刷新 ) ,分为两个阶段。
初始化阶段:装载页面数据
运行阶段:消息等待,事件处理
一个比较好的习惯是把除声明以外的所有的脚本指令都放到运行阶段执行,避免初始化阶段 DOM 元素加载失败或者低级的次序问题而导致脚本失效。
Ø onload 事件
元素的 onload 事件将在元素被完全加载后由浏览器发起。利用 body 元素的 onload 事件就可以实现将所有运行指令放在 body 元素及所有子元素被加载以后执行,避免了脚本的失效。
8. 推荐的的如何放置 javascript 代码的例子:
<html>
<head>
<script>
...
<!--
// 这里放置函数和闭包
function add(x, y)
{
return x+y;
}
-->
</script>
</head>
<script>
<!--
// 这里放置全局变量
var a = 100;
var b = 200;
-->
</script>
<body>
</body>
</html>
注:只要不在函数内部声明的变量似乎都是全局的,上面的例子中的全局变量声明即使放到 <head> 或 <body> 内部都是可以的。
9. with 关键字
var oMemery = {
numStack: [];
}
with(object) {
numStack[0]=1;
}
使用 with 的性能比不使用要差,所以不要在循环语句中使用它,尽量少用。
10. Array
1) 数组的创建,用 new Array() 或 [] ;
2) 直接调用 Array() 函数和通过 new 运算符将 Array() 作为构造函数调用的结果是一样的。例如: var a = Array(1, 2, 3) 和 var a = new Array(1, 2, 3) 等价。
3) 由于 JS 是一种动态类型语言,因此数组元素不必具有相同的类型,这和 Java 是不同的。
例:
var a = new Array();
a[0] = 1.2;
a[1] = "JS";
a[2] = true;
a[3] = {x:1, y:2};
a[4] = new Array {1, 2, 3};
4) 用 new Array() 创建数组可以包含参数,如果参数个数大于 1 ,那么这些参数为数组对应的元素进行初始化;如果参数的个数等于 1 并且为数字,该参数指定的是数组的长度。
例 :
var a = new Array {1, 2, 3};
var b = new Array(10);
5) 数组可以用 length 属性取得长 ; 注意当数组被当作普通对象或哈希表来使用的时候 ( 也就是说普通对象采用数组语法 [] 来访问的时候 ) ,数组的 length 属性是不起作用的
6) length 属性可以读,也可以写,通过改变 length 的值,可以在数组的末尾添加或删除元素。例如,设置数组的 length 为 0, 可以清除数组中的所有元素。如果给 length 设置了一个比它当前值小的值,那么数组将被截断,这个长度之外的元素都会被抛弃,他们的值也就丢失了;如果给 length 设置的值比当前的值大,那么新的,未初始化的元素就会被添加到数组末尾。
7) delete 操作虽然能够删除数组元素,但它并不会改变数组的 length 属性,因此如果要删除数组某个下标值之后的值,应当直接修改 length 的值。
8) 数组还提供了一些插入和删除数组元素的方法,这些方法会恰当的改变数组 length 的值,所以要尽量使用这些方法,尽少使用 delete 。
9) 数组常量中还可以直接存放未初始化的元素,只要在逗号之间省去该元素的值就可以了
var sparseArray = [1,,,,5];
10) 利用 Array 的 apply 方法可以很容易的将 Argument 和其他一些带下标的对象转换为数组:
function test () {
// 将传给函数 test() 的参数列表转换为数组对象返回
return Array.apply(this, arguments);
}
Ø 数组常用操作
1) push() 和 pop() ,在数组的末尾插入或删除一个元素
var a = new Array() ;
a.push(1);
a.push(2, 3, 4); // 数组现在是 [1, 2, 3, 4]
var b = a.pop(); // 数组现在是 [1,2,4]
2 ) unshift 和 shift, 在数组的头部插入或删除元素。使用 unshift 可以将一个或多个元素插入到数组的头部,使用 shift 则依次从头部删除他们。
var a = new Array();
a.unshift(1);
a.unshift(2,3,4); // 数组现在是 [2, 3, 4, 1], 注意顺序
alert(a.length); // 输出: 4
var b = a.shift(); // 数组现在是 [3,4,1]
alert(a.length); // 输出: 3
3) join
join() 方法可以把一个数组的所有元素都转换成字符串,然后再把他们连接起来。你可以指定一个可选的字符串来分隔结果字符串中的元素。如果没有指定分隔字符串,那么默认使用逗号分割元素。
例:
var a = [1,2,3];
var s = a.join(); //s 的值是字符串 ”1,2,3”
var b = [“A”, “k”, “I”, “r”, “a”];
var name = b.join(“”); //name 的值是 Akira
4) reverse
reverse 方法颠倒数组元素的顺序并返回颠倒后的数据。它在原数组上执行这一操作,也就是说它并不是创建一个重新排列的新数组,而是在已经存在的数组中对元素进行重排。
例:
var a = new Array(1, 2, 3);
a.reverse();
var s = a.join(); // 现在 s 是 ”3,2,1”, a 是 [3,2,1]
5) sort
对数组排序,它可以接受一个参数,这个参数是比较两个元素值得一个闭包,如果这个参数缺省,那么 sort 方法将按照默认的规则对元素进行排序。
例:
var arr = [3,2,1,6,7];
arr.sort();
6) concat
该方法创建并返回一个数组,这个数组包含了调用 concat() 的原始数组的元素,其后跟随的是 concat 的参数,如果其中有些参数是数组,那么它将被展开,其元素将被添加到返回的数组中,但是要注意, concat() 并不能递归的展开一个元素为数组的数组。
例: