Java面向对象和JavaScript面向对象的区别
JS面向对象是采用原型链的方式设计的,JAVA是采用正统的面向对象的思想设计的.
ECMA-262 把对象(object)定义为“属性的无序集合,每个属性存放一个原始值、对象或函数”。严格来说,这意味着对象是无特定顺序的值的数组。
面向对象语言的要求:一种面向对象语言需要向开发者提供四种基本能力
封装 - 把相关的信息(无论数据或方法)存储在对象中的能力
聚集 - 把一个对象存储在另一个对象内的能力
继承 - 由另一个类(或多个类)得来类的属性和方法的能力
多态 - 编写能以多种方法运行的函数或方法的能力
对象的创建和销毁都在 JavaScript 执行过程中发生,理解这种范式的含义对理解整个语言至关重要。
JavaScript 中的所有事物都是对象:字符串、数值、数组、函数... 此外,JavaScript 允许自定义对象。
JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。
原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。
准确地说,这些属性和方法定义在Object的构造器函数(constructor functions)之上的prototype
属性上,而非对象实例本身。
javascript中,每个对象都会在内部生成一个 proto
属性,当我们访问一个对象属性时,如果这个对象不存在就回去 proto
指向的对象里面找,一层一层找下去,,知道找到为止,如果到了原型链顶端,还没找到,则返回undefined
,这就是javascript原型链的概念。
基于类 vs 基于原型的语言
基于类的面向对象语言,比如 Java 和 C++,是构建在两个不同实体的概念之上的:即类和实例。
类(class):定义了所有用于具有某一组特征对象的属性(可以将 Java 中的方法和变量以及 C++ 中的成员都视作属性)。类是抽象的事物,而不是其所描述的全部对象中的任何特定的个体。例如Employee 类可以用来表示所有雇员的集合。
实例(instance):类的实例化体现;或者说,是类的一个成员。例如, Victoria 可以是Employee 类的一个实例,表示一个特定的雇员个体。实例具有和其父类完全一致的属性。
基于原型的语言(如 JavaScript)并不存在这种区别:它只有对象。基于原型的语言具有所谓原型对象(prototypical object)的概念。原型对象可以作为一个模板,新对象可以从中获得原始的属性。任何对象都可以指定其自身的属性,既可以是创建时也可以在运行时创建。而且,任何对象都可以作为另一个对象的原型(prototype),从而允许后者共享前者的属性。
定义类
在基于类的语言中,需要专门的类定义符(class definition)定义类。在定义类时,允许定义特殊的方法,称为构造器(constructor),来创建该类的实例。在构造器方法中,可以指定实例的属性的初始值以及一些其他的操作。您可以通过将new 操作符和构造器方法结合来创建类的实例。
JavaScript 也遵循类似的模型,但却不同于基于类的语言。在 JavaScript 中你只需要定义构造函数来创建具有一组特定的初始属性和属性值的对象。任何 JavaScript 函数都可以用作构造器。 也可以使用 new 操作符和构造函数来创建一个新对象。
子类和继承
基于类的语言是通过对类的定义中构建类的层级结构的。在类定义中,可以指定新的类是一个现存的类的子类。子类将继承父类的全部属性,并可以添加新的属性或者修改继承的属性。例如,假设Employee 类只有 name 和 dept 属性,而 Manager 是Employee 的子类并添加了 reports 属性。这时,Manager 类的实例将具有所有三个属性:name,dept 和reports。
JavaScript 通过将构造器函数与原型对象相关联的方式来实现继承。这样,您可以创建完全一样的 Employee — Manager 示例,不过需要使用略微不同的术语。首先,定义 Employee 构造器函数,指定 name 和dept 属性;然后,定义 Manager 构造器函数,指定 reports 属性。最后,将一个新的Employee 对象赋值给 Manager 构造器函数的 prototype 属性。这样,当创建一个新的Manager 对象时,它将从 Employee 对象中继承 name and dept 属性。
添加和移除属性
在基于类的语言中,通常在编译时创建类,然后在编译时或者运行时对类的实例进行实例化。一旦定义了类,无法对类的属性进行更改。然而,在 JavaScript 中,允许运行时添加或者移除任何对象的属性。如果您为一个对象中添加了一个属性,而这个对象又作为其它对象的原型,则以该对象作为原型的所有其它对象也将获得该属性。
区别摘要
下面的表格摘要给出了上述区别。本节的后续部分将描述有关使用 JavaScript 构造器和原型创建对象层级结构的详细信息,并将其与在 Java 中的做法加以对比。
一.面向对象的能力
JS对于对象的理解为“属性的无序集合,每个属性存放一个原始值、对象或函数”JS只有一种访问作用域public. JS不支持静态作用
Java的对象是具有类定义,类有方法,属性,还有静态,和访问作用域(public ,private, protected)。java支持静态作用域
早绑定与晚绑定
所谓绑定,是把对象的接口和对象实例结合在一起的方法。
早绑定,是在实例化对象之前定义它的特性与方法,编译器或解释程序就能提前转为机器代码。java是属于早绑定.
晚绑定,是编译器和解释程序在运行前,不知道对象的类型。ECMAScript的所有变量采用晚绑定。
二.定义类或者对象
JS定义类或者对象的方法有6种:
目前广泛使用的是构造函数/原型方式。动态原型方法也很流行,功能上与构造函数/原型等价
1·工厂方法 提供能创建并返回特定类型对象的工厂函数
function createCar(sColor, iDoors, iMpg){
var oTempCar = new Object;
oTempCar.color = sColor;
oTempCar.doors = iDoors;
oTempCar.mpg = iMpg;
oTempCar.showColor = function (){
alert(this.color);
};
return oTempCar;
}
varCar1 = createCar("red", 4, 23);
2·构造函数方式 第一步选择类名,即构造函数的名字,根据惯例这个构造函数的首字母大写。
function Car(sColor, iDoors, iMpg){
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.showColor = function (){
alert(this.color);
};
}
var oCar1 = new Car("red", 4, 23);
3·原型方式 该方式利用对象的prototyppe属性
function Car(){
}
Car.prototype.color = "red";
Car.prototype.doors = 4;
Car.prototype.mpg = 23;
Car.prototype.showColor = function (){
alert(this.color);
};
var oCar1 = new Car();
4· 混合构造函数/原型方式 利用构造函数方式来定义对象的所有非函数属性,利用原型方式来定义
对象的函数属性(这种方式是开发者采取的主要方式)
function Car(sColor, iDoors, iMpg){
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
}
Car.prototype.showColor = function (){
alert(this.color);
};
var oCar1 = new Car("red", 4, 23);
5· 动态原型方式 对于对象的函数和属性进行完全的封装到构造函数中
function Car(sColor, iDoors, iMpg){
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
if(typeof Car._initialized=="undefined"){
Car.prototype.showColor = function (){
alert(this.color);
};
Car._initialized = true;
}
}
var oCar1 = new Car("red", 4, 23);
6· 混合工厂方式 这种方式是不能应用前一种方式的变通方法。通过提供假构造函数,返回另一种对象的新实例。
function Car(sColor, iDoors, iMpg){
var oTempCar = new Object;
oTempCar.color = sColor;
oTempCar.doors = iDoors;
oTempCar.mpg = iMpg;
oTempCar.showColor = function (){
alert(this.color);
};
return oTempCar;
}
varCar1 = new Car("red", 4, 23);
Java定义类/对象的方式
Java采用严格的类声明方式
Class Car {
private String color;
public String showColor(){
...
}
}
还有一种在特殊方式,用在产生interface和abstract类的实例,即匿名类方式。
三.修改对象定义
JS可以修改对象定义,Java不可以;
创建新方法
可以使用Prototype属性为任何已有的类定义新方法。
Number.prototype.toHexString = funtion (){
return this.toString(16);
};
重定义已有方法
同定义新方法一样,也可以重定义已有的方法。函数名只是指向函数的指针,因此可以轻易的使它指向其他函数。
Function.prototype.toString = function (){
return "Function code hidden";
};
function sayHi() {
alert("hi");
}
alert(SayHi.toString());
极晚绑定
这是一种现象,能够在对象实例化后再定义其方法。应该尽量少用。