1.数组
Javascript中数组的大小是可以动态改变的
数组常用的方法:
concat:合并数组,不会改变原数组,返回一个新的数组
join:将数组中的内容按照方法参数指定的字符连接成字符串并返回
slice:返回原数组的子数组,slice(a,b)返回从下标a开始到下标b之前的元素组成的数组[如果有负数例如-3,表示数组的倒数第3个数]
push,pop:向数组末尾增加元素或者弹出元素,改变了原来的数组【注意,添加的元素可以是数组,添加进去了之后就可能是多维数组了】
unshift,shift:向数组的开头添加或者删除元素,改变了原来的数组
reverse:反转数组
sort:给数组排序
splice:可以删除数组中的一部分元素,也可以在指定的位置插入一部分元素【如果这个方法的第二个参数是0,插入时是插入在下标为第一个参数的元素之前】
测试页面:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascript" src="js/xml.js"> </script> <script type="text/javascript"> function test(){ var array1 = new Array(1,2,3);//创建并初始化数组 var array2 = new Array(4,[5,6],7); var array3 = array1.concat(array2);//合并 array3={1,2,3,4,[5,6],7} var array4 = array1.concat([8,9],10);//array4={1,2,3,8,9,10} 注意和上面的区别![5,6]-8,9 var string1 = array1.join("+");//按照指定的字符连成字符串并返回 1+2+3 var array5 = array1.slice(3,6);//取得子数组 var array6 = array1.slice(-2,-1);// 2 array1.push(11); array1.push([12,13,14]);//在数组的末尾添加和删除元素 array1=1,2,3,11,[12,13,14] var poped = array1.pop(); //array1=1,2,3,11 array1.unshift(0);//在数组的开头添加和删除元素 array1=0,1,2,3,11 var shifted = array1.shift(); array1.reverse();//反转数组 array1.sort();//默认按照字母序排列 array1=1,11,2,3 array1.sort(function(a,b){return a-b}); //升序排列 array1=1,2,3,11 var s1 = array1.splice(1,3);//删除一部分元素并返回 array1=1 var s2 = array1.splice(10);// 没有删除 array1.splice(1,0,20,21,23); // array1=1,20,21,23 alert(""); } </script> </head> <body> <input type="button" value="Test" onclick="test()"> <br/> </body> </html>
3.简单对象
测试代码:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascript" src="js/xml.js"> </script> <script type="text/javascript"> function test(){ //创建出简单对象的两种方式 var obj1 = new Object(); var obj2 = {}; //给简单对象增加属性(可以随时添加属性) obj1.text = "obj1"; obj1.value = 1; obj1.method = function(){ alert("obj1"); } //访问属性 alert(obj1.text); obj1.method();//加上了括号就表示调用方法 alert(obj1["value"]); //通过对象直接量的方式定义属性 var obj3 = { text : "obj3", value : 3, method : function(){ alert("obj3"); }, obj : obj1 } alert(obj3.obj.value); alert(""); } </script> </head> <body> <input type="button" value="Test" onclick="test()"> <br/> </body> </html>
3.JSON 数据格式
JSON 和 XML 的对比
测试:
如果从服务器端得到的JSON数据是一个数组,那么使用eval方法就可以得到一个数组,但是
如果从服务器端得到的JSON数据是一个对象,那么使用eval方法时,要在对象两端加上括号才可以正确解析!
测试代码:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascript" src="js/xml.js"> </script> <script type="text/javascript"> function test(){ var json1 = "[1,2,{a:4,b:'hello',c:[100,200,300]}]"; //注意b是字符串,使用的是单引号 var array1 = eval(json1); var json2 = "{a:4,b:'hello',c:[100,200,300]}"; var obj = eval("("+json2+")"); alert(""); } </script> </head> <body> <input type="button" value="Test" onclick="test()"> <br/> </body> </html>
4.面向对象的 Javascript
①对象的定义
②公有的属性和方法的定义
Javascript中的对象和面向对象语言中的对象不同的一个地方是,Javascript这种动态语言允许动态的给一个对象增加属性。
在Java中我们定义了属于某个类的一个对象,那么这个对象可使用的属性和方法是固定,但是在Javascript中我们通过类创建出来的对象则可以
随时根据需要增加属性和方法,我们接着上面的代码再写出下面的内容:
book2.author=”wang”;//给book2对象动态增加一个新的属性 alert(book2.author);//显示author属性值,输出内容是wang book2.setAuthor = function(author){this.author = author};//给book2对象动态增加一个新的方法 book2.setAuthor (“zhu”); //设置author属性的新值 alert(book2.author);//显示新的author值,输出内容是wang
③原型对象:类的原型对象上定义的公有方法和属性会使得该类的实例都具有
最好的定义方式:
//利用原型对象来定义对象的属性和方法 var Book = function(name){ //共有的属性在构造器中定义 this.name = name; //采用下面的定义方式可以保证公有方法的定义只执行一次 if (typeof Book._init == "undefined") { //公有的方法在原型对象上定义 Book.prototype.getName = function(){ return this.name; }; Book.prototype.setName = function(name){ this.name = name; }; } Book._init=true; }
采用这种方式定义的好处是在对象很多的时候可以节省很多的空间!如下图所示
从上图中我们可以发现“构造函数”法来定义成员变量和成员方法,我们在创建对象时,就会把“构造函数”中的内容都创建出来,
假设一个成员变量占用一个内存单位,一个成员方法占用两个内存单位,那么我们每创建一个对象,其中都保存着name变量,setName,getName方法,
这个对象将占用了五个内存单位,四个对象我们使用了20个内存空间。
而如果我们使用本节的prototype方式定义类,那么成员方法都保存在原型对象中,由于一个类只有一个原型对象(实际上是表示类的那个函数只有一个原型对象)
所有这个从这个类创建出来的对象都继承(也可以说是共享)了原型对象中定义的两个方法,这时我们每创建一个对象,
实际上对象中只保存了成员变量name,同时继承使用原型对象中的setName和getName方法,四个对象我们将只占用4*1+4=8个内存空间。
关于公有的属性和方法的完整测试代码:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascript" src="js/xml.js"> </script> <script type="text/javascript"> //javascript中类的定义,建议采用下面的方式创建类,并且类名是大写的 var Teacher = function(name){ this.name = name; if (typeof Teacher._init == "undefined") { Teacher.prototype.students = []; Teacher.prototype.getName = function(){ return this.name; } Teacher.prototype.setName = function(name){ this.name = name; } Teacher.prototype.addStudent = function(name){ this.students.push(name); } Teacher.prototype.showStudents = function(){ alert(this.students); } } Teacher._init = true; } //下面的类的定义就好像是构造器,new对象是时function就会执行 /* var Book = function(name){ //定义共有的属性 this.name = name; //定义公有的方法 this.getName = function(){ return this.name; } this.setName = function(name){ this.name = name; } }*/ //利用原型对象来定义对象的属性和方法 var Book = function(name){ //共有的属性在构造器中定义 this.name = name; //采用下面的定义方式可以保证公有方法的定义只执行一次 if (typeof Book._init == "undefined") { //公有的方法在原型对象上定义 Book.prototype.getName = function(){ return this.name; }; Book.prototype.setName = function(name){ this.name = name; }; } Book._init = true; } function test(){ var t = new Teacher(); //alert(t instanceof Teacher); var b1 = new Book("java"); var b2 = new Book("javascript"); alert(b1.getName()); b2.setName("ajax"); alert(b2.getName()); var t1 = new Teacher("t1"); var t2 = new Teacher("t2"); t1.addStudent("ming"); t2.addStudent("yinger"); t1.showStudents(); t2.showStudents(); alert(""); } </script> </head> <body> <input type="button" value="Test" onclick="test()"> <br/> </body> </html>
公有属性定义在原型对象上的错误!如下图中的t1和t2
原型对象中适合保存成员方法和常量,但不适合保存普通的成员变量。
Book.prototype.tt = "zxc";
var book1 = new Book("AJAX");
var book2 = new Book("Java");
alert(book1.tt);
alert(book2.tt);
book2.tt = "bnm";
alert(book2.tt);
alert(book1.tt);
你觉得这个程序的输出结果会是什么呢?前两次alert我们都能想到,肯定是”zxc”,第三个我们也能想到,输出”bnm”,
第四个是不是也是”bnm”呢?不,第四个还是”zxc”。为什么会这样呢?
这是因为原型对象中定义的内容对于它所属于的那个类创建出来的对象们来说是只读的。你可以用点加上原型对象中定义的那个属性名来取到属性值,
但是当你用点加上原型对象中定义的那个属性名给那个属性赋值时,实际上并不是在给原型对象中的属性赋值,而是在给你的这个对象动态增加一个属性,
这个属性的名字和原型对象中的那个属性名一样。下面这个图很好的描述了对象内部的变化以及alert时对象到底读取了哪个tt属性。
当然如果你想改变原型对象中定义的属性值,就只能像下面这样的方式来做:
Book.prototype.tt = "bnm"
这个时候,所有本身没有tt属性的对象再来读tt这个属性的时候,值就变成了”bnm”了。有人会说那我用book1.prototype.tt这种方式是不是可以修改属性呢?
实践是回答问题最好的方法,我们可以运行一下这行代码,你会发现,会有错误产生,那是因为只有一个表示函数的变量才有prototype属性,才有原型对象,
而对于一个普通对象来说,它是没有prototype属性的。
我们知道了普通的成员变量不适合定义在原型对象中,我们再来总结一下为什么方法和常量适合定义在原型对象中。
我们使用方法其实都是一个读操作,而且不同对象使用同一个方法可以产生不同的运行结果,之间互不影响。
至于常量,常量是不会变的,它的作用就是给别人读的,既然原型对象中的属性只是用来读的,那么常量放在原型变量里面定义就非常合适了。
④继承:
Java中父类可以有子类,子类可以再有自己的子类,继承关系可以很深。而在Javascript中,所谓的“继承”仅仅是一个类(实际上是函数)的所有对象
可以继承原型对象的属性内容,不存在多层次继承的情况。
另一方面,Java中子类继承了父类的成员变量,那么每一个子类对象在是用这个成员变量时都是独立互不影响的,而在Javascript中,
由于这个继承是对象之间的继承,且一个类的多个对象同时继承了这个类的一个原型对象,因此,当原型对象中的属性发生变化时,
所有的普通对象在获取这个属性时也都会发生变化。
最后,Java中从父类继承的成员变量是可读可写的,而Javascript中,则是只读的,当你象写这个属性时,实际上并没有真正修改原型对象中的那个属性值,
而是给当前对象新建了一个属性,如我们前面的例子所示。
⑥私有变量和方法:
Javascript中并没有Java那样的关键字来控制属性方法的访问权限,因此我们只有采用曲线救国的方式来解决这个问题。
我们知道所谓私有的内容就是在类之外是不可见的。Javascript中我们的类就是一个方法,那么什么内容在方法之外不可见呢?
没错,就是方法中的局部变量。那么如果我们在方法中定义一个局部变量,那它就是我们Javascript类中的私有成员变量了。
var Book = function(name){ var privateVale = 999; this.name = name; this.setPrivateValue =function(value){privateVale = value;} this.getPrivateValue =function(){return privateVale;} } Book.prototype.getName =function(){return this.name;} Book.prototype.setName =function(name){this.name = name;} var book1 = new Book(“AJAX”); alert(book1.getPrivateValue());
结果是 999
定义私有的方法:
var Book = function(name){ var privateVale; this.name = name; var setPrivateValue =function(value){privateVale = value;} this.getPrivateValue =function(){return privateVale;} setPrivateValue(999); } Book.prototype.getName =function(){return this.name;} Book.prototype.setName =function(name){this.name = name;} var book1 = new Book(“AJAX”); alert(book1.getPrivateValue());
上面这段代码,我们定义了外部可见的公有方法getPrivateValue以及私有内部可见的setPrivateValue方法,这样对于私有属性privateVale,
别人在使用的时候就只能获取它的值而不能给它赋值了。
我们来总结一下,当你需要定义Javascript中的私有变量和方法的时候,可以在“构造函数”中通过局部变量的方式来定义,
注意提供给别人操作这些私有变量和方法的方法只能在“构造函数”中定义成公有,而不能在原型对象中定义,因为只有构造函数中才可以看到这些私有变量。
⑦静态变量和方法:
Javascript中的类是一个函数,对于我们前面看到了每个函数都有一个prototype的属性表示它的原型对象。这说明函数是可以有属性的,
既然可以有属性就可以动态的增加属性。所以当我们需要定义Javascript中的类的静态属性和方法时,就可以给表示类的变量增加属性内容。
仍然以Book类为例,示例代码如下:
Book.TYPE = “IT”;
Book.print = function(){alert(Book.TYPE);}
如上所示,我们定义的“静态”属性和方法与Java中的使用方式一样,当然定义方式略有不同,Java中的都定义在类里面了,而javascript中我们一般定义在类构造函数的外面。
这里仍然有一个建议,就是类的“静态”属性名使用大写字母,这和前面说道的prprotype定义的常量一样,为的是让别人一目了然。
这种类“静态”属性和prorotype定义的常量还是有一些差别的,一个类的所有对象看到的prototype定义的常量值是一样的,读变量的时候可以通过对象名点上变量名,
但是不能写,而且可能存在对象中定义的属性覆盖了prototype中定义的这个常量,而类的“静态”属性在整个程序中看到的结果都是一样的,读写变量的时候都是类名点上变量名
在Javascript中应该在何时定义类的“静态”属性和方法?总的来说和Java中是一样的。当类的某个值与对象无关期望所有位置看到的结果是一样的时候,
就可以定义为类静态属性。如果类的一个方法做的是和具体对象无关的操作,而是做一些工作操作的时候,就可以将这个方法定义为静态的类方法。