从数组到对象
>>> var myarr = [‘red’,’blue’,’yellow’,’purple’];
>>> myarr;
[“red”,”blue”,”yellow”,”purple”]
>>> myarr[0]
“red”
>>> myarr[3]
“purple”
对象的情况跟数组很类似,唯一的不同是它的键值类型是自定义的。也就是说,我们的索引方式不再局限于数字了,而可以使用一些更为人性化的键值,比如first_name,age等。
示例:1
2
3
4var hero = {
breed : 'Turtle',
occupation: 'Ninja'
};
正如我们所见:
- 这里有一个用于表示该对象的变量名hero。
- 与定义数组时所用的中括号[]不同,对象使用的是大括号{}。
- 括号中用逗号分割着的是组成该对象的元素(通常被称之为属性)。
- 键/值对之间用冒号分割,例如,key:value。
有时候,我们还可以在键值(属性名)上面加一对引号,例如,下面三行代码所定义的内容是完全相同的:
var o = {prop:1};
var o = {“prop”:1};
var o = {‘prop’:1};
如果我们所选的属性名不符合JavaScript中的变量名规则,就必须对其施加一对引号。1
2
3
4
5var o = {
something: 1,
'yes or no':'yes',
'!#%^^&*': true
};
该对象合法。
元素,属性,方法
对象的属性也可以是一个函数,因为函数本身也是一种数据,在这种情况下,我们会称该属性为方法,例如:1
2
3
4
5
6var dog = {
name : 'Benji',
talk : function(){
alert('woof,woof!');
}
};
当然我们也可以像下面这样,在数组中存储一些函数元素并在需要时调用它们,这在实践中并不多见。
>>> var a = [];
>>> a[0] = function(what){alert(what);};
>>> a0;
哈希表、关联型数组
- 一般性数组,也叫做索引型数组或者枚举型数组(通常以数字为键值)
- 关联型数组,也叫做哈希表(通常以字符串为键值)
访问对象属性
- 一种是中括号表示法,例如hero[‘ocuupation’]
- 另一种则是点号表示法,例如hero.occupation
尽管相对而言,点号表示法更易于读写,但也不是总能适用的。其中的属性和命名原则相同,即如果我们所访问的属性没有一个合法的名字,它就不能通过点号表示访问。
让我们来看一个具体的对象:1
2
3
4var hero = {
breed: 'Turtle',
occupation:'Ninja'
};
下面我们用点号表示法来访问操作:
>>> hero.breed;
“Turtle”
再用中括号表示法来访问属性:
>>> hero[‘occupation’];
“Ninja”
如果我们访问的属性不存在,代码就会返回undefined。
>>> ‘Hair color is’+hero.hair_color;
‘Hair color is undefined’
另外,由于对象中可以包含任何类型的数据,自然也包括其他对象:1
2
3
4
5
6
7
8var book = {
name: 'Catch-22',
published: 1961,
author: {
firstname:'Joseph',
lastname: 'Heller'
}
};
在这里,如果我们想访问book对象的author属性对象的firstname需要这样:
>>> book.author.firstname
‘Joseph’
当然,也可以连续使用中括号表示法,例如:
>>> book[‘author’][‘lastname’]
‘Heller’
甚至可以混合使用这两种表示法,例如:
>>> book.author[‘lastname’]
‘Heller’
>>> book[‘author’].lastname
‘Heller’
另外还有一种情况,即如果我们要访问的属性名是不确定的,就必须使用中括号表示法了,它允许我们在运行时通过变量来实现相关属性的动态存取。
>>> var key = ‘firstname’;
>>> book.author[key];
“Joseph”
调用对象方法
由于对象方法实际上只是一个函数类型属性,因此它们的访问方式与属性完全相同。即用点号表示法或中括号表示法均可。而其调用方式也与其他函数相同,在指定的方法名后加一对括号即可。例如下面的say方法:1
2
3
4
5
6
7var hero = {
breed:'Turtle',
occuptation:'Ninja',
say:function() {
return 'I am ' + hero.occupation;
}
}
>>> hero.say();
‘I am Ninja’
如果调用方法时需要传递一些参数,做法也和一般函数一样,例如:
>>> hero.say(‘a’,’b’,’c’);
另外,由于我们可以像访问数组一样用中括号来访问属性,因此这意味着我们同样可以用中括号来调用方法,尽管这种做法在实践中并不常见。
>>> hero‘say’;
修改属性与方法
首先创建一个空对象:
>>> var hero={};
这时候,如果我们访问一个不存在的属性,就会:
>>> typeof hero.breed
“undefined”
现在,我们来为该对象添加一些属性和方法:
>>> hero.breed = ‘turtle’;
>>> hero.name = ‘Leonardo’;
>>> hero.sayName = function() {return hero.name;};
然后调用该方法:
>>> hero.sayName();
‘Leonardo’
接下来,我们删除一个属性;
>>> delete hero.name;
true
然后再调用该方法,它就不能正常工作了;
>>> hero.sayName();
reference to undefined property hero.name
使用this值
当我们处于某个对象方法内部时,还可以用另外一种方法来访问同一对象的属性,即该对象的特殊值this。1
2
3
4
5
6var hero = {
name: 'Rafaelo',
sayName:function(){
return this.name;
}
}
>>> hero.sayName();
‘Rafaelo’
也就是说,当我们引用this值时,实际上所引用的就是“这个对象”或者“当前对象”。
构造器函数
我们可以通过构造函数的方式来创建对象,下面来看一个例子:1
2
3function Hero(){
this.occupation='Ninja';
}
为了能使用该函数来创建对象,我们需要使用new操作符,例如:
>>> var hero =new Hero();
>>> hero.occupation;
‘Ninja’
使用构造器函数的好处在于,它可以在创建对象时接收一些参数。下面,我们就来修改一下上面的构造函数,使它可以通过接收参数的方式来设定name属性:1
2
3
4
5
6
7function Hero (name){
this.name = name;
this.occupation = 'Ninja';
this.whoAreYou=function(){
return "I'm" + this.name +"and I 'm a" + this.occupation;
}
}
现在,我们就能利用同一个构造器来创建不同的对象了:
>>> var h1 = new Hero(‘Michelangelo’);
>>> var h2 = new Hero(‘Donatello’);
>>> h1.whoAreYou();
“I’m Michelangelo and I’m a Ninja”
>>> h2.whoAreYou();
“I’m Donatello and I’m a Ninja”
如果我们在调用一个构造器函数时忽略了new操作符,尽管不会出错,但结果可能出乎意料,例如:
>>> var h= Hero(‘Leonardo’);
>>> typeof h
“undefined”
在这种情况下,this指向的是全局 对象
全局对象
程序所在的宿主环境一般都会为其提供一个全局对象,而所谓的全局变量其实都只不过是该对象的属性罢了。
例如当程序的宿主环境是web浏览器时,它所提供的全局对象就是windows。我们来看一个实例,首先,我们在所有函数之外声明一个全局变量。
>>> var a = 1;
然后,我们就可以通过各种不同的方式来访问该全局变量了:
- 可以当做一个变量a来访问。
- 也可以当做全局对象的一个属性来访问,例如window[‘a’]或window.a;
现在,让我们回过头去分析一下刚才那个不使用new操作符调用构造器函数的情况,那时候,this值指向的是全局对象,并且所有的属性设置都是针对this所代表window对象的。
也就是说,当我们声明了一个构造函数,但又不通过new调用它时,代码就会返回’undefined’
>>> function Hero(name){this.naem=name;}
>>> var h = Hero(‘Leonardo’);
>>> typeof h
“undefined”
>>> typeof h.name
h has no properties
由于我们在Hero中使用了this,所以这里就会创建一个全局变量(同时也是全局对象的一个属性)。
>>> name
“Leonardo”
>>> window.name
“Leonardo”
而如果我们使用new来调用相同的构造函数,我们就会创建一个新对象,并且this也会自动指向该对象。
>>> var h2 = new Hero(‘Michelangelo’);
>>> typeof h2
“object”
>>> h2.name
“Michelangelo”构造器属性
当我们创建对象时,实际上同时也赋予了该对象一种特殊的属性=即构造器属性,该属性实际上是一个指向用于创建该对象的构造器函数的引用。
>>> h2.constructor
Hero(name)
当然,由于构造器属性所引用的是一个函数,因此我们也可以利用它来创建一个其他新对象。例如像下面这样,大意就是:”无论对象H2
有没有被创建,我们都可以用它来创建另一个对象”.
>>> var h3 = new h2.constructor(‘Rafaello’);
>>> h3.name;
“Rafaello”
另外,如果对象是通过对象文本标识符创建的,那么实际上它就是由內建构造函数Object()函数所创建的。
>>> var o = {};
>>> o.constructor;
Object()
>>> typeof o.constructor;
“function”