类和构造函数

定义构造函数既是定义类,并且类名要大些,而普通的函数和方法都是首字母小写。

 构造函数和类的标识

原型对象是类的唯一标识:当且仅当两个对象继承自同一个原型对象时,他们才是属于同一个类的实例。

JavaScript中的Java式的类继承

  •  构造函数对象

之前提到,构造函数(对象)为JavaScript的类定义了名字。任何添加到这个构造函数对象中的属性都是类字段和类方法。

  •  原型对象

原型对象的属性被类的所有实例所继承,如果原型对象的属性是函数的话,这个函数就作为类的实例的方法来调用。

  •  实例对象

类的每个实例都是一个独立的对象,直接给这个实例定义的属性是不会为所有实例所共享的。定义在实例上的非函数属性,实际上实例的字段。

 类的扩充

JavaScript中基于原型的继承机制是动态的:对象从其原型继承属性,如果创建对象之后原型的属性发生改变,也会影响到继承这个原型的所有实例对象。

类和类型

instanceof运算符

尽管instanceof运算符的右操作数是构造函数,但计算过程实际上是检测了对象的继承关系,而不是坚持创建对象的构造函数。

 constructor属性

另一种识别对象是否属于某个类的方法是使用constructor属性。因为构造函数是类的公用标识,所以最直接的方法就是使用constructor属性。

 构造函数的名称

使用instanceof运算符和constructor属性来检测对象所属的类有一个主要的问题,在多个执行上下文中存在构造函数的多个副本的时候,这两种方法的检测结果会出错。多个执行上下文中的函数看起来一模一样,但它们是相互独立的对象,因为彼此不相等。

 鸭式辩型

为了解决客户都JavaScript中检测对象的类的各种技术所存在的缺陷问题,提出鸭式辩型:不要关注“对象的类是什么”,而是关注“对象能做什么”。

 JavaScript中的面向对象技术

  • toString()方法作用是返回一个可以表示这个对象的字符串,在希望使用字符串的地方用到对象的话,JavaScript会自动调用这个方法,如果没有实现这个方法,类会默认从Object.prototype中继承toString()方法,结果就是“[Object Object]”,这个字符串意义不大。
  •  toLocaleString()和toString()极为类似:toLocaleString()是以本地敏感性的方式来将对象转换为字符串。默认情况下,对象所继承的toLocaleString()只是简单的调用toString()方法。有一些内置类型包含有用的toLocaleString()方法用以实际返回本地化相关的字符串。如果需要为对象到字符串的转换定义toString()方法,那么同样需要定义toLocalString()方法用以处理本地化的对象到字符串的转换。
  • 第三个方法是valueOf(),它用来将对象转换为原始值。
  • 第四个方法是toJSON(),这个方法由JSON.stringify()自动调用。JSON格式用于序列化良好的数据结构,而且可以处理JavaScript原始值、数组和纯对象。它和类无关,当对一个对象执行序列化操作时,它会忽略对象的原型和构造函数。
  • 比较方法:JavaScript的相等运算符比较对象时,比较的是引用而不是值。
  • 方法借用:多个类中的方法可以公用一个单独的函数。

Range.prototype.equals = generic.equals;

 子类

JavaScript的对象可以从类的原型对象中继承属性。如果O是类B的实例,B是A的子类,那么O也一定从A中继承了属性。为此,首先要确保B的原型对象继承自A的原型对象。

B.prototype = inherit(A.prototype);

B.prototype.constructor = B;

这两行代码是Javascript中创建子类的关键,如果不这样做,原型对象仅仅是一个普通对象,它继承自Object.prototype,意味着你的类和所有类一样是Object的子类。

组合 VS 子类

面向对象编程中一条广为人知的设计原则:组合优于继承。


发表评论