腊月的季节

对象

从数组到对象

>>> var myarr = [‘red’,’blue’,’yellow’,’purple’];
>>> myarr;
[“red”,”blue”,”yellow”,”purple”]
>>> myarr[0]
“red”
>>> myarr[3]
“purple”
对象的情况跟数组很类似,唯一的不同是它的键值类型是自定义的。也就是说,我们的索引方式不再局限于数字了,而可以使用一些更为人性化的键值,比如first_name,age等。
示例:

1
2
3
4
var 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
    5
    var o = {
    something: 1,
    'yes or no':'yes',
    '!#%^^&*': true
    };

该对象合法。

元素,属性,方法

对象的属性也可以是一个函数,因为函数本身也是一种数据,在这种情况下,我们会称该属性为方法,例如:

1
2
3
4
5
6
var dog = {
name : 'Benji',
talk : function(){
alert('woof,woof!');
}
};

当然我们也可以像下面这样,在数组中存储一些函数元素并在需要时调用它们,这在实践中并不多见。
>>> var a = [];
>>> a[0] = function(what){alert(what);};
>>> a0;

哈希表、关联型数组

  • 一般性数组,也叫做索引型数组或者枚举型数组(通常以数字为键值)
  • 关联型数组,也叫做哈希表(通常以字符串为键值)

    访问对象属性

  • 一种是中括号表示法,例如hero[‘ocuupation’]
  • 另一种则是点号表示法,例如hero.occupation
    尽管相对而言,点号表示法更易于读写,但也不是总能适用的。其中的属性和命名原则相同,即如果我们所访问的属性没有一个合法的名字,它就不能通过点号表示访问。
    让我们来看一个具体的对象:
    1
    2
    3
    4
    var 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
8
var 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
7
var 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
6
var hero = {
name: 'Rafaelo',
sayName:function(){
return this.name;
}
}

>>> hero.sayName();
‘Rafaelo’
也就是说,当我们引用this值时,实际上所引用的就是“这个对象”或者“当前对象”。

构造器函数

我们可以通过构造函数的方式来创建对象,下面来看一个例子:

1
2
3
function Hero(){
this.occupation='Ninja';
}

为了能使用该函数来创建对象,我们需要使用new操作符,例如:
>>> var hero =new Hero();
>>> hero.occupation;
‘Ninja’
使用构造器函数的好处在于,它可以在创建对象时接收一些参数。下面,我们就来修改一下上面的构造函数,使它可以通过接收参数的方式来设定name属性:

1
2
3
4
5
6
7
function 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”

热评文章