JavaScript面向对象编程

命名空间

命名空间是一个容器,它允许开发人员在一个独特的,特定于应用程序的名称下捆绑所有的功能。 在JavaScript中,命名空间只是另一个包含方法,属性,对象的对象。

需要认识到非常重要的一点,与其他面向对象编程语言中的普通对象和命名空间相比,它们在语言层面上没有区别。

创造的JavaScript命名空间背后的想法很简单:一个全局对象被创建,所有的变量,方法和功能成为该对象的属性。使用命名空间也最大程度地减少应用程序的名称冲突的可能性。

我们来创建一个全局变量叫做 MYAPP

// 全局命名空间
var MYAPP = MYAPP || {};
 

在上面的代码示例中,我们首先检查MYAPP是否已经被定义(是否在同一文件中或在另一文件)。如果是的话,那么使用现有的MYAPP全局对象,否则,创建一个名为MYAPP的空对象用来封装方法,函数,变量和对象。

我们也可以创建子命名空间:

// 子命名空间
MYAPP.event = {};
 

下面是用于创建命名空间和添加变量,函数和方法的代码写法:

// 给普通方法和属性创建一个叫做MYAPP.commonMethod的容器
MYAPP.commonMethod = {
regExForName: "", // 定义名字的正则验证
regExForPhone: "", // 定义电话的正则验证
validateName: function(name){
// 对名字name做些操作,你可以通过使用“this.regExForname”
// 访问regExForName变量
}, validatePhoneNo: function(phoneNo){
// 对电话号码做操作
}
} // 对象和方法一起申明
MYAPP.event = {
addListener: function(el, type, fn) {
// 代码
},
removeListener: function(el, type, fn) {
// 代码
},
getEvent: function(e) {
// 代码
} // 还可以添加其他的属性和方法
} //使用addListner方法的写法:
MYAPP.event.addListener("yourel", "type", callback);
 

标准内置对象

JavaScript有包括在其核心的几个对象,例如,Math,Object,Array和String对象。下面的例子演示了如何使用Math对象使用其随机()方法来获得一个随机数。

console.log(Math.random());
 
注意:T这里和接下来的例子都假设名为 console.log 的方法全局有定义。console.log 实际上不是 JavaScript 自带的。

查看 JavaScript 参考:全局对象 了解 JavaScript 内置对象的列表。

JavaScript 中的每个对象都是 Object 对象的实例且继承它所有的属性和方法。

自定义对象

JavaScript是一种基于原型的语言,它没类的声明语句,比如C+ +或Java中用的。这有时会对习惯使用有类申明语句语言的程序员产生困扰。相反,JavaScript可用方法作类。定义一个类跟定义一个函数一样简单。在下面的例子中,我们定义了一个新类Person。

function Person() { }
// 或
var Person = function(){ }
 

对象(类的实例)

我们使用 new obj 创建对象 obj 的新实例, 将结果(obj 类型)赋值给一个变量方便稍后调用。

在下面的示例中,我们定义了一个名为Person的类,然后我们创建了两个Person的实例(person1 and person2).

function Person() { }
var person1 = new Person();
var person2 = new Person();
 
有两种为对象创建实例,请参考 Object.create 。

构造器

在实例化时构造器被调用 (也就是对象实例被创建时)。构造器是对象中的一个方法。 在JavaScript,中函数就可以作为构造器使用,因此不需要特别地定义一个构造器方法. 每个声明的函数都可以在实例化后被调用执行

构造器常用于给对象的属性赋值或者为调用函数做准备。 在本文的后面描述了类中方法既可以在定义时添加,也可以在使用前添加。

在下面的示例中, Person类实例化时构造器调用一个 alert函数。

function Person() {
alert('Person instantiated');
} var person1 = new Person();
var person2 = new Person();
 

属性 (对象属性)

属性就是 类中包含的变量;每一个对象实例有若干个属性. 为了正确的继承,属性应该被定义在类的原型属性 (函数)中。

可以使用 关键字 this调用类中的属性, this是对当前对象的引用。 从外部存取(读/写)其属性的语法是: InstanceName.Property; 这与C++,Java或者许多其他语言中的语法是一样的 (在类中语法 this.Property 常用于set和get属性值)

在下面的示例中,我们为定义Person类定义了一个属性 firstName 并在实例化时赋初值。

function Person(firstName) {
this.firstName = firstName;
alert('Person instantiated');
} var person1 = new Person('Alice');
var person2 = new Person('Bob'); // Show the firstName properties of the objects
alert('person1 is ' + person1.firstName); // alerts "person1 is Alice"
alert('person2 is ' + person2.firstName); // alerts "person2 is Bob"
 

方法

方法与属性很相似, 不同的是:一个是函数,另一个可以被定义为函数。 调用方法很像存取一个属性,  不同的是add () 在方法名后面很可能带着参数. 为定义一个方法, 需要将一个函数赋值给类的 prototype 属性; 这个赋值给函数的名称就是用来给对象在外部调用它使用的。

在下面的示例中,我们给Person类定义了方法 sayHello(),并调用了它.

function Person(firstName) {
this.firstName = firstName;
} Person.prototype.sayHello = function() {
alert("Hello, I'm " + this.firstName);
}; var person1 = new Person("Alice");
var person2 = new Person("Bob"); // call the Person sayHello method.
person1.sayHello(); // alerts "Hello, I'm Alice"
person2.sayHello(); // alerts "Hello, I'm Bob"
 

在JavaScript中方法通常是一个绑定到对象中的普通函数, 这意味着方法可以在其所在context之外被调用。 思考下面示例中的代码:

function Person(firstName) {
this.firstName = firstName;
} Person.prototype.sayHello = function() {
alert("Hello, I'm " + this.firstName);
}; var person1 = new Person("Alice");
var person2 = new Person("Bob");
var helloFunction = person1.sayHello; person1.sayHello(); // alerts "Hello, I'm Alice"
person2.sayHello(); // alerts "Hello, I'm Bob"
helloFunction(); // alerts "Hello, I'm undefined" (or fails
// with a TypeError in strict mode)
alert(helloFunction === person1.sayHello); // alerts true
alert(helloFunction === Person.prototype.sayHello); // alerts true
helloFunction.call(person1); // alerts "Hello, I'm Alice"
 

如上例所示, 所有指向sayHello函数的引用 ,包括 person1Person.prototype, 和 helloFunction 等, 均引用了相同的函数.

在调用函数的过程中,this的值取决于我们怎么样调用函数.  在通常情况下,我们通过一个表达式person1.sayHello()来调用函数:即从一个对象的属性中得到所调用的函数。此时this被设置为我们取得函数的对象(即person1)。这就是为什么person1.sayHello() 使用了姓名“Alice”而person2.sayHello()使用了姓名“bob”的原因。

然而我们使用不同的调用方法时, this的值也就不同了。当从变量 helloFunction()中调用的时候, this就被设置成了全局对象 (在浏览器中即window)。由于该对象 (非常可能地) 没有firstName 属性, 我们得到的结果便是"Hello, I'm undefined". (这是松散模式下的结果, 在 严格模式中,结果将不同(此时会产生一个error)。 但是为了避免混淆,我们在这里不涉及细节) 。另外,我们可以像上例末尾那样,使用Function#call (或者Function#apply)显式的设置this的值。

更多有关信息请参考 Function#call and Function#apply

继承

创建一个或多个类的专门版本类方式称为继承(Javascript只支持单继承)。 创建的专门版本的类通常叫做子类,另外的类通常叫做父类。 在Javascript中,继承通过赋予子类一个父类的实例并专门化子类来实现。在现代浏览器中你可以使用 Object.create 实现继承.

JavaScript 并不检测子类的 prototype.constructor (见 Object.prototype), 所以我们必须手动申明它.

在下面的例子中, 我们定义了 Student类作为 Person类的子类. 之后我们重定义了sayHello() 方法并添加了 sayGoodBye() 方法.

// 定义Person构造器
function Person(firstName) {
this.firstName = firstName;
} // 在Person.prototype中加入方法
Person.prototype.walk = function(){
alert("I am walking!");
};
Person.prototype.sayHello = function(){
alert("Hello, I'm " + this.firstName);
}; // 定义Student构造器
function Student(firstName, subject) {
// 调用父类构造器, 确保(使用Function#call)"this" 在调用过程中设置正确
Person.call(this, firstName); // 初始化Student类特有属性
this.subject = subject;
}; // 建立一个由Person.prototype继承而来的Student.prototype对象.
// 注意: 常见的错误是使用 "new Person()"来建立Student.prototype.
// 这样做的错误之处有很多, 最重要的一点是我们在实例化时
// 不能赋予Person类任何的FirstName参数
// 调用Person的正确位置如下,我们从Student中来调用它
Student.prototype = Object.create(Person.prototype); // See note below // 设置"constructor" 属性指向Student
Student.prototype.constructor = Student; // 更换"sayHello" 方法
Student.prototype.sayHello = function(){
alert("Hello, I'm " + this.firstName + ". I'm studying " + this.subject + ".");
}; // 加入"sayGoodBye" 方法
Student.prototype.sayGoodBye = function(){
alert("Goodbye!");
}; // 测试实例:
var student1 = new Student("Janet", "Applied Physics");
student1.sayHello(); // "Hello, I'm Janet. I'm studying Applied Physics."
student1.walk(); // "I am walking!"
student1.sayGoodBye(); // "Goodbye!" // Check that instanceof works correctly
alert(student1 instanceof Person); // true
alert(student1 instanceof Student); // true
 

对于“Student.prototype = Object.create(Person.prototype);”这一行,在不支持 Object.create方法的老JavaScript引擎中,可以使用一个"polyfill"(又名"shim",查看文章链接),或者使用一个function来获得相同的返回值,就像下面:

function createObject(proto) {
function ctor() { }
ctor.prototype = proto;
return new ctor();
} // Usage:
Student.prototype = createObject(Person.prototype);
 
更多相关信息请参考 Object.create,连接中还有一个老JavaScript引擎的兼容方案(shim)。

封装

在上一个例子中,Student类虽然不需要知道Person类的walk()方法是如何实现的,但是仍然可以使用这个方法;Student类不需要明确地定义这个方法,除非我们想改变它。 这就叫做封装,对于所有继承自父类的方法,只需要在子类中定义那些你想改变的即可。

抽象

抽象是允许模拟工作问题中通用部分的一种机制。这可以通过继承(具体化)或组合来实现。
JavaScript通过继承实现具体化,通过让类的实例是其他对象的属性值来实现组合。

JavaScript Function 类继承自Object类(这是典型的具体化) 。Function.prototype的属性是一个Object实例(这是典型的组合)。

var foo = function(){};
alert( 'foo is a Function: ' + (foo instanceof Function) ); // alerts "foo is a Function: true"
alert( 'foo.prototype is an Object: ' + (foo.prototype instanceof Object) ); // alerts "foo.prototype is an Object: true"
 

多态

就像所有定义在原型属性内部的方法和属性一样,不同的类可以定义具有相同名称的方法;方法是作用于所在的类中。并且这仅在两个类不是父子关系时成立(继承链中,一个类不是继承自其他类)。

注意

本文中所展示的面向对象编程技术不是唯一的实现方式,在JavaScript中面向对象的实现是非常灵活的。

同样的,文中展示的技术没有使用任何语言hacks,它们也没有模仿其他语言的对象理论实现。

JavaScript中还有其他一些更加先进的面向对象技术,但这些都超出了本文的介绍范围。

文章出处:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript

JavaScript面向对象编程[转]的更多相关文章

  1. JavaScript面向对象编程学习笔记

    1  Javascript 面向对象编程 所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量.对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例 ...

  2. 快速学习JavaScript面向对象编程

    到处都是属性.方法,代码极其难懂,天哪,我的程序员,你究竟在做什么?仔细看看这篇指南,让我们一起写出优雅的面向对象的JavaScript代码吧! 作为一个开发者,能否写出优雅的代码对于你的职业生涯至关 ...

  3. 深入理解Javascript面向对象编程

    深入理解Javascript面向对象编程 阅读目录 一:理解构造函数原型(prototype)机制 二:理解原型域链的概念 三:理解原型继承机制 四:理解使用类继承(继承的更好的方案) 五:建议使用封 ...

  4. 【转】Javascript 面向对象编程(一):封装

    原文链接:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html Javascript ...

  5. Javascript 面向对象编程(一):封装 by 阮一峰

    <Javascript高级程序设计(第二版)>(Professional JavaScript for Web Developers, 2nd Edition) 它们都是非常优秀的Java ...

  6. 转:javascript面向对象编程

    作者: 阮一峰 日期: 2010年5月17日 学习Javascript,最难的地方是什么? 我觉得,Object(对象)最难.因为Javascript的Object模型很独特,和其他语言都不一样,初学 ...

  7. 探讨javascript面向对象编程

    (个人blog迁移文章.) 前言: 下面将探讨javascript面向对象编程的知识. 请不要刻意把javascript想成面向对象编程是理所当然的. javascript里面,对象思想不可少,但是不 ...

  8. JavaScript面向对象编程(一)原型与继承

    原型(prototype) JavaScript是通过原型(prototype)进行对象之间的继承.当一个对象A继承自另外一个对象B后,A就拥有了B中定义的属性,而B就成为了A的原型.JavaScri ...

  9. JavaScript面向对象编程(二)构造函数和类

    new关键字和构造函数 在文章JavaScript面向对象编程(一)原型与继承中讨论啦JavaScript中原型的概念,并且提到了new关键字和构造函数.利用new关键字构造对象的实例代码如下: // ...

  10. JavaScript 面向对象编程(三)如何写类和子类

    在JavaScript面向对象编程(一)原型与继承和JavaScript面向对象编程(二)构造函数和类中,我们分别讨论了JavaScript中面向对象的原型和类的概念.基于这两点理论,本篇文章用一个简 ...

随机推荐

  1. Erlang/OTP:基于Behaviour的回调函数

    原始链接:https://blog.zhustec.me/posts/erlang-otp-1-callback-based-on-behaviour OTP 是什么 OTP 的全称是开源电信平台 ( ...

  2. 【OpenPose-Windows】OpenPose+VS2015+Windows+CUDA8+cuDNN5.1 官方配置教程(转载)

    [我的电脑配置] 操作系统:Windows 10 CUDA版本:cuda_8.0.61_win10 cuDNN版本:cudnn-8.0-windows10-x64-v5.1 GPU model:Nvi ...

  3. Technology, globalisation and the squeeze on good jobs

    Technology, globalisation and the squeeze on good jobs技术与全球化冲击好工作“Highest stock market EVER! Jobs ar ...

  4. To zero

    Let bygone be bygone. Now  everything changed. In fact, everything occurs to me cause I am a loser i ...

  5. 使用HTTP头去绕过WAF(bypasswaf)

    在用node http get 请求的时候,发现的 解决方案: Add headers to all Burp requests to bypass some WAF products. This e ...

  6. IPMS 元件实作

    一.改用zg框架的jsp 1.引入表头和表尾jsp <%@ include file="../../jsp/menuHeader.jsp"%> <%@ inclu ...

  7. Android模拟器内安装应用

    一.通过apk安装器安装应用 1.下载apk安装器(网上随便搜一个就可以) 2.下载要测试的应用的apk,我这里下载的是微信的apk 3.打开apk安装器,点击右上角的Devices选择要安装到的设备 ...

  8. 格式化java8 LocalDateTime

    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(time1);

  9. INI

    .ini 文件是Initialization File的缩写,即初始化文件,是windows的系统配置文件所采用的存储格式,统管windows的各项配置,一般用户就用windows提供的各项图形化管理 ...

  10. Cocos2d-x 3.x 在wp8中调用系统字体的解决方案

    问题和解决方法: 在使用cocos2d-x设计游戏的时候,字体是个很重要的部分.如果游戏中对字体没有太多的要求,就可以使用平台系统自带的字体,可以节省游戏的尺寸,以及减小游戏运行时所占用的内存.当加载 ...