再读斋

JavaScript⑦对象

函数

定义函数

  • 创建一个函数需要用到关键字function,后面是一个函数名
  • 为函数提供0或多个参数,使用参数向函数传值
  • 可以返回一个值作为调用这个函数的结果,这是可选的
  • 编写函数体,包含完成函数工作的所有代码

JavaScript有两种方式定义函数,第一种方式如下:

1
2
3
function add(x,y) {
return x + y;
}

注意,函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。因此,函数内部通过运算可以实现非常复杂的逻辑。如果没有return语句,函数执行完毕后也会返回结果,只是结果为undefined。

由于JavaScript函数也是一个对象,上述定义的add()函数实际上是一个函数对象,而函数名add可以视为指向该函数的变量。
因此,第二种定义函数的方式如下:

1
2
3
var add = function (x,y) {
return x + y;
};

这种方式下,function{....}是一个匿名函数,它没有函数名,但是这个匿名函数赋值给了变量add,所有通过变量add就可以调用该函数。

上述两种定义是等价的,注意第二种方式按照完整语法需要在末尾加一个;号,表示赋值语句结束。

函数声明可以出现在脚本中的任何位置。使用多个外部JavaScript文件时有一点要记住,如果不同文件中有两个同名的函数,将使用浏览器最后看到的那个函数。

调用函数

调用函数时,按顺序传入参数即可:

1
var sum = add(1,2); //返回3

由于JavaScript允许任意参数而不影响调用,因此传入的参数比定义的参数多也没有问题,虽然函数内部并不需要这些参数:

1
var sum = add(1,2,3); //返回3

传入的参数比定义的少也没有问题:

1
var sum = add(); //返回NaN

此时,add的参数将受到undefined,计算结果为NaN

变量作用域

全局变量

如果一个变量在函数外声明,这个变量就是全局变量。可以在JavaScript代码中的任何地方访问。

1
2
3
4
5
6
7
8
var x = 3; //全局变量
var y = 4;
var add = function (x,y) {
var z = 4; //局部变量
return x + y + z;
}

局部变量

如果一个变量在函数内声明,这个变量就是局部变量。只能在函数体内部使用。

1
2
3
4
5
6
7
8
var x = 3; //全局变量
var y = 4;
var add = function (x,y) {
var z = 4; //局部变量
return x + y + z;
}

变量提升

JavaScript函数定义有个特点,它会先扫描整个函数体的语句,把所有声明的变量提升到函数顶部

1
2
3
4
5
6
7
8
9
'use strict'
function foo() {
var x = "hello," + y;
alert(x);
y = "world";
}
foo();

虽然是strict模式,但语句var x = "hello," + y并不报错,原因是变量y在稍后说明了。但是alert显示hello,undefined,说明变量y的值为undefined。这正是因为JavaScript引擎自动提升了变量y的声明,但不会提升变量y的赋值。

1
2
3
4
5
6
function foo() {
var y; // 提升变量y的申明
var x = 'Hello, ' + y;
alert(x);
y = 'Bob';
}

由于JavaScript的这一特性,我们在函数内部定义变量时,请严格遵守“在函数内部首先声明所有变量”这一规则。最常见的做法是用一个var声明函数内部所用到的变量:

1
2
3
4
5
6
7
8
9
10
function foo() {
var
x = 1, // x初始化为1
y = x + 1, // y初始化为2
z, i; // z和i为undefined
// 其他语句:
for (i=0; i<100; i++) {
...
}
}

对象

普通创建对象

创建对象

已经有了一个包含一些属性的对象。如何使用JavaScript创建这个对象呢?方法如下:

1
2
3
4
5
6
var fido = {
name: "Fido",
weight: 40,
breed: "Mixed",
loves: ["walks","fetching balls"]
};

访问和操作对象

  • 使用“点”记法访问对象属性
1
2
3
4
5
if (fido.weight > 25) {
alert("Wonderful");
} else {
alert("keep moving");
}
  • 使用一个串结合[]记法访问属性
1
2
3
4
var breed = fido["breed"];
if (breed == "mixed") {
alert("Best in show");
}
  • 改变属性的值
1
2
fido.weight = 27; //改变Fido的重量
fido.loves.push("chewing bones"); //向它的loves数组增加一个新元素
  • 枚举对象的所有属性
1
2
3
4
var prop;
for(prop in fido) {
alert("Fido has a" + prop + " property"); //每次循环迭代时,变量prop会得到下一个属性名的相应串值
}
  • 处理对象的数组
1
2
3
4
5
6
var likes = fido.loves;
var likesStr = "Fido likes";
for (var i = 0; i < likes.length; i++) {
likesStr += " " + likes[i];
}
  • 向函数传入一个对象
1
2
3
4
5
function bark(dog) {
dog.weight = 28; //会同时改变fido中的值
}
bark(fido);

注意:将一个对象赋值给变量时,这个变量会包含这个对象的一个引用,而不是对象的副本,可以把引用想成是对象的一个指针。所有对该变量中属性的改变都会改变原对象的属性。

上述代码中,改变dog对象的weight属性时,实际上是修改的原对象fido的属性,而不是副本,所有不仅函数体内的dog对象发生了改变,函数体外的fido对象也发生了改变。

给对象增加方法

1
2
3
4
5
6
7
8
9
10
11
12
var fido = {
name: "Fido";
weight: 40;
breed: "Mixed";
loves: ["walks","fetching balls"]
bark: function() {
alert("Woof Woof");
}
};
fido.bark(); //调用方法

构造函数创建对象

构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
function Dog(name,breed,weight) {
this.name = name;
this.breed = breed;
this.weight = weight;
this.bark = function() {
if (this.weight) {
alert(this.name + " say Woof!");
}
};
}
注意这个语法和对象的语法有所不同。这些是语句,所有需要一个“;”结束各语句。this用于指示对象中的属性,它就代表了新创建的实例对象。

创建对象

1
2
3
4
5
var fido = new Dog("Fido","Mixed",38); //new关键字创建一个对象
var tiny = new Dog("Tiny","Chawalla",18);
fido.bark();
tiny.bark();

prototype属性创建对象

prototype属性包含一个对象,所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就放在构造函数里面。

实例对象一旦创建,将自动引用prototype对象的属性和方法。也就是说,实例对象的属性和方法分为两种,一种是本地的,一种是引用的:

1
2
3
4
5
6
7
8
9
10
  function DOG(name){
    this.name = name;
  }
  DOG.prototype = { species : '犬科' };
  var dogA = new DOG('大毛');
  var dogB = new DOG('二毛');
  alert(dogA.species); // 犬科
  alert(dogB.species); // 犬科

现在,species属性放在prototype对象中,两个实例对象共享的,只要修改了prototype对象,就会同时影响到两个实例对象。

1
2
3
DOG.prototype.species = '猫科';
alert(dogA.species); // 猫科
alert(dogB.species); // 猫科

综上所述,由于所有实例对象共享同一个prototype对象,那么在外界看起来,prototype对象就好像是实例对象的原型,而实例对象则好像继承了prototype对象一样。

刘涤生 wechat