我发现在 JavaScript 里如果非要用类 class,对象 object,实例 instance 来描述面向对象概念的话,很容易搞混。比如 obj instanceof Constructor
, 我们可以说 “这个对象是那个构造函数的一个实例” 吗?感觉怪怪的。
还有在某些开发语言语境里,对象有点像类,是个抽象概念,而在 JavaScript 里,对象就是实例,实实在在位于内存的某个位置。
构造函数的原型就是为构造函数这个对象创建蓝图添加新功能的。
原型特点
-
使用原型可以方便地定义对象,但是原型其实是函数的一个特性。只有函数才有原型,对象没有原型。
-
原型一旦定义,它的属性就变为了对象的属性,甚至是原型定义之前已经初始化的同类对象,在原型定义后都可以调用这个构造函数的原型。原型不是被简单拷贝到每个对象,而是被附加在对象上。原型和构造函数内的函数或变量同名的话,会优先调用构造函数内的函数或变量,只有在构造函数内找不到才会在原型里继续搜寻。但是后面提到的继承不往前追溯。Ninja 的对象必须在
Ninja.prototype = new Person();
继承语句之后被创建才能继承 Person '类’。 -
原型不光可以给对象添加方法(method),也可以添加属性(property)。
new 关键字
var obj = new func();
函数前用 new 关键字是函数作为构造函数(constructor)被调用。所以注意,这里不是定义,func()内的所有语句会被依次执行。返回值 obj 是一个新创建的对象,不再是函数了。
继承
下面 Ninja 继承了 Person,所以 n 是 Person 的一个实例(对象)。
Ninja.prototype = new Person();
var n = new Ninja(); // n instanceof Person 会返回 true
小技巧:使用 undefined || null;
来避免调用到 undefined 使程序崩溃。
例如:callback.call(context || null, “arg”);
JavaScript 的常用代码规范:
如果一个函数是用作构造函数的话名字首字母大写,比如 function Ninja(){}
;其他所有不是构造函数的都用小写字母命名。
另外, 构造函数一般是名词,对应将要创建的 '类 (class)'。普通函数一般使用动词来命名,或者动词加名词,描述做什么。