//定义一个对象
var obj = new Object();
//动态创建属性name
obj.name = "an object";
//动态创建属性sayHi
obj.sayHi = function(){
return "Hi";
}
obj.sayHi();
在JavaScript中,包含三种基本的数据类型,字符串(String),数值(Number),布尔值(boolean),下面是一些简单的例子:
var str = "Hello, world";//字符串
var i = 10;//整型数
var f = 2.3;//浮点数
var b = true;//布尔值
我们可以分别查看变量的值及变量的类型:
print(str);
print(i);
print(f);
print(b);
print(typeof str);
print(typeof i);
print(typeof f);
print(typeof b);
注意,在此处使用的print()函数为rhino解释器的顶层对象的方法,可以用来打印字符串,通常情况下,在客户端,程序员多使用alert()进行类似的动作,alert()是浏览器中JavaScript解释器的顶层对象(window)的一个方法。
Hello, world
10
2.3
true
string
number
number
Boolean
在JavaScript中,所有的数字,不论是整型浮点,都属于“数字”基本类型。typeof是一个一元的操作符.
对象类型不是对象本身,而是指一种类型,我们在第三章会对对象进行详细的讨论,此处的对象包括,对象(属性的集合,即键值的散列表),数组(有序的列表),函数(包含可执行的代码)。
对象类型是一种复合的数据类型,其基本元素由基本数据类型组成,当然不限于基本类型,比如对象类型中的值可以是其他的对象类型实例,我们通过例子来说明:
var str = "Hello, world";
var obj = new Object();
obj.str = str;
obj.num = 2.3;
var array = new Array("foo", "bar", "zoo");
var func = function(){
print("I am a function here");
}
可以看到,对象具有属性,如obj.str, obj.num,这些属性的值可以是基本类型,事实上还可以更复杂,我们来看看他们的类型:
print(typeof obj);
print(typeof array);
print(typeof func);
//将打印出
object
object
function
var str = "JavaScript Kernal";
print(str.length);//打印17
对象转换为基本类型则是通过这样的方式:通过调用对象的valueOf()方法来取得对象的值,如果和上下文的类型匹配,则使用该值。如果valueOf取不到值的话,则需要调用对象的toString()方法,而如果上下文为数值型,则又需要将此字符串转换为数值。
valueOf()的作用是,将一个对象的值转换成一种合乎上下文需求的基本类型,toString()则名副其实,可以打印出对象对应的字符串,当然前提是你已经“重载”了Object的toString()方法。
事实上,这种转换规则会导致很多的问题,比如,所有的非空对象,在布尔值环境下,都会被转成true,
var x = 3;
var y = x + "2";// => 32
var z = x + 2;// => 5
if(datamodel.item){
//do something...
}else{
datamodel.item = new Item();
}
这种写法事实上具有更深层次的含义:
应该注意到,datamodel.item是一个对象(字符串,数字等),而if需要一个boolean型的表达式,所以这里进行了类型转换。在JavaScript中,如果上下文需要boolean型的值,则引擎会自动将对象转换为boolean类型。转换规则为,如果该对象非空,则转换为true,否则为false.因此我们可以采取这种简写的形式。
function handleMessage(message, handle){
if(typeof handle == "function"){
return handle(message);
}else{
throw new Error("the 2nd argument should be a function");
}
}
但是,typeof并不总是有效的,比如下面这种情况:
var obj = {};
var array = ["one", "two", "three", "four"];
print(typeof obj);//object
print(typeof array); //object
运行结果显示,对象obj和数组array的typeof值均为”object”,这样我们就无法准确判断了,这时候,可以通过调用instanceof来进行进一步的判断:
print(obj instanceof Array);//false
print(array instanceof Array);//true
第一行代码返回false,第二行则返回true。因此,我们可以将typeof操作符和instanceof操作符结合起来进行判断。
[]可以作用于对象,一般而言,对象中的属性的值是通过点(.)运算符来取值,如:
var object = {
field : "self",
printInfo : function(){
print(this.field);
}
}
object.field;
object.printInfo();
但是考虑到这样一种情况,我们在遍历一个对象的时候,对其中的属性的键(key)是一无所知的,我们怎么通过点(.)来访问呢?这时候我们就可以使用[]运算符:
for(var key in object){
print(key + ":" + object[key]);
}
运行结果如下:
field:slef
printInfo:function (){
print(this.field);
}
点运算符的左边为一个对象(属性的集合),右边为属性名,应该注意的是右边的值除了作为左边的对象的属性外,同时还可能是它自己的右边的值的对象:
var object = {
field : "self",
printInfo : function(){
print(this.field);
},
outter:{
inner : "inner text",
printInnerText : function(){
print(this.inner);
}
}
}
object.outter.printInnerText();
这个例子中,outter作为object的属性,同时又是printInnerText()的对象。
但是点(.)操作符并不总是可用的,考虑这样一种情况,如果一个对象的属性本身就包含点(.)的键(self.ref),点操作符就无能为力了:
var ref = {
id : "reference1",
func : function(){
return this.id;
}
};
var obj = {
id : "object1",
"self.ref" : ref
};
当我们尝试访问obj的”self.ref”这个属性的时候:obj.self.ref,解释器会以为obj中有个名为self的属性,而self对象又有个ref的属性,这样会发生不可预知的错误,一个好的解决方法是使用中括号([])运算符来访问:
print(obj["self.ref"].func());
运算符==读作相等,而运算符===则读作等同。这两种运算符操作都是在JavaScript代码中经常见到的,但是意义则不完全相同,简而言之,相等操作符会对两边的操作数做类型转换,而等同则不会。我们还是通过例子来说明:
print(1 == true);
print(1 === true);
print("" == false);
print("" === false);
print(null == undefined);
print(null === undefined);
运行结果如下:
true
false
true
false
true
false
相等和等同运算符的规则分别如下:
相等运算符
如果操作数具有相同的类型,则判断其等同性,如果两个操作数的值相等,则返回true(相等),否则返回false(不相等).
如果操作数的类型不同,则按照这样的情况来判断:
l null和undefined相等
l 其中一个是数字,另一个是字符串,则将字符串转换为数字,在做比较
l 其中一个是true,先转换成1(false则转换为0)在做比较
l 如果一个值是对象,另一个是数字/字符串,则将对象转换为原始值(通过toString()或者valueOf()方法)
l 其他情况,则直接返回false
等同运算符
如果操作数的类型不同,则不进行值的判断,直接返回false
如果操作数的类型相同,分下列情况来判断:
l 都是数字的情况,如果值相同,则两者等同(有一个例外,就是NaN,NaN与其本身也不相等),否则不等同
l 都是字符串的情况,与其他程序设计语言一样,如果串的值不等,则不等同,否则等同
l 都是布尔值,且值均为true/false,则等同,否则不等同
l 如果两个操作数引用同一个对象(数组,函数),则两者完全等同,否则不等同
l 如果两个操作数均为null/undefined,则等同,否则不等同
//声明一个对象
var jack = new Object();
jack.name = "jack";
jack.age = 26;
jack.birthday = new Date(1984, 4, 5);
//声明另一个对象
var address = new Object();
address.street = "Huang Quan Road";
address.xno = "135";
//将addr属性赋值为对象address
jack.addr = address;
JSON的应用场景是:当一个函数拥有多个返回值时,在传统的面向对象语言中,我们需要组织一个对象,然后返回,而JavaScript则完全不需要这么麻烦,比如:
function point(left, top){
this.left = left;
this.top = top;
//handle the left and top
return {x: this.left, y:this.top};
}
直接动态的构建一个新的匿名对象返回即可:
var pos = point(3, 4);
//pos.x = 3;
//pos.y = 4;
使用JSON返回对象,这个对象可以有任意复杂的结构,甚至可以包括函数对象。
在实际的编程中,我们通常需要遍历一个JavaScript对象,事先我们对对象的内容一无所知。怎么做呢?JavaScript提供了for..in形式的语法糖:
for(var item in json){
//item为键
//json[item]为值
}
函数在JavaScript中可以:
Ø 被赋值给一个变量
Ø 被赋值为对象的属性
Ø 作为参数被传入别的函数
Ø 作为函数的结果被返回
Ø 用字面量来创建
在JavaScript中,函数的参数是比较有意思的,比如,你可以将任意多的参数传递给一个函数,即使这个函数声明时并未制定形式参数。
事实上,JavaScript在处理函数的参数时,与其他编译型的语言不一样,解释器传递给函数的是一个类似于数组的内部值,叫arguments。
function sum(){
var result = 0;
for(var i = 0, len = arguments.length; i < len; i++){
var current = arguments[i];
if(isNaN(current)){
throw new Error("not a number exception");
}else{
result += current;
}
}
return result;
}
print(sum(10, 20, 30, 40, 50));
print(sum(4, 8, 15, 16, 23, 42));//《迷失》上那串神奇的数字
print(sum("new"));
函数sum没有显式的形参,而我们又可以动态的传递给其任意多的参数,那么,如何在sum函数中如何引用这些参数呢?这里就需要用到arguments这个伪数组了,运行结果如下:
150
108
Error: not a number exception
赋值给一个变量:
//声明一个函数,接受两个参数,返回其和
function add(x, y){
return x + y;
}
var a = 0;
a = add;//将函数赋值给一个变量
var b = a(2, 3);//调用这个新的函数a
print(b);
这段代码会打印”5”,因为赋值之后,变量a引用函数add,也就是说,a的值是一个函数对象(一个可执行代码块),因此可以使用a(2, 3)这样的语句来进行求和操作。
赋值为对象的属性:
var obj = {
id : "obj1"
}
obj.func = add;//赋值为obj对象的属性
obj.func(2, 3);//返回5
事实上,这个例子与上个例子的本质上是一样的,第一个例子中的a变量,事实上是全局对象(如果在客户端环境中,表示为window对象)的一个属性。而第二个例子则为obj对象,由于我们很少直接的引用全局对象,就分开来描述。
作为参数传递:
//高级打印函数的第二个版本
function adPrint2(str, handler){
print(handler(str));
}
//将字符串转换为大写形式,并返回
function up(str){
return str.toUpperCase();
}
//将字符串转换为小写形式,并返回
function low(str){
return str.toLowerCase();
}
adPrint2("Hello, world", up);
adPrint2("Hello, world", low);
运行此片段,可以得到这样的结果:
HELLO, WORLD
hello, world
var array = new Array(1, 2, 3, 4, 5);
print(array.length); //得到数组长度
另一个与其他语言的数组不同的是,字符串也可以作为数组的下标,事实上,在JavaScript的数组中,字符串型下标和数字型的下标会被作为两个截然不同的方式来处理,一方面,如果是数字作为下标,则与其他程序设计语言中的数组一样,可以通过index来进行访问,而使用字符串作为下标,就会采用访问JavaScript对象的属性的方式进行,毕竟JavaScript内置的Array也是从Object上继承下来的。比如:
var stack = new Array();
stack['first'] = 3.1415926;
stack['second'] = "okay then.";
stack['third'] = new Date();
for(var item in stack){
print(typeof stack[item]);
}
运行结果为:
number
string
object
向数组中添加元素:
var array = [];
array.push(1);
array.push(2);
array.push(3);
array.push("four");
array.push("five");
array.push(3.1415926);
前面提到过,JavaScript的数组有列表的性质,因此可以向其中push不同类型的元素,接上例:
var len = array.length;
for(var i = 0; i < len; i++){
print(typeof array[i]);
}
结果为:
number
number
number
string
string
number
弹出数组中的元素:
for(var i = 0; i < len; i++){
print(array.pop());
}
print(array.length);
运行结果如下,注意最后一个0是指array的长度为0,因为这时数组的内容已经全部弹出:
3.1415926
five
four
3
2
1
0
join,连接数组元素为一个字符串:
array = ["one", "two", "three", "four", "five"];
var str1 = array.join(",");
var str2 = array.join("|");
print(str1);
print(str2);
运行结果如下:
one,two,three,four,five
one|two|three|four|five
连接多个数组为一个数组:
var another = ["this", "is", "another", "array"];
var another2 = ["yet", "another", "array"];
var bigArray = array.concat(another, another2);
结果为:
one,two,three,four,five,this,is,another,array,yet,another,array
从数组中取出一定数量的元素,不影响数组本身:
print(bigArray.slice(5,9));
结果为:
this,is,another,array
slice方法的第一个参数为起始位置,第二个参数为终止位置,操作不影响数组本身。下面我们来看splice方法,虽然这两个方法的拼写非常相似,但是功用则完全不同,事实上,splice是一个相当难用的方法:
bigArray.splice(5, 2);
bigArray.splice(5, 0, "very", "new", "item", "here");
第一行代码表示,从bigArray数组中,从第5个元素起,删除2个元素;而第二行代码表示,从第5个元素起,删除0个元素,并把随后的所有参数插入到从第5个开始的位置,则操作结果为:
one,two,three,four,five,very,new,item,here,another,array,yet,another,array
我们再来讨论下数组的排序,JavaScript的数组的排序函数sort将数组按字母顺序排序,排序过程会影响源数组,比如:
var array = ["Cisio", "Borland", "Apple", "Dell"];
print(array);
array.sort();
print(array);
执行结果为:
Cisio,Borland,Apple,Dell
Apple,Borland,Cisio,Dell
这种字母序的排序方式会造成一些非你所预期的小bug,比如:
var array = [10, 23, 44, 58, 106, 235];
array.sort();
print(array);
得到的结果为:
10,106,23,235,44,58
可以看到,sort不关注数组中的内容是数字还是字母,它仅仅是按照字母的字典序来进行排序,对于这种情况,JavaScript提供了另一种途径,通过给sort函数传递一个函数对象,按照这个函数提供的规则对数组进行排序。
function sorter(a, b){
return a - b;
}
var array = [10, 23, 44, 58, 106, 235];
array.sort(sorter);
print(array);
函数sorter接受两个参数,返回一个数值,如果这个值大于0,则说明第一个参数大于第二个参数,如果返回值为0,说明两个参数相等,返回值小于0,则第一个参数小于第二个参数,sort根据这个返回值来进行最终的排序:
10,23,44,58,106,235
当然,也可以简写成这样:
array.sort(function(a, b){return a - b;});//正序
array.sort(function(a, b){return b - a;});//逆序
邮箱地址正则var emailval = /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/;
emailval.test("kmustlinux@hotmail.com");//true