对象
我们常听到一句话:“在javascript中,一切皆是对象”。那么对象是什么呢?ECMA-262把对象定义为:“无序属性的集合,其属性可以包含基本值,对象或者函数”。也就是说对象是一组没有特定顺序的值,它的每个属性或者方法都有一个名字,每个名字都映射到一个值。
创建对象有很多种方法,最原始的方法是这样的:
也可以这样写:
虽然这些方式都可以简单的创建一个对象,但是它们都有明显的弊端。假如说我们要创建一组相似的对象,这些对象拥有相同的属性名,只是属性值各不相同,我们用上面的办法就需要重复很多的代码,这显然是不合理的。还好我们有更机智的办法。
工厂模式
对于上面创建多个相似对象的问题,我们可以用一个函数来封装它所有的属性,这样我们只要给函数传入不同的参数(属性值),就能轻松创建出一个对象。就像工厂里加工产品一样,只要有一个模子,我们就可以复制出来无数个产品。
简单来说,使用工厂模式创建对象的过程就是,在函数内创建一个对象,赋予属性及方法后再将对象返回。但是工厂模式创建的实例类型全都是Object,却不能识别到底是哪种对象类型。instanceof
用于判断一个变量是否是某个对象的实例,从上例最后两行代码就能看出,工厂模式就像暗箱操作,实例不知道自己是被谁创造的。但是好在“构造函数模式”可以解决这个问题。
构造函数模式
我们用构造函数重写上面的栗子:
最后两行代码可以看出,在这个模式中,可以验证fun是构造函数Person的实例,说明了构造函数可以将它的实例标识为一种特定的类型,这正是胜于工厂模式的地方。
我们仔细观察构造函数与工厂模式创造的函数的不同之处:
- 没有显式地创建对象;
- 直接将属性和方法赋值给了this对象;
- 没有return语句;
- 函数首字母大写(为了区别于普通函数);
- 调用函数时用到
new
操作符。
new操作符
构造函数跟其他函数的唯一区别,就在于调用它们的方式不同,任何函数,只要通过new
操作符来调用,那它就可以作为构造函数。通过new
调用函数时会经历以下步骤:
- 创建一个新对象;
- 将构造函数的作用域赋值给了新对象(因此this就指向了这个新对象);
- 执行构造函数中的代码(为这个新对象添加属性);
- 返回新对象
构造函数的问题
构造函数模式虽然好用,但也并非没有缺点,它的主要问题就是每个方法要在每个实例上创建一遍。在上面的栗子中,实例fun
中创建了一个getName
方法,但是如果我们再实例化一个对象,会再次创建一个getName
方法,并且这两个同名函数是不相等的。
这些getName
方法实现的功能是完全一样的,但是由于分别属于不同的实例,就不得不为每个getName
分配空间,这显然是不合理的,那要怎么样才能让所有的实例都访问同一个getName
方法呢,这就要用到原型模式了。关于原型,且听下回分解。