原创作者: abruzzi  

第三章 对象与JSON

JavaScript对象与传统的面向对象中的对象几乎没有相似之处,传统的面向对象语言中,创建一个对象必须先有对象的模板:类,类中定义了对象的属性和操作这些属性的方法。通过实例化来构筑一个对象,然后使用对象间的协作来完成一项功能,通过功能的集合来完成整个工程。而Javascript中是没有类的概念的,借助JavaScript的动态性,我们完全可以创建一个空的对象(而不是类),通过像对象动态的添加属性来完善对象的功能。

JSON是JavaScript中对象的字面量,是对象的表示方法,通过使用JSON,可以减少中间变量,使代码的结构更加清晰,也更加直观。使用JSON,可以动态的构建对象,而不必通过类来进行实例化,大大的提高了编码的效率。

3.1 Javascript对象

JavaScript对象其实就是属性的集合,这里的集合与数学上的集合是等价的,即具有确定性,无序性和互异性,也就是说,给定一个JavaScript对象,我们可以明确的知道一个属性是不是这个对象的属性,对象中的属性是无序的,并且是各不相同的(如果有同名的,则后声明的覆盖先声明的)。

一般来说,我们声明对象的时候对象往往只是一个空的集合,不包含任何的属性,通过不断的添加属性,使得该对象成为一个有完整功能的对象,而不用通过创建一个类,然后实例化该类这种模式,这样我们的代码具有更高的灵活性,我们可以任意的增删对象的属性。

如果读者有python或其他类似的动态语言的经验,就可以更好的理解JavaScript的对象,JavaScript对象的本身就是一个字典(dictionary),或者Java语言中的Map,或者称为关联数组,即通过键来关联一个对象,这个对象本身又可以是一个对象,根据此定义,我们可以知道JavaScript对象可以表示任意复杂的数据结构。

3.1.1 对象的属性

属性是由键值对组成的,即属性的名字和属性的值。属性的名字是一个字符串,而值可以为任意的JavaScript对象(JavaScript中的一切皆对象,包括函数)。比如,声明一个对象:

 

 

Js代码

  1. //声明一个对象  
  2. var jack = new Object();  
  3. jack.name = "jack";  
  4. jack.age = 26;  
  5. jack.birthday = new Date(1984, 4, 5);  
  6.    
  7. //声明另一个对象  
  8. var address = new Object();  
  9. address.street = "Huang Quan Road";  
  10. address.xno = "135";  
  11.    
  12. //将addr属性赋值为对象address  
  13. jack.addr = address;  
//声明一个对象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属性赋值为对象addressjack.addr = address;
 

 

 

这种声明对象的方式与传统的OO语言是截然不同的,它给了我们极大的灵活性来定制一个对象的行为。

 

对象属性的读取方式是通过点操作符(.)来进行的,比如上例中jack对象的addr属性,可以通过下列方式取得:

 

 

Js代码

var ja = jack.addr;       ja = jack[addr];  
var ja = jack.addr; ja = jack[addr];
 

 

 

后者是为了避免这种情况,设想对象有一个属性本身包含一个点(.),这在JavaScript中是合法的,比如说名字为foo.bar,当使用jack.foo.bar的时候,解释器会误以为foo属性下有一个bar的字段,因此可以使用jack[foo.bar]来进行访问。通常来说,我们在开发通用的工具包时,应该对用户可能的输入不做任何假设,通过[属性名]这种形式则总是可以保证正确性的。

3.1.2属性与变量

在第二章,我们讲解了变量的概念,在本章中,读者可能已经注意到,这二者的行为非常相似,事实上,对象的属性和我们之前所说的变量其实是一回事。

JavaScript引擎在初始化时,会构建一个全局对象,在客户端环境中,这个全局对象即为window。如果在其他的JavaScript环境中需要引用这个全局对象,只需要在顶级作用域(即所有函数声明之外的作用域)中声明:

 

 

Js代码

var global = this;  
var global = this;
 

 

 

我们在顶级作用域中声明的变量将作为全局对象的属性被保存,从这一点上来看,变量其实就是属性。比如,在客户端,经常会出现这样的代码:

 

 

Js代码

var v = "global";       var array = ["hello", "world"];       function func(id){       var element = document.getElementById(id);       //对elemen做一些操作   }  
var v = "global"; var array = ["hello", "world"]; function func(id){    var element = document.getElementById(id);    //对elemen做一些操作}
 

 

 

事实上相当于:

 

 

Js代码

  1. window.v = "global";  
  2.    
  3. window.array = ["hello", "world"];  
  4.    
  5. window.func = function(id){  
  6.     var element = document.getElementById(id);  
  7.     //对elemen做一些操作    
  8. }  
window.v = "global"; window.array = ["hello", "world"]; window.func = function(id){    var element = document.getElementById(id);    //对elemen做一些操作  }
 

 

 

3.1.3原型对象

原型(prototype),是JavaScript特有的一个概念,通过使用原型,JavaScript可以建立其传统OO语言中的继承,从而体现对象的层次关系。JavaScript本身是基于原型的,每个对象都有一个prototype的属性来,这个prototype本身也是一个对象,因此它本身也可以有自己的原型,这样就构成了一个链结构。

访问一个属性的时候,解析器需要从下向上的遍历这个链结构,直到遇到该属性,则返回属性对应的值,或者遇到原型为null的对象(JavaScript的基对象Object的prototype属性即为null),如果此对象仍没有该属性,则返回undefined.

下面我们看一个具体的例子:

 

 

Js代码

  1. //声明一个对象base  
  2. function Base(name){  
  3.     this.name = name;  
  4.     this.getName = function(){  
  5.        return this.name;  
  6.     }  
  7. }  
  8.    
  9. //声明一个对象child  
  10. function Child(id){  
  11.     this.id = id;  
  12.     this.getId = function(){  
  13.        return this.id;    
  14.     }  
  15. }  
  16.    
  17. //将child的原型指向一个新的base对象  
  18. Child.prototype = new Base("base");  
  19.    
  20. //实例化一个child对象  
  21. var c1 = new Child("child");  
  22.    
  23. //c1本身具有getId方法  
  24. print(c1.getId());  
  25. //由于c1从原型链上"继承"到了getName方法,因此可以访问  
  26. print(c1.getName());  
//声明一个对象basefunction Base(name){    this.name = name;    this.getName = function(){       return this.name;    }} //声明一个对象childfunction Child(id){    this.id = id;    this.getId = function(){       return this.id;      }} //将child的原型指向一个新的base对象Child.prototype = new Base("base"); //实例化一个child对象var c1 = new Child("child"); //c1本身具有getId方法print(c1.getId());//由于c1从原型链上"继承"到了getName方法,因此可以访问print(c1.getName());
 

 

 

得出结果:

 

 

child
base 

 

 

由于遍历原型链的时候,是有下而上的,所以最先遇到的属性值最先返回,通过这种机制可以完成重载的机制。

 

3.1.4 this指针

         JavaScript中最容易使人迷惑的恐怕就数this指针了,this指针在传统OO语言中,是在类中声明的,表示对象本身,而在JavaScript中,this表示当前上下文,即调用者的引用。这里我们可以来看一个常见的例子:

 

 

Js代码

  1. //定义一个人,名字为jack  
  2. var jack = {  
  3.     name : "jack",  
  4.     age : 26  
  5. }  
  6.    
  7. //定义另一个人,名字为abruzzi  
  8. var abruzzi = {  
  9.     name : "abruzzi",  
  10.     age : 26  
  11. }  
  12.    
  13. //定义一个全局的函数对象  
  14. function printName(){  
  15.     return this.name;  
  16. }  
  17.    
  18. //设置printName的上下文为jack, 此时的this为jack  
  19. print(printName.call(jack));  
  20. //设置printName的上下文为abruzzi,此时的this为abruzzi  
  21. print(printName.call(abruzzi));  
//定义一个人,名字为jackvar jack = {    name : "jack",    age : 26} //定义另一个人,名字为abruzzivar abruzzi = {    name : "abruzzi",    age : 26} //定义一个全局的函数对象function printName(){    return this.name;} //设置printName的上下文为jack, 此时的this为jackprint(printName.call(jack));//设置printName的上下文为abruzzi,此时的this为abruzziprint(printName.call(abruzzi));
 

 

 

运行结果:

 

 

jack
Abruzzi 

 

 

应该注意的是,this的值并非函数如何被声明而确定,而是被函数如何被调用而确定,这一点与传统的面向对象语言截然不同,call是Function上的一个函数,详细描述在第四章。

3.2使用对象

对象是JavaScript的基础,我们使用JavaScript来完成编程工作就是通过使用对象来体现的,这一小节通过一些例子来学习如何使用JavaScript对象:

对象的声明有三种方式:

 

Ø  通过new操作符作用域Object对象,构造一个新的对象,然后动态的添加属性,从无到有的构筑一个对象。

Ø  定义对象的“类”:原型,然后使用new操作符来批量的构筑新的对象。

Ø  使用JSON,这个在下一节来进行详细说明

 

这一节我们详细说明第二种方式,如:

 

 

Js代码

  1. //定义一个"类",Address  
  2. function Address(street, xno){  
  3.     this.street = street || 'Huang Quan Road';  
  4.     this.xno = xno || 135;  
  5.     this.toString = function(){  
  6.        return "street : " + this.street + ", No : " + this.xno;     
  7.     }  
  8. }  
  9.    
  10. //定义另一个"类",Person  
  11. function Person (name, age, addr) {  
  12.   this.name = name || 'unknown';  
  13.   this.age = age;  
  14.   this.addr = addr || new Address(null, null);  
  15.   this.getName = function () {return this.name;}  
  16.   this.getAge = function(){return this.age;}  
  17.   this.getAddr = function(){return this.addr.toString();}  
  18. }  
  19.    
  20. //通过new操作符来创建两个对象,注意,这两个对象是相互独立的实体  
  21. var jack = new Person('jack', 26, new Address('Qing Hai Road', 123));  
  22. var abruzzi = new Person('abruzzi', 26);  
  23.    
  24. //查看结果  
  25. print(jack.getName());  
  26. print(jack.getAge());  
  27. print(jack.getAddr());  
  28.    
  29. print(abruzzi.getName());  
  30. print(abruzzi.getAge());  
  31. print(abruzzi.getAddr());  
//定义一个"类",Addressfunction Address(street, xno){    this.street = street || 'Huang Quan Road';    this.xno = xno || 135;    this.toString = function(){       return "street : " + this.street + ", No : " + this.xno;       }} //定义另一个"类",Personfunction Person (name, age, addr) {  this.name = name || 'unknown';  this.age = age;  this.addr = addr || new Address(null, null);  this.getName = function () {return this.name;}  this.getAge = function(){return this.age;}  this.getAddr = function(){return this.addr.toString();}} //通过new操作符来创建两个对象,注意,这两个对象是相互独立的实体var jack = new Person('jack', 26, new Address('Qing Hai Road', 123));var abruzzi = new Person('abruzzi', 26); //查看结果print(jack.getName());print(jack.getAge());print(jack.getAddr()); print(abruzzi.getName());print(abruzzi.getAge());print(abruzzi.getAddr());
 

 

 

运行结果如下:

 

 

jack
26
street : Qing Hai Road, No : 123
abruzzi
26
street : Huang Quan Road, No : 135 

 

3.3 JSON及其使用

JSON全称为JavaScript对象表示法(JavaScriptObject Notation),即通过字面量来表示一个对象,从简单到复杂均可使用此方式。比如:

 

 

Js代码

var obj = {       name : "abruzzi",       age : 26,       birthday : new Date(1984, 4, 5),       addr : {          street : "Huang Quan Road",          xno : "135"       }   }  
var obj = {    name : "abruzzi",    age : 26,    birthday : new Date(1984, 4, 5),    addr : {       street : "Huang Quan Road",       xno : "135"    }}
 

 

 

这种方式,显然比上边的例子简洁多了,没有冗余的中间变量,很清晰的表达了obj这样一个对象的结构。事实上,大多数有经验的JavaScript程序员更倾向与使用这种表示法,包括很多JavaScript的工具包如jQuery,ExtJS等都大量的使用了JSON。JSON事实上已经作为一种前端与服务器端的数据交换格式,前端程序通过Ajax发送JSON对象到后端,服务器端脚本对JSON进行解析,还原成服务器端对象,然后做一些处理,反馈给前端的仍然是JSON对象,使用同一的数据格式,可以降低出错的概率。

         而且,JSON格式的数据本身是可以递归的,也就是说,可以表达任意复杂的数据形式。JSON的写法很简单,即用花括号括起来的键值对,键值对通过冒号隔开,而值可以是任意的JavaScript对象,如简单对象String,Boolean,Number,Null,或者复杂对象如Date,Object,其他自定义的对象等。

         JSON的另一个应用场景是:当一个函数拥有多个返回值时,在传统的面向对象语言中,我们需要组织一个对象,然后返回,而JavaScript则完全不需要这么麻烦,比如:

 

 

Js代码

function point(left, top){       this.left = left;       this.top = top;       //handle the left and top       return {x: this.left, y:this.top};   }  
function point(left, top){    this.left = left;    this.top = top;    //handle the left and top    return {x: this.left, y:this.top};}
 

 

 

直接动态的构建一个新的匿名对象返回即可:

 

 

Js代码

var pos = point(3, 4);   //pos.x = 3;   //pos.y = 4;  
var pos = point(3, 4);//pos.x = 3;//pos.y = 4;
 

 

 

使用JSON返回对象,这个对象可以有任意复杂的结构,甚至可以包括函数对象。

在实际的编程中,我们通常需要遍历一个JavaScript对象,事先我们对对象的内容一无所知。怎么做呢?JavaScript提供了for..in形式的语法糖:

 

 

Js代码

for(var item in json){       //item为键       //json[item]为值   }  
for(var item in json){    //item为键    //json[item]为值}
 

 

 

这种模式十分有用,比如,在实际的WEB应用中,对一个页面元素需要设置一些属性,这些属性是事先不知道的,比如:

 

 

Js代码

var style = {       border:"1px solid #ccc",       color:"blue"   };  
var style = {    border:"1px solid #ccc",    color:"blue"};
 

 

 

然后,我们给一个DOM元素动态的添加这些属性:

 

 

Js代码

for(var item in style){       //使用jQuery的选择器       $("div#element").css(item, style[item]);   }  
for(var item in style){    //使用jQuery的选择器    $("div#element").css(item, style[item]);}
 

 

 

当然,jQuery有更好的办法来做这样一件事,这里只是举例子,应该注意的是,我们在给$("div#element")添加属性的时候,我们对style的结构是不清楚的。

 

另外比如我们需要收集一些用户的自定义设置,也可以通过公开一个JSON对象,用户将需要设置的内容填入这个JSON,然后我们的程序对其进行处理。

 

 

Js代码

function customize(options){       this.settings = $.extend(default, options);   }  
function customize(options){    this.settings = $.extend(default, options);}
 

 

转载于:https://www.cnblogs.com/TDYToBaby/archive/2010/06/12/1757313.html

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐