尽管面向对象JavaScript与其他语言相比之下存在差异,并由此引发了一些争论,但毋庸置疑,JavaScript具有强大的面向对象编程能力 JavaScript回顾 如果你对诸如变量(variables)、类型(types)、函数(functions)、以及作用域(scope)等JavaScript概念觉得心里没底,那么你可以阅读重新介绍JavaScript中的这些主题。你还可以查阅JavaScript 1.5核心指南 面向对象编程是一种编程范式(paradigm),即使用抽象来创建基于真实世界的模型。它使用了几种以前建立的范式技术,包括模块化(modularity)、多态(polymorphism)、和封装(encapsulation)。今天,许多流行的编程语言(比如Java、JavaScript、C#、C 、Python、PHP、Ruby、以及Objective-C)都支持面向对象编程(OOP)。 专用术语 类(Class) 基于原型的编程 基于原型的编程(Prototype-based programming)是一种面向对象编程风格,其中类(classes)并不存在,并且行为重用(在基于类的语言中称为继承)是通过粉饰充当原型的现存对象来完成的。这种模式也称为无类的(class-less)、面向原型的(prototype-oriented)、或基于实例(instance-based)的编程。 JavaScript面向对象编程 核心对象(Core Objects) JavaScript有几个包含在其核心中的对象;例如,Math、Object、Array、以及String等对象。下面的示例演示了如何使用Math对象的random()方法获取随机数。 alert(Math.random()); 提示:本例和所有其他示例都假设已在全局范围内定义了函数名alert(正如包含在web浏览器中的alert一样)。alert函数实际上不是JavaScript本身的一部分。 JavaScript核心对象列表,参阅JavaScript 1.5核心参考:全局对象(Global Objects)。 自定义对象(Custom Objects) 类(The Class) function Person() { } 对象(类实例)(The Object (Class Instance)) 要创建obj对象的一个新实例,我们使用语句new obj,同时将结果(其类型是obj)赋给某个变量(variable),以便稍后访问。 在下例中,我们首先定义名为Person的类,然后创建两个实例(person1和person2)。 function Person() {}
var person1 = new Person(); var person2 = new Person(); 还可参阅新的实例化替代方法Object.create。 当实例化时(创建对象实例的瞬间)是会调用构造函数。构造函数是类的一个方法。而在JavaScript中,会函数(function)作为作为该对象的构造函数;因此,也就无需显式定义一个构造函数方法。类中声明的每个行为在实例化时都会执行。 function Person() {
alert('Person instantiated'); } var person1 = new Person(); var person2 = new Person(); 属性(对象属性)(The Property (object attribute)) 属性是包含在类中的变量;每个对象实例都有这些属性。属性应设置在类(函数)的原型(prototype)属性中,以便继承正常工作。 function Person(gender) {
this.gender = gender; alert('Person instantiated'); } var person1 = new Person('Male'); // Male: 男 var person2 = new Person('Female'); // Female: 女 //显示person1的性别 alert('person1 is a ' person1.gender); // person1 is a Male 方法(The methods) function Person(gender) {
this.gender = gender; alert('Person instantiated'); } Person.prototype.sayHello = function() { alert('hello'); }; var person1 = new Person('Male'); var person2 = new Person('Female'); // 调用Person的sayHello方法。 person1.sayHello(); // hello 在JavaScript中,方法是作为属性被绑定到某个类/对象的普通函数对象,这意味着,可以“脱离上下文(out of the context)”来调用它们。考虑如下示例代码: function Person(gender) { this.gender = gender; } Person.prototype.sayGender = function() { alert(this.gender); }; var person1 = new Person('Male'); var genderTeller = person1.sayGender; person1.sayGender(); // alerts 'Male' genderTeller(); // alerts undefined alert(genderTeller === person1.sayGender); // alerts true alert(genderTeller === Person.prototype.sayGender); // alerts true 此示例一次演示了多个概念。这表明,在JavaScript中没有“基于对象的方法(per-object methods)”,因为该方法的所有引用都指向完全相同的函数,即我们起初在原型上定义的那个函数。当某个函数被作为方法(或确切地说是属性)调用时,JavaScript会将当前的“对象上下文(object context)”“绑定”到特定的“this”变量。这与调用该函数对象的“call”方法等效,如下所示: genderTeller.call(person1); //alerts 'Male'e 更多相关信息,请参阅Function.call和Function.apply 继承(Inheritance) 继承是一种方法,用于创建作为一个或多个类专用版本的类。(JavaScript仅支持单类继承)。这个专用类通常被称为子类(child),而其他类通常被称为父类(parent)。在JavaScript中,你要完成继承,需将父类的实例赋给子类,然后将子类特化(specializing)。 提示:由于JavaScript不检测的子类的prototype.constructor(原型的构造函数),参阅Core JavaScript 1.5核心参考:Global Objects:Object:prototype属性,因此我们必须手动指定该值。 在下例中,我们定义Student类作为Person的子类。然后我们重新定义sayHello()方法,并添加sayGoodBye()方法。 // 定义Person类 function Person() {} Person.prototype.walk = function() { alert('I am walking!'); }; Person.prototype.sayHello = function() { alert('hello'); }; // 定义Student类 function Student() { //调用父类构造函数 Person.call(this); } // 继承Person Student.prototype = new Person(); // 修正构造函数指针,由于它指向Person Student.prototype.constructor = Student; // 替换sayHello方法 Student.prototype.sayHello = function() { alert('hi, I am a student'); } // 添加sayGoodBye方法 Student.prototype.sayGoodBye = function() { alert('goodBye'); } var student1 = new Student(); student1.sayHello(); student1.walk(); student1.sayGoodBye(); // 检验继承 alert(student1 instanceof Person); // true alert(student1 instanceof Student); // true
在上例中,Student无须知晓Person类的walk()方法是如何实现的,但仍可使用该方法;Student类无须显式定义该方法,除非我们想改变它。这称为封装(encapsulation),这样每个类继承其父类的方法,并且只需定义它所希望改变的东西。 抽象 抽象是一种机制(mechanism),允许对处理中的问题的当前部分进行建模。这可以通过继承(特化)或组合(composition)来实现。JavaScript通过继承实现特化(specialization),通过让类实例成为其他对象的属性值实现组合。 var foo = function() {};
alert('foo is a Function: ' (foo instanceof Function)); alert('foo.prototype is an Object: ' (foo.prototype instanceof Object)); 多态 就像所有的方法和属性被定义在原型属性内部一样,不同的类可以定义具有相同名称的方法;方法的作用域限于定义它们的类之内。这仅当两个类之间没有父子关系(当一个类没有从继承链中的其他类继承时)时才为真。 提示 本文中所提出的面向对象编程实现技术不仅适用于JavaScript,因为就如何进行面向对象编程而言,这是非常灵活的。 |
|
来自: 潇湘雨plgwyaef > 《待分类》