number: 线性的事物,大小和次序分明,多而不乱。便于代码进行批量处理,也控制代码的迭代和循环等。
注意:typeof(NaN)和typeof(Infinity)都返回number 。
NaN参与任何数值计算的结构都是NaN,而且 NaN != NaN 。
Infinity / Infinity = NaN 。
JavaScript的代码就只有function一种形式,function就是函数的类型。也许其他编程语言还有procedure或 method等代码概念,但在JavaScript里只有function一种形式。当我们写下一个函数的时候,只不过是建立了一个function类型的实体而已。请看下面的程序:
function myfunc()
{
alert("hello");
};
alert(typeof(myfunc));
这个代码运行之后可以看到typeof(myfunc)返回的是function。以上的函数写法我们称之为“定义式”的,如果我们将其改写成下面的“变量式”的,就更容易理解了:
var myfunc = function ()
{
alert("hello");
};
好了,以上的讲述,我们应该算理解了function类型的东西都是和object类型一样的东西,这种东西被我们称为“对象”。我们的确可以这样去看待这些“对象”,因为它们既有“属性”也有“方法”嘛。但下面的代码又会让我们产生新的疑惑:
var anObject = {}; //一个对象
anObject.aProperty = "Property of object"; //对象的一个属性
anObject.aMethod = function(){alert("Method of object")}; //对象的一个方法
//主要看下面:
alert(anObject["aProperty"]); //可以将对象当数组以属性名作为下标来访问属性
anObject["aMethod"](); //可以将对象当数组以方法名作为下标来调用方法
for( var s in anObject) //遍历对象的所有属性和方法进行迭代化处理
alert(s + " is a " + typeof(anObject[s]));
同样对于function类型的对象也是一样:
var aFunction = function() {}; //一个函数
aFunction.aProperty = "Property of function"; //函数的一个属性
aFunction.aMethod = function(){alert("Method of function")}; //函数的一个方法
//主要看下面:
alert(aFunction["aProperty"]); //可以将函数当数组以属性名作为下标来访问属性
aFunction["aMethod"](); //可以将函数当数组以方法名作为下标来调用方法
for( var s in aFunction) //遍历函数的所有属性和方法进行迭代化处理
alert(s + " is a " + typeof(aFunction[s]));
是的,对象和函数可以象数组一样,用属性名或方法名作为下标来访问并处理。那么,它到底应该算是数组呢,还是算对象?
我们来看下面的代码:
function WhoAmI() //定义一个函数WhoAmI
{
alert("I'm " + this.name + " of " + typeof(this));
};
WhoAmI(); //此时是this当前这段代码的全局对象,在浏览器中就是window对象,其name属性为空字符串。输出:I'm of object
var BillGates = {name: "Bill Gates"};
BillGates.WhoAmI = WhoAmI; //将函数WhoAmI作为BillGates的方法。
BillGates.WhoAmI(); //此时的this是BillGates。输出:I'm Bill Gates of object
var SteveJobs = {name: "Steve Jobs"};
SteveJobs.WhoAmI = WhoAmI; //将函数WhoAmI作为SteveJobs的方法。
SteveJobs.WhoAmI(); //此时的this是SteveJobs。输出:I'm Steve Jobs of object
WhoAmI.call(BillGates); //直接将BillGates作为this,调用WhoAmI。输出:I'm Bill Gates of object
WhoAmI.call(SteveJobs); //直接将SteveJobs作为this,调用WhoAmI。输出:I'm Steve Jobs of object
BillGates.WhoAmI.call(SteveJobs); //将SteveJobs作为this,却调用BillGates的WhoAmI方法。输出:I'm Steve Jobs of object
SteveJobs.WhoAmI.call(BillGates); //将BillGates作为this,却调用SteveJobs的WhoAmI方法。输出:I'm Bill Gates of object
WhoAmI.WhoAmI = WhoAmI; //将WhoAmI函数设置为自身的方法。
WhoAmI.name = "WhoAmI";
WhoAmI.WhoAmI(); //此时的this是WhoAmI函数自己。输出:I'm WhoAmI of function
({name: "nobody", WhoAmI: WhoAmI}).WhoAmI(); //临时创建一个匿名对象并设置属性后调用WhoAmI方法。输出:I'm nobody of object
从上面的代码可以看出,同一个函数可以从不同的角度来调用,this并不一定是函数本身所属的对象。this只是在任意对象和function元素结合时的一个概念,是种结合比起一般对象语言的默认结合更加灵活,显得更加超然和洒脱。
除JSON外,在JavaScript中我们可以使用new操作符结合一个函数的形式来创建对象。例如:
function MyFunc() {}; //定义一个空函数
var anObj = new MyFunc(); //使用new操作符,借助MyFun函数,就创建了一个对象
JavaScript的这种创建对象的方式可真有意思,如何去理解这种写法呢?
其实,可以把上面的代码改写成这种等价形式:
function MyFunc(){};
var anObj = {}; //创建一个对象
MyFunc.call(anObj); //将anObj对象作为this指针调用MyFunc函数
我们就可以这样理解,JavaScript先用new操作符创建了一个对象,紧接着就将这个对象作为this参数调用了后面的函数。其实,JavaScript内部就是这么做的,而且任何函数都可以被这样调用!但从 “anObj = new MyFunc()” 这种形式,我们又看到一个熟悉的身影,C++和C#不就是这样创建对象的吗?原来,条条大路通灵山,殊途同归啊!
前两年,微软在设计AJAX类库的初期,用了一种被称为“闭包”(closure)的技术来模拟“类”。其大致模型如下:
function Person(firstName, lastName, age)
{
//私有变量:
var _firstName = firstName;
var _lastName = lastName;
var BillGates = new Person("Bill Gates");
BillGates.SayHello();
var SteveJobs = new Employee("Steve Jobs", 1234);
SteveJobs.SayHello();
SteveJobs.ShowMeTheMoney();
原型类模型虽然不能模拟真正的私有变量,而且也要分两部分来定义类,显得不怎么“优雅”。不过,对象间的方法是共享的,不会遇到垃圾回收问题,而且性能优于“闭包”模型。正所谓“有失必有得”嘛。
我们已经知道,用 var anObject = new aFunction() 形式创建对象的过程实际上可以分为三步:第一步是建立一个新对象;第二步将该对象内置的原型对象设置为构造函数prototype引用的那个原型对象;第三步就是将该对象作为this参数调用构造函数,完成成员设置等初始化工作。对象建立之后,对象上的任何访问和操作都只与对象自身及其原型链上的那串对象有关,与构造函数再扯不上关系了。换句话说,构造函数只是在创建对象时起到介绍原型对象和初始化对象两个作用。
function anyfunc(){}; //定义一个函数躯壳
anyfunc.prototype = Person; //将原型对象放到中转站prototype
var BillGates = new anyfunc(); //新建对象的内置原型将是我们期望的原型对象
不过,这个anyfunc函数只是一个躯壳,在使用过这个躯壳之后它就成了多余的东西了,而且这和直接使用构造函数来创建对象也没啥不同,有点不爽。