diff options
Diffstat (limited to 'files/zh-cn/conflicting/learn/javascript')
-rw-r--r-- | files/zh-cn/conflicting/learn/javascript/client-side_web_apis/manipulating_documents/index.html | 172 | ||||
-rw-r--r-- | files/zh-cn/conflicting/learn/javascript/objects/index.html | 362 |
2 files changed, 534 insertions, 0 deletions
diff --git a/files/zh-cn/conflicting/learn/javascript/client-side_web_apis/manipulating_documents/index.html b/files/zh-cn/conflicting/learn/javascript/client-side_web_apis/manipulating_documents/index.html new file mode 100644 index 0000000000..1f53ff70ba --- /dev/null +++ b/files/zh-cn/conflicting/learn/javascript/client-side_web_apis/manipulating_documents/index.html @@ -0,0 +1,172 @@ +--- +title: JavaScript 与 CSS +slug: Web/Guide/CSS/Getting_started/JavaScript +translation_of: Learn/JavaScript/Client-side_web_APIs/Manipulating_documents +translation_of_original: Web/Guide/CSS/Getting_started/JavaScript +--- +<p>{{ CSSTutorialTOC() }}</p> + +<p>本文是 <a href="/en/CSS/Getting_Started" title="https://developer.mozilla.org/en/CSS/Getting_Started">CSS tutorial</a> 第二部分的第一章节。第二部分的内容主要是一些css和其他web技术的使用范例。 </p> + +<p>第二部分的内容主要来向你展示CSS是如何同其他技术进行交互的。但是这样做的目的并不是教你如何使用这些技术,如果你想深入学习,可以查找具体的文档。</p> + +<p>换句话说,这些页面是用来向你展示CSS的多种用途的。通过这些页面,你不需要掌握其他技术就可以获取到很多CSS的相关知识。</p> + +<p>上一章 (Part I): <a href="/en/CSS/Getting_Started/Media" title="https://developer.mozilla.org/en/CSS/Getting_Started/Media">Media</a><br> + 下一章: <a href="/en/CSS/Getting_Started/SVG_graphics" title="https://developer.mozilla.org/en/CSS/Getting_Started/SVG_graphics">SVG</a></p> + +<h3 id="Information:_JavaScript" name="Information:_JavaScript">相关知识: JavaScript</h3> + +<p>JavaScript是一种编程语言,它被广泛用来实现web站点和应用中的交互效果。</p> + +<p>JavaScript可以同样式进行交互,你可以通过编写程序来动态改变文档上元素的样式。 </p> + +<p>有三种方法可以实现这样的效果:</p> + +<ul> + <li>控制样式表—可以添加、删除、修改样式表。</li> + <li>控制样式规则—可以添加、删除、修改样式规则。</li> + <li>控制DOM中的单个元素—可以不依赖样式表来修改元素样式。</li> +</ul> + +<table style="background-color: #f4f4f4; border: 1px solid #3366bb; margin-bottom: 1em; padding: 1em; width: 100%;"> + <caption>更多细节</caption> + <tbody> + <tr> + <td>要了解 JavaScript的更多细节,可以到这个wiki <a href="/en/JavaScript" title="en/JavaScript">JavaScript</a> 。</td> + </tr> + </tbody> +</table> + +<h3 id="Action:_A_JavaScript_demonstration" name="Action:_A_JavaScript_demonstration">范例: 一个JavaScript的实例</h3> + +<p>新建一个<code>doc5.html的页面,把下面的代码复制粘贴进入,注意要保证保存了所有的代码:</code></p> + +<div style="width: 48em;"> +<pre class="brush:html;"><!DOCTYPE html> +<html> + +<head> +<title>Mozilla CSS Getting Started - JavaScript demonstration</title> +<link rel="stylesheet" type="text/css" href="style5.css" /> +<script type="text/javascript" src="script5.js"></script> +</head> + +<body> +<h1>JavaScript sample</h1> +<div id="square"></div> +<button>Click Me</button> + +</body> +</html> +</pre> +</div> + +<p>新建一个CSS文件<code>style5.css</code>,复制粘贴下面的样式代码到文件中:</p> + +<div style="width: 48em;"> +<pre class="brush:css;"> #square { + + width: 20em; + + height: 20em; + + border: 2px inset gray; + + margin-bottom: 1em; + + } + + button { + + padding: .5em 2em; + + }</pre> +</div> + +<p>新建一个JavaScript文件<code>script5.js</code>,复制粘贴下面的代码到文件中:</p> + +<div style="width: 48em;"> +<pre class="brush: js">// JavaScript demonstration +var changeBg = function (event) { + console.log("method called"); + var me = event.target + , square = document.getElementById("square"); + square.style.backgroundColor = "#ffaa44"; + me.setAttribute("disabled", "disabled"); + setTimeout(function () { clearDemo(me) }, 2000); +} + +function clearDemo(button) { + var square = document.getElementById("square"); + square.style.backgroundColor = "transparent"; + button.removeAttribute("disabled"); +} + +window.onload = function() { + var button = document.querySelector("button"); + button.addEventListener("click", changeBg); + console.log(button); +}</pre> +</div> + +<p>用浏览器打开HTML文件并点击按钮。</p> + +<p>这里有在线的示例:<a href="http://jsfiddle.net/diwanshi/Y4VPK/4/embedded/result/">Here is the Live Example</a></p> + +<table> + <tbody> + <tr> + <td style="padding-right: 2em;"> + <table style="border: 2px outset #3366bb; padding: 0 1em .5em .5em;"> + <tbody> + <tr> + <td> + <p><strong>JavaScript demonstration</strong></p> + </td> + </tr> + </tbody> + </table> + </td> + <td> + <table style="border: 2px outset #3366bb; padding: 0 1em .5em .5em;"> + <tbody> + <tr> + <td> + <p><strong>JavaScript demonstration</strong></p> + </td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> +</table> + +<div class="note"><strong>重要提示</strong> : + +<ul> + <li>HTML文档中外链了CSS文件和JavaScript文件。</li> + <li>脚本直接修改了DOM元素的样式,通过修改属性值来改变按钮的样式。</li> + <li>在JavaScript中<code>document.getElementById("square")</code> 在功能上同 CSS 选择器 <code>#square的功能是类似的。</code></li> + <li>在 JavaScript代码中, <code>backgroundColor</code> 对应于CSS 属性<code>background-color</code>。因为JavaScript中不允许在命名中出现中划线,所以采用了驼峰式,的写法来做替代。</li> + <li>浏览器针对button有内置的CSS规则 <code>button{{ mediawiki.external('disabled=\"true\"') }}</code> ,这会导致按钮在不可点击状态下的显示样式跟预期有出入。</li> +</ul> +</div> + +<table style="background-color: #fffff4; border: 1px solid #3366bb; margin-bottom: .5em; padding: 1em;"> + <caption>挑战</caption> + <tbody> + <tr> + <td>修改脚本代码实现如下效果:当颜色改变的时候让方块跳至右侧20em的距离,然后再恢复到原来的位置。</td> + </tr> + </tbody> +</table> + +<p>这里有一个解决方案示例:<a href="/en/CSS/Getting_Started/Challenge_solutions#JavaScript" title="https://developer.mozilla.org/en/CSS/Getting_Started/Challenge_solutions#JavaScript">See a solution to this challenge.</a></p> + +<h3 id="下一步做什么呢?">下一步做什么呢?</h3> + +<p>如果你对本页内容有疑问,或者有其他想法,欢迎到 <a href="/Talk:en/CSS/Getting_Started/JavaScript" title="Talk:en/CSS/Getting_Started/JavaScript">Discussion</a> 页面进行讨论。</p> + +<p>在示例中,尽管只有button元素使用了脚本代码,但是HTML文档还是i需要外链一个脚本文件。Mozilla 对CSS做了扩展,让它可以为选择元素引用JavaScript代码 (也可以使内容或者其他样式表文件) 。下篇文章会对此有详细说明: <strong><a href="/en/CSS/Getting_Started/XBL_bindings" title="en/CSS/Getting_Started/XBL_bindings">XBL bindings</a></strong></p> diff --git a/files/zh-cn/conflicting/learn/javascript/objects/index.html b/files/zh-cn/conflicting/learn/javascript/objects/index.html new file mode 100644 index 0000000000..1ae4554c63 --- /dev/null +++ b/files/zh-cn/conflicting/learn/javascript/objects/index.html @@ -0,0 +1,362 @@ +--- +title: JavaScript面向对象简介 +slug: Web/JavaScript/Introduction_to_Object-Oriented_JavaScript +tags: + - JavaScript + - OOP + - 命名空间 + - 对象 + - 封装 + - 成员 + - 构造函数 + - 继承 + - 面向对象 +translation_of: Learn/JavaScript/Objects +translation_of_original: Web/JavaScript/Introduction_to_Object-Oriented_JavaScript +--- +<div>{{jsSidebar("Introductory")}}</div> + +<div> </div> + +<p>JavaScript 的核心是支持面向对象的,同时它也提供了强大灵活的 OOP 语言能力。本文从对面向对象编程的介绍开始,带您探索 JavaScript 的对象模型,最后描述 JavaScript 当中面向对象编程的一些概念。</p> + +<h2 id="JavaScript_Review" name="JavaScript_Review">JavaScript回顾</h2> + +<p>如果您对 JavaScript 的概念(如变量、类型、方法和作用域等)缺乏自信,您可以在<a href="/zh-CN/JavaScript/A_re-introduction_to_JavaScript" title="en/JavaScript/A_re-introduction_to_JavaScript">重新介绍 JavaScript</a> 这篇文章里学习这些概念。您也可以查阅这篇 <a href="/zh-CN/JavaScript/Guide" title="en/JavaScript/Guide">JavaScript 1.5 核心指南</a>。</p> + +<h2 id="Object-oriented_programming" name="Object-oriented_programming">面向对象编程</h2> + +<p>面向对象编程是用抽象方式创建基于现实世界模型的一种编程模式。它使用先前建立的范例,包括模块化,多态和封装几种技术。今天,许多流行的编程语言(如Java,JavaScript,C#,C+ +,Python,PHP,Ruby和Objective-C)都支持面向对象编程(OOP)。</p> + +<p>相对于「一个程序只是一些函数的集合,或简单的计算机指令列表。」的传统软件设计观念而言,面向对象编程可以看作是使用一系列对象相互协作的软件设计。 在 OOP 中,每个对象能够接收消息,处理数据和发送消息给其他对象。每个对象都可以被看作是一个拥有清晰角色或责任的独立小机器。</p> + +<p>面向对象程序设计的目的是在编程中促进更好的灵活性和可维护性,在大型软件工程中广为流行。凭借其对模块化的重视,面向对象的代码开发更简单,更容易理解,相比非模块化编程方法 <a href="#cite-1"><sup>1</sup></a>, 它能更直接地分析, 编码和理解复杂的情况和过程。</p> + +<h2 id="Terminology" name="Terminology">术语</h2> + +<dl> + <dt>Namespace 命名空间</dt> + <dd>允许开发人员在一个独特,应用相关的名字的名称下捆绑所有功能的容器。</dd> + <dt>Class 类</dt> + <dd>定义对象的特征。它是对象的属性和方法的模板定义。</dd> + <dt>Object 对象</dt> + <dd>类的一个实例。</dd> + <dt>Property 属性</dt> + <dd>对象的特征,比如颜色。</dd> + <dt>Method 方法</dt> + <dd>对象的能力,比如行走。</dd> + <dt>Constructor 构造函数</dt> + <dd>对象初始化的瞬间,被调用的方法。通常它的名字与包含它的类一致。</dd> + <dt>Inheritance 继承</dt> + <dd>一个类可以继承另一个类的特征。</dd> + <dt>Encapsulation 封装</dt> + <dd>一种把数据和相关的方法绑定在一起使用的方法。</dd> + <dt>Abstraction 抽象</dt> + <dd>结合复杂的继承,方法,属性的对象能够模拟现实的模型。</dd> + <dt>Polymorphism 多态</dt> + <dd>多意为「许多」,态意为「形态」。不同类可以定义相同的方法或属性。</dd> +</dl> + +<p>更多关于面向对象编程的描述,请参照维基百科的 <a class="external" href="http://zh.wikipedia.org/wiki/面向对象程序设计">面向对象编程</a> 。</p> + +<h2 id="原型编程">原型编程</h2> + +<p>基于原型的编程不是面向对象编程中体现的风格,且行为重用(在基于类的语言中也称为继承)是通过装饰它作为原型的现有对象的过程实现的。这种模式也被称为弱类化,原型化,或基于实例的编程。</p> + +<p>原始的(也是最典型的)基于原型语言的例子是由大卫·安格尔和兰德尔·史密斯开发的。然而,弱类化的编程风格近来变得越来越流行,并已被诸如JavaScript,Cecil,NewtonScript,IO,MOO,REBOL,Kevo,Squeak(使用框架操纵Morphic组件),和其他几种编程语言采用。<a href="#cite-1"><sup>1</sup></a></p> + +<h2 id="JavaScript_Object_Oriented_Programming" name="JavaScript_Object_Oriented_Programming">JavaScript面向对象编程</h2> + +<h3 id="命名空间">命名空间</h3> + +<p>命名空间是一个容器,它允许开发人员在一个独特的,特定于应用程序的名称下捆绑所有的功能。 <strong>在JavaScript中,命名空间只是另一个包含方法,属性,对象的对象。</strong></p> + +<div class="note"> +<p><span style="font-size: 14px; line-height: 1.5;"><strong>注意:</strong>需要认识到重要的一点是:与其他面向对象编程语言不同的是,Javascript中的普通对象和命名空间在语言层面上没有区别。这点可能会让JavaScript初学者感到迷惑。</span></p> +</div> + +<p>创造的JavaScript命名空间背后的想法很简单:一个全局对象被创建,所有的变量,方法和功能成为该对象的属性。使用命名空间也最大程度地减少应用程序的名称冲突的可能性。</p> + +<p>我们来创建一个全局变量叫做 MYAPP</p> + +<pre class="brush: js">// 全局命名空间 +var MYAPP = MYAPP || {};</pre> + +<p>在上面的代码示例中,我们首先检查MYAPP是否已经被定义(是否在同一文件中或在另一文件)。如果是的话,那么使用现有的MYAPP全局对象,否则,创建一个名为MYAPP的空对象用来封装方法,函数,变量和对象。</p> + +<p>我们也可以创建子命名空间:</p> + +<pre class="brush: js">// 子命名空间 +MYAPP.event = {};</pre> + +<p>下面是用于创建命名空间和添加变量,函数和方法的代码写法:</p> + +<pre class="brush: js">// 给普通方法和属性创建一个叫做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) { + // 代码 + } + + // 还可以添加其他的属性和方法 +} + +//使用addListener方法的写法: +MYAPP.event.addListener("yourel", "type", callback);</pre> + +<h3 id="Core_Objects" name="Core_Objects">标准内置对象</h3> + +<p>JavaScript有包括在其核心的几个对象,例如,Math,Object,Array和String对象。下面的例子演示了如何使用Math对象的random()方法来获得一个随机数。</p> + +<pre class="brush: js">console.log(Math.random()); +</pre> + +<div class="note"><strong>注意:</strong>这里和接下来的例子都假设名为 <code>console.log</code> 的方法全局有定义。<code>console.log</code> 实际上不是 JavaScript 自带的。</div> + +<p>查看 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects" title="en-US/docs/Web/JavaScript/Reference/Global_Objects">JavaScript 参考:全局对象</a> 了解 JavaScript 内置对象的列表。</p> + +<p>JavaScript 中的每个对象都是 <code>Object</code> 对象的实例且继承它所有的属性和方法。</p> + +<h3 id="Custom_Objects" name="Custom_Objects">自定义对象</h3> + +<h4 id="The_Class" name="The_Class">类</h4> + +<p>JavaScript是一种基于原型的语言,它没类的声明语句,比如C+ +或Java中用的。这有时会对习惯使用有类申明语句语言的程序员产生困扰。相反,JavaScript可用方法作类。定义一个类跟定义一个函数一样简单。在下面的例子中,我们定义了一个新类Person。</p> + +<pre class="brush: js">function Person() { } +// 或 +var Person = function(){ } +</pre> + +<h4 id="The_Object_.28Class_Instance.29" name="The_Object_.28Class_Instance.29">对象(类的实例)</h4> + +<p>我们使用 <code>new <em>obj </em></code><span style="font-size: 14.3999996185303px; line-height: 16.7999992370605px;">创建对象 </span><em><code>obj</code></em><span style="font-size: 14.3999996185303px; line-height: 16.7999992370605px;"> 的新实例</span><span style="font-size: 14px; line-height: 1.5;">, 将结果(</span><em><code>obj 类型</code></em><span style="font-size: 14px; line-height: 1.5;">)</span><span style="font-size: 14px; line-height: 1.5;">赋值给一个变量方便稍后调用。</span></p> + +<p>在下面的示例中,我们定义了一个名为<code>Person</code>的类,然后我们创建了两个<code>Person</code>的实例(<code>person1</code> and <code>person2</code>).</p> + +<pre class="brush: js">function Person() { } +var person1 = new Person(); +var person2 = new Person(); +</pre> + +<div class="note"><strong>注意:</strong>有一种新增的创建未初始化实例的实例化方法,请参考 <a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create" title="Object.create">Object.create</a> 。</div> + +<h4 id="The_Constructor" name="The_Constructor">构造器</h4> + +<p>在实例化时构造器被调用 (也就是对象实例被创建时)。构造器是对象中的一个方法。 在JavaScript中函数就可以作为构造器使用,因此不需要特别地定义一个构造器方法,每个声明的函数都可以在实例化后被调用执行。</p> + +<p>构造器常用于给对象的属性赋值或者为调用函数做准备。 在本文的后面描述了类中方法既可以在定义时添加,也可以在使用前添加。</p> + +<p>在下面的示例中, <code>Person类实例化时构造器调用一个</code> alert函数。</p> + +<pre class="brush: js">function Person() { + alert('Person instantiated'); +} + +var person1 = new Person(); +var person2 = new Person(); +</pre> + +<h4 id="The_Property_.28object_attribute.29" name="The_Property_.28object_attribute.29">属性 (对象属性)</h4> + +<p>属性就是 类中包含的变量;每一个对象实例有若干个属性. 为了正确的继承,属性应该被定义在类的原型属性 (函数)中。</p> + +<p>可以使用 关键字 <code>this</code>调用类中的属性, this是对当前对象的引用。 从外部存取(读/写)其属性的语法是: <code>InstanceName.Property</code>; 这与C++,Java或者许多其他语言中的语法是一样的 (在类中语法 <code>this.Property</code> 常用于set和get属性值)</p> + +<p>在下面的示例中,我们为定义<code>Person类定义了一个属性</code> <code>firstName</code> 并在实例化时赋初值。</p> + +<pre class="brush: js">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" +</pre> + +<h4 id="The_methods" name="The_methods">方法(对象属性)</h4> + +<p>方法与属性很相似, 不同的是:一个是函数,另一个可以被定义为函数。 调用方法很像存取一个属性, 不同的是add <code>()</code> 在方法名后面很可能带着参数. 为定义一个方法, 需要将一个函数赋值给类的 <code>prototype</code> 属性; 这个赋值给函数的名称就是用来给对象在外部调用它使用的。</p> + +<p>在下面的示例中,我们给<code>Person类</code>定义了方法 <code>sayHello()</code>,并调用了它.</p> + +<pre class="brush: js">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" +</pre> + +<p>在JavaScript中方法通常是一个绑定到对象中的普通函数, 这意味着方法可以在其所在context之外被调用。 思考下面示例中的代码:</p> + +<pre class="brush: js">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) +console.log(helloFunction === person1.sayHello); // logs true +console.log(helloFunction === Person.prototype.sayHello); // logs true +helloFunction.call(person1); // logs "Hello, I'm Alice" +</pre> + +<p>如上例所示, 所有指向<code>sayHello函数的引用</code> ,包括 <code>person1</code>, <code>Person.prototype</code>, 和 <code>helloFunction</code> 等, 均引用了<em>相同的函数</em>.</p> + +<p>在调用函数的过程中,<span style="font-family: consolas,monaco,andale mono,monospace; line-height: 1.5;">this的值</span><span style="line-height: 1.5;">取决于我们怎么样调用函数. </span><span style="line-height: 1.5;"> 在通常情况下,我们通过一个表达式</span><span style="font-family: consolas,monaco,andale mono,monospace; line-height: 1.5;">person1.sayHello()</span><span style="line-height: 1.5;">来调用函数:即从一个对象的属性中得到所调用的函数</span><span style="line-height: 1.5;">。此时this被设置为我们取得函数的对象(即</span><span style="font-family: consolas,monaco,andale mono,monospace; line-height: 1.5;">person1</span><span style="line-height: 1.5;">)。这就是为什么</span><code style="font-style: normal; line-height: 1.5;">person1.sayHello()</code><span style="line-height: 1.5;"> 使用了姓名“Alice”而</span><code style="font-style: normal; line-height: 1.5;">person2.sayHello()使用了姓名“bob”的原因。</code><span style="line-height: 1.5;"> </span></p> + +<p><span style="line-height: 1.5;">然而我们使用不同的调用方法时, </span><code style="font-style: normal; line-height: 1.5;">this的值也就不同了</code><span style="line-height: 1.5;">。当从变量 </span><code style="font-style: normal; line-height: 1.5;">helloFunction()中调用的时候,</code><span style="line-height: 1.5;"> </span><code style="font-style: normal; line-height: 1.5;">this</code><span style="line-height: 1.5;">就被设置成了全局对象 (在浏览器中即</span><code style="font-style: normal; line-height: 1.5;">window</code><span style="line-height: 1.5;">)。由于该对象 (非常可能地) 没有</span><code style="font-style: normal; line-height: 1.5;">firstName</code><span style="line-height: 1.5;"> 属性, 我们得到的结果便是"Hello, I'm undefined". (这是松散模式下的结果, 在 </span><a href="/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode">严格模式</a>中,结果将不同(此时会产生一个error)。<span style="line-height: 1.5;"> 但是为了避免混淆,我们在这里不涉及细节) 。另外,我们可以像上例末尾那样,使用</span><code style="font-style: normal; line-height: 1.5;">Function#call</code><span style="line-height: 1.5;"> (或者</span><code style="font-style: normal; line-height: 1.5;">Function#apply</code><span style="line-height: 1.5;">)</span><span style="line-height: 1.5;">显式的设置</span><span style="font-family: consolas,monaco,andale mono,monospace; line-height: 1.5;">this的值。</span></p> + +<div class="note">更多有关信息请参考 <a href="/zh-CN/JavaScript/Reference/Global_Objects/Function/call" title="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call">Function#call</a> and <a href="/zh-CN/JavaScript/Reference/Global_Objects/Function/apply" title="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply">Function#apply</a></div> + +<h4 id="Inheritance" name="Inheritance">继承</h4> + +<p>创建一个或多个类的专门版本类方式称为继承(Javascript只支持单继承)。 创建的专门版本的类通常叫做子类,另外的类通常叫做父类。 在<span style="line-height: 1.5;">Javascript中,继承通过赋予子类一个父类的实例并专门化子类来实现。在现代浏览器中你可以使用 </span><a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Object/create#Classical_inheritance_with_Object.create" style="line-height: 1.5;" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/create#Classical_inheritance_with_Object.create">Object.create</a><span style="line-height: 1.5;"> 实现继承.</span></p> + +<div class="note"> +<p>JavaScript 并不检测子类的 <code>prototype.constructor</code> (见 <a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Object/prototype">Object.prototype</a>), 所以我们必须手动申明它.</p> +</div> + +<p>在下面的例子中, 我们定义了 <code>Student类作为</code> <code>Person类的子类</code>. 之后我们重定义了<code>sayHello()</code> 方法并添加了 <code>sayGoodBye() 方法</code>.</p> + +<pre class="brush: js">// 定义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(){ + console.log("Hello, I'm " + this.firstName + ". I'm studying " + this.subject + "."); +}; + +// 加入"sayGoodBye" 方法 +Student.prototype.sayGoodBye = function(){ + console.log("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 +console.log(student1 instanceof Person); // true +console.log(student1 instanceof Student); // true +</pre> + +<p>对于“<span style="font-family: consolas,monaco,andale mono,monospace;">Student.prototype = Object.create(Person.prototype);</span>”这一行,在不支持 <code><a href="/en/JavaScript/Reference/Global_Objects/Object/create" title="Object.create">Object.create</a>方法的老JavaScript引擎中,可以使用一个</code>"polyfill"(又名"shim",查看文章链接),或者使用一个function来获得相同的返回值,就像下面:</p> + +<pre class="brush: js">function createObject(proto) { + function ctor() { } + ctor.prototype = proto; + return new ctor(); +} + +// Usage: +Student.prototype = createObject(Person.prototype); +</pre> + +<div class="note">更多相关信息请参考<em> </em><a href="/en/JavaScript/Reference/Global_Objects/Object/create" style="font-style: italic;" title="Object.create">Object.create</a>,连接中还有一个老JavaScript引擎的兼容方案(shim)。</div> + +<h4 id="Encapsulation" name="Encapsulation">封装</h4> + +<p>在上一个例子中,Student类虽然不需要知道Person类的walk()方法是如何实现的,但是仍然可以使用这个方法;Student类不需要明确地定义这个方法,除非我们想改变它。 这就叫做<strong>封装</strong>,对于所有继承自父类的方法,只需要在子类中定义那些你想改变的即可。</p> + +<h4 id="Abstraction" name="Abstraction">抽象</h4> + +<p>抽象是允许模拟工作问题中通用部分的一种机制。这可以通过继承(具体化)或组合来实现。<br> + JavaScript通过继承实现具体化,通过让类的实例是其他对象的属性值来实现组合。</p> + +<p>JavaScript Function 类继承自Object类(这是典型的具体化) 。Function.prototype的属性是一个Object实例(这是典型的组合)。</p> + +<pre class="brush: js">var foo = function(){}; +console.log( 'foo is a Function: ' + (foo instanceof Function) ); <span style="font-size: 1rem;">// logs "</span><span style="font-size: 1rem;">foo is a Function: true</span><span style="font-size: 1rem;">"</span> +console.log( 'foo.prototype is an Object: ' + (foo.prototype instanceof Object) ); // logs "<span style="font-size: 1rem;">foo.prototype is an Object: true</span><span style="font-size: 1rem;">"</span></pre> + +<h4 id="Polymorphism" name="Polymorphism">多态</h4> + +<p>就像所有定义在原型属性内部的方法和属性一样,不同的类可以定义具有相同名称的方法;方法是作用于所在的类中。并且这仅在两个类不是父子关系时成立(继承链中,一个类不是继承自其他类)。</p> + +<h2 id="Notes" name="Notes">注意</h2> + +<p>本文中所展示的面向对象编程技术不是唯一的实现方式,在JavaScript中面向对象的实现是非常灵活的。</p> + +<p>同样的,文中展示的技术没有使用任何语言hacks,它们也没有模仿其他语言的对象理论实现。</p> + +<p>JavaScript中还有其他一些更加先进的面向对象技术,但这些都超出了本文的介绍范围。</p> + +<h2 id="References" name="References">参考</h2> + +<ol> + <li><span style="line-height: 1.5;"><a name="cite-1"></a>维基百科。「</span>面向对象程序设计」,<a href="http://zh.wikipedia.org/wiki/面向对象程序设计">http://zh.wikipedia.org/wiki/面向对象程序设计</a></li> + <li>维基百科。“<a href="http://en.wikipedia.org/wiki/Encapsulation_%28object-oriented_programming%29">Encapsulation (object-oriented programming)</a>”</li> +</ol> |