1.2 JavaScript语言特性
JavaScript是一门动态的、弱类型、基于原型的脚本语言。在JavaScript中“一切皆对象”,在这一方面,它比其他的面向对象的语言来得更为彻底。即使作为代码本身载体的函数(function),也是对象,数据与代码的界限在JavaScript中已经相当模糊。虽然它被广泛应用在Web客户端,但是其应用范围远远未局限于此。下面就这几个特点分别介绍。
1.2.1 动态性
动态性是指,在一个JavaScript对象中,要为一个属性赋值,我们不必事先创建一个字段,只需要在使用的时候做赋值操作即可。如下例:
//定义一个对象
var obj = new Object();
//动态创建属性name
obj.name = "an object";
//动态创建属性sayHi
obj.sayHi = function(){
return "Hi";
}
obj.sayHi();
当不需要一个对象的属性时,我们可以很轻易地将其从对象上删除。
obj.name
"juntao"
delete obj.name
obj.name
undefined
假如我们使用Java语言,代码可能会是这样:
class Obj{
String name;
Function sayHi;
public Obj(Sting name, Function sayHi){
this.name = name;
this.sayHi = sayHi;
}
}
Obj obj = new Obj("an object", new Function());
可以看出,在静态语言中,需要预先定义好对象需要什么属性,属性自身的类型是什么,当定义完成之后,对象的结构就定下来了,之后都保持这种结构而无法更改。通常对象可能会继承一些自己用不到的方法,而且也无法删除。
另一个有趣的例子是动态地访问一个JavaScript对象的属性。
var key = "property";
print(key);
"property"
var obj = {
property: "my property"
}
print(obj[key]);
"my property"
应该注意到key是一个变量,其值为“property”,当执行obj[key]时,key被求值为“property”,然后去除obj["property"],这个特性可以使得代码更加简洁清晰,比如可以动态地从代码中生成对象的属性名,然后去除属性值等。
1.2.2 弱类型
与Java、C/C++不同,JavaScript是弱类型的,它的数据类型无需在声明时指定,解释器会根据上下文对变量进行实例化,比如:
//定义一个变量s,并赋值为字符串
var s = "text";
print(s);
//赋值s为整型
s = 12+5;
print(s);
//赋值s为浮点型
s = 6.3;
print(s);
//赋值s为一个对象
s = new Object();
s.name = "object";
print(s.name);
结果为:
text
17
6.3
Object
在JavaScript中,类型是和值关联的,而不是和变量关联。弱类型具有很大的灵活性,在定义变量时无须显式声明。不过,弱类型也有其不利的一面,比如在开发面向对象的JavaScript的时候,没有类型的判断将会是比较麻烦的问题,不过我们可以通过别的途径来解决此问题。
1.2.3 面向对象
虽然与主流的面向对象语言中的面向对象的概念大相径庭,但是在JavaScript中,一切都是对象!只不过JavaScript中,这一点更为彻底一些,甚至用以表达逻辑的函数/代码本身也是对象,比如代码本身可以作为参数传递给其他的代码。
var array = [1, 2, 3, 4, 5];
array.map(function(item){
return item * 2;
});
运行结果如下。
[2, 4, 6, 8, 10]
数组array中有5个元素,每个元素是一个数字。数组的map方法会接受一个匿名函数,这样对于数组中的每个元素,都会调用这个匿名函数(返回元素乘以2的值),最后把结果放入结果数组。有意思的是此处的map,它可以接受函数作为参数。map函数可以处理更为复杂的场景,比如数组中的每个元素都是一个复杂对象。
var staff = [
{name: 'abruzzi', age: 24},
{name: 'bajmine', age: 26},
{name: 'chris', age: 25}
];
staff.map(function(item){
return item.name.toUpperCase();
});
运行结果如下。
['ABRUZZI', 'BAJMINE', 'CHRIS']
在上例中,map用以将数组staff中的每个元素的name属性取出,转换为大写字母,并生成新的数组,而将对于那些不关心的其他属性(比如此处的age)排除在结果集之外。
另一个例子是与map很类似的函数filter,用于过滤数组中满足某些条件的元素,filter的使用方法与map一样,也接受一个函数。
staff.filter(function(item){
return item.age > 24;
});
这样结果中仅包含age大于24的条目。
[
{name: 'bajmine', age: 26},
{name: 'chris', age: 25}
]
这两个例子中,可以看到函数可以像其他任何数据类型(字符串、数字)那样,被轻易地传递给其他函数。在JavaScript中一切都是对象。
1.2.4 解释与编译
通常来说,JavaScript是一门解释型的语言,特别是在浏览器中的JavaScript,所有的主流浏览器都将JavaScript作为一个解释型的脚本来进行解析。然而,这并非定则,在Java版的JavaScript解释器Rhino中,脚本可以被编译为Java字节码。Google的V8引擎则直接将JavaScript代码编译为本地代码,无需解释。
解释型的语言有一定的好处,即可以随时修改代码,无需编译,刷新页面即可重新解释,可以实时看到程序的结果,但是由于每一次都需要解释,程序的开销较大;而编译型的语言则仅需要编译一次,每次都运行编译过的代码即可,但是又丧失了动态性。