JavaScript面向对象(3)

全局对象

我们知道在对象方法内部可以使用this来表示对象本身。

1
2
3
4
5
6
7
8
9
var hero = {
name:'Rafaelo',
sayName:function(){
return this.name;
}
}

>>> hero.sayName();
>>> "Rafaelo"

接下来我们通过构造器函数来创建对象

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

>>> var hero = new Hero();
>>> hero.occupation;
>>> "Ninja"

我们可以看出构造器的函数来创建对象有两个比较好的特点:

  1. 可以在创建对象的时候传参数。
  2. 在使用的时候才真正创建和执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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("xiaohong");
>>> var h2 = new Hero("xiaoming");
>>> h1.whoAreYou();
>>> "I'm xiaohong and I'm a Ninja";
>>> h2.whoAreYou();
>>> "I'm xiaoming and I'm a Ninja";

假如我们在调用构造函数的时候忽略了new操作符

1
2
3
>>> var h = Hero('xiaohong');
>>> typeof h
>>> "undefined"

没有使用new操作符,因此我们不是在创建一个新对象,这里Hero和一个普通函数没什么区别,所以h就是这个Hero函数的返回值。

那么在这种情况下,Hero函数内这个this引用的是什么呢?

我们知道有全局变量,程序的宿主环境一般会为其提供一个全局对象,而全局变量只不过是全局对象的一个属性罢了。

1
2
>>> var a = 1;
//也可以window['a']或者window.a来访问

在Web浏览器中,window就是全局对象。这里的this其实指向了这个window对象。所以此时this.name的name成了全局变量。这就是为什么函数中没有声明var的变量是全局变量。

instanceof操作符

通过instanceof操作符,我们可以测试一个对象是不是由某个指定的构造器函数所创建的。

1
2
3
4
5
6
7
8
9
>>> function Hero(){}
>>> var h = new Hero();
>>> var o = {};
>>> h instanceof Hero;
>>> true
>>> h instanceof Object;
>>> true
>>> o instanceof Object;
>>> true

注意,这里不是调用函数,所以instanceof后面跟函数名。不要这样用(h instanceof Hero())

内建构造函数

内建构造器函数大致上可分为三个组:

  • 数据封装类对象:包括Object、Array、Boolean、Number和String以及undefined和null.
  • 工具类对象:包括Math、Date、RegExp等。
  • 错误类对象:异常发生时的特殊错误类对象。

Object对象

Object对象是JavaScript中所有对象的父级对象,这意味着我们创建的所有对象都继承自它。

下面两行执行结果是等价的:

1
2
var o = {}
var o = new Object();

实际上空对象没有什么实质作用,Object对象包含了一些方法和属性,比如toString(),valueOf()方法。

Function对象

我们知道函数是对象,函数对象内建构造器是Function(),我们可以将它作为创建函数的另一种备用方法。

下面三种定义函数的方式是等效的:

1
2
3
4
5
6
7
8
9
10
11
12
function sum(a, b){
return a + b;
}
>>> sum(1, 2);

var sum = function(a, b){
return a + b;
}
>>> sum(1, 2);

var sum = new Function('a', 'b', 'return a + b;');
>>> sum(1, 2);

之前我们使用call或者apply方法将父对象的构造函数绑定在子对象上来实现继承。

1
2
3
4
5
6
7
8
9
10
11
12
function Animal(){
this.species="动物"
}

function Cat(name, color){
Animal.apply(this, arguments);
this.name=name;
this.color=color;
}

var cat1 = new Cat("大黄", "yellow");
alert(cat1.species);

其实call()和apply()是Function对象的内置方法,call和apply只是在传参形式上有所不同,下面代码是等效的

1
2
Animal.apply(this, ['a', 'b', 'c']);
Animal.call(this, 'a', 'b', 'c');

这样实现继承的原理是,Cat方法调用的时候,Animal中的this就会被自动设置为Cat对象的引用。

arguments对象

上面我们看到我们可以直接使用arguments对象来传递函数参数,尽管arguments看上去是一个数组,但实际上它是一个类似于数组的对象。arguments是一个单纯的数组,没有sort(),slice()等这样的方法。另外,arguments中有一个callee属性,该属性引用的是当前被调用的函数对象,如果我们所创建的函数返回值是arguments.callee,那么该函数在调用的时候就会返回自身引用。

1
2
3
function f(){
return arguments.callee;
}

我们可以通过arguments.callee属性来实现匿名函数递归调用。

1
2
3
4
5
6
7
8
(
function(count){
if(count<5){
alert(count);
arguments.callee(++count);
}
}
)(1)

Error对象

在JavaScript中也可以使用try..catch..finally

1
2
3
4
5
try{
doSomething();
}catch(e){

}