mirror of
https://github.com/fofolee/uTools-Manuals.git
synced 2026-02-27 17:44:35 +08:00
语法高亮,滚动条美化,设置页面调整
This commit is contained in:
@@ -83,19 +83,19 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<pre class="brush: js">
|
||||
<pre><code class="language-javascript">
|
||||
function Employee () {
|
||||
this.name = "";
|
||||
this.dept = "general";
|
||||
}
|
||||
</pre>
|
||||
</code></pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre class="brush: java">
|
||||
<pre><code class="language-java">
|
||||
public class Employee {
|
||||
public String name = "";
|
||||
public String dept = "general";
|
||||
}</pre>
|
||||
}</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -111,7 +111,7 @@ public class Employee {
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<pre class="brush: js">
|
||||
<pre><code class="language-javascript">
|
||||
function Manager() {
|
||||
Employee.call(this);
|
||||
this.reports = [];
|
||||
@@ -122,10 +122,10 @@ function WorkerBee() {
|
||||
Employee.call(this);
|
||||
this.projects = [];
|
||||
}
|
||||
WorkerBee.prototype = Object.create(Employee.prototype);</pre>
|
||||
WorkerBee.prototype = Object.create(Employee.prototype);</code></pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre class="brush: java">
|
||||
<pre><code class="language-java">
|
||||
public class Manager extends Employee {
|
||||
public Employee[] reports = new Employee[0];
|
||||
}
|
||||
@@ -134,7 +134,7 @@ public class Manager extends Employee {
|
||||
|
||||
public class WorkerBee extends Employee {
|
||||
public String[] projects = new String[0];
|
||||
}</pre>
|
||||
}</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -150,7 +150,7 @@ public class WorkerBee extends Employee {
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<pre class="brush: js">
|
||||
<pre><code class="language-javascript">
|
||||
function SalesPerson() {
|
||||
WorkerBee.call(this);
|
||||
this.dept = 'sales';
|
||||
@@ -163,10 +163,10 @@ function Engineer() {
|
||||
this.dept = 'engineering';
|
||||
this.machine = '';
|
||||
}
|
||||
Engineer.prototype <code>= Object.create(WorkerBee.prototype);</code></pre>
|
||||
Engineer.prototype <code>= Object.create(WorkerBee.prototype);</code></code></pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre class="brush: java">
|
||||
<pre><code class="language-java">
|
||||
<code>public class SalesPerson extends WorkerBee {
|
||||
public String dept = "sales";
|
||||
public double quota = 100.0;
|
||||
@@ -176,7 +176,7 @@ Engineer.prototype <code>= Object.create(WorkerBee.prototype);</code></pre>
|
||||
public class Engineer extends WorkerBee {
|
||||
public String dept = "engineering";
|
||||
public String machine = "";
|
||||
}</code></pre>
|
||||
}</code></code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -190,7 +190,7 @@ public class Engineer extends WorkerBee {
|
||||
<p>使用右侧的代码创建以下层次结构。</p>
|
||||
<p><img src="https://mdn.mozillademos.org/files/10412/=figure8.3.png"/></p>
|
||||
<h4 id="个别对象">个别对象</h4>
|
||||
<pre class="brush: js">var jim = new Employee; // 如构造函数无须接受任何参数,圆括号可以省略。
|
||||
<pre><code class="language-javascript">var jim = new Employee; // 如构造函数无须接受任何参数,圆括号可以省略。
|
||||
// jim.name is ''
|
||||
// jim.dept is 'general'
|
||||
|
||||
@@ -214,32 +214,32 @@ var jane = new Engineer;
|
||||
// jane.name is ''
|
||||
// jane.dept is 'engineering'
|
||||
// jane.projects is []
|
||||
// jane.machine is ''</pre>
|
||||
// jane.machine is ''</code></pre>
|
||||
<h2 id="对象的属性">对象的属性</h2>
|
||||
<p>本节将讨论对象如何从原型链中的其它对象中继承属性,以及在运行时添加属性的相关细节。</p>
|
||||
<h3 id="继承属性">继承属性</h3>
|
||||
<p>假设您通过如下语句创建一个<code>mark</code>对象作为 <code>WorkerBee</code>的实例:</p>
|
||||
<pre class="brush: js">var mark = new WorkerBee;
|
||||
</pre>
|
||||
<pre><code class="language-javascript">var mark = new WorkerBee;
|
||||
</code></pre>
|
||||
<p>当 JavaScript 发现 <code>new</code> 操作符时,它会创建一个通用对象,并将其作为关键字 <code>this</code> 的值传递给 <code>WorkerBee</code> 的构造器函数。该构造器函数显式地设置 <code>projects</code> 属性的值,然后隐式地将其内部的 [[Prototype]] 属性设置为 <code>WorkerBee.prototype</code> 的值。内置的 [[Prototype]] 属性决定了用于返回属性值的原型链。一旦这些属性设置完成,JavaScript 返回新创建的对象,然后赋值语句会将变量 <code>mark</code> 的值指向该对象。</p>
|
||||
<p>这个过程不会显式的将 <code style="font-size: 14px;">mark</code>所继承的原型链中的属性值作为本地变量存放在 <code>mark</code> 对象中。当请求属性的值时,JavaScript 将首先检查对象自身中是否存在属性的值,如果有,则返回该值。如果不存在,JavaScript会检查原型链(使用内置的 [[Prototype]] 属性)。如果原型链中的某个对象包含该属性的值,则返回这个值。如果没有找到该属性,JavaScript 则认为对象中不存在该属性。这样,<code>mark</code> 对象中将具有如下的属性和对应的值:</p>
|
||||
<pre class="brush: js">mark.name = "";
|
||||
<pre><code class="language-javascript">mark.name = "";
|
||||
mark.dept = "general";
|
||||
mark.projects = [];
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p><code>mark</code> 对象从 <code>mark.__proto__</code> 中保存的原型对象中继承了 <code>name</code> 和 <code>dept</code> 属性的值。并由 <code>WorkerBee</code> 构造器函数为 <code>projects</code> 属性设置了本地值。 这就是 JavaScript 中的属性和属性值的继承。这个过程的一些微妙之处将在 <a href="#Property_inheritance_revisited">Property inheritance revisited</a> 中进一步讨论。</p>
|
||||
<p>由于这些构造器不支持为实例设置特定的值,所以这些属性值仅仅是创建自 <code>WorkerBee</code> 的所有对象所共享的默认值。当然这些属性的值是可以修改的,所以您可以为 <code>mark</code>指定特定的信息,如下所示:</p>
|
||||
<pre class="brush: js">mark.name = "Doe, Mark";
|
||||
<pre><code class="language-javascript">mark.name = "Doe, Mark";
|
||||
mark.dept = "admin";
|
||||
mark.projects = ["navigator"];</pre>
|
||||
mark.projects = ["navigator"];</code></pre>
|
||||
<h3 id="添加属性">添加属性</h3>
|
||||
<p>在 JavaScript 中,您可以在运行时为任何对象添加属性,而不必受限于构造器函数提供的属性。添加特定于某个对象的属性,只需要为该对象指定一个属性值,如下所示:</p>
|
||||
<pre class="brush: js">mark.bonus = 3000;
|
||||
</pre>
|
||||
<pre><code class="language-javascript">mark.bonus = 3000;
|
||||
</code></pre>
|
||||
<p>这样 <code>mark</code> 对象就有了 <code>bonus</code> 属性,而其它 <code>WorkerBee</code> 则没有该属性。</p>
|
||||
<p>如果您向某个构造器函数的原型对象中添加新的属性,那么该属性将添加到从这个原型中继承属性的所有对象的中。例如,可以通过如下的语句向所有雇员中添加 <code>specialty</code> 属性:</p>
|
||||
<pre class="brush: js">Employee.prototype.specialty = "none";
|
||||
</pre>
|
||||
<pre><code class="language-javascript">Employee.prototype.specialty = "none";
|
||||
</code></pre>
|
||||
<p>只要 JavaScript 执行了该语句,则 <code>mark</code> 对象也将具有 <code>specialty</code> 属性,其值为 <code>"none"</code>。下图则表示了在 <code>Employee</code> 原型中添加该属性,然后在 <code>Engineer</code> 的原型中重载该属性的效果。</p>
|
||||
<p><img alt="" class="internal" src="/@api/deki/files/4422/=figure8.4.png" style="height: 519px; width: 833px;"/><br/>
|
||||
<small><strong>添加属性</strong></small></p>
|
||||
@@ -258,15 +258,15 @@ mark.projects = ["navigator"];</pre>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<pre class="brush: js">
|
||||
<pre><code class="language-javascript">
|
||||
function Employee (name, dept) {
|
||||
this.name = name || "";
|
||||
this.dept = dept || "general";
|
||||
}
|
||||
</pre>
|
||||
</code></pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre class="brush: java">
|
||||
<pre><code class="language-java">
|
||||
public class Employee {
|
||||
public String name;
|
||||
public String dept;
|
||||
@@ -281,20 +281,20 @@ public class Employee {
|
||||
this.dept = dept;
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<pre class="brush: js">
|
||||
<pre><code class="language-javascript">
|
||||
function WorkerBee (projs) {
|
||||
this.projects = projs || [];
|
||||
}
|
||||
WorkerBee.prototype = new Employee;
|
||||
</pre>
|
||||
</code></pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre class="brush: java">
|
||||
<pre><code class="language-java">
|
||||
public class WorkerBee extends Employee {
|
||||
public String[] projects;
|
||||
public WorkerBee () {
|
||||
@@ -305,22 +305,22 @@ public class WorkerBee extends Employee {
|
||||
}
|
||||
}
|
||||
|
||||
</pre>
|
||||
</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<pre class="brush: js">
|
||||
<pre><code class="language-javascript">
|
||||
|
||||
function Engineer (mach) {
|
||||
this.dept = "engineering";
|
||||
this.machine = mach || "";
|
||||
}
|
||||
Engineer.prototype = new WorkerBee;
|
||||
</pre>
|
||||
</code></pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre class="brush: java">
|
||||
<pre><code class="language-java">
|
||||
public class Engineer extends WorkerBee {
|
||||
public String machine;
|
||||
public Engineer () {
|
||||
@@ -332,41 +332,41 @@ public class Engineer extends WorkerBee {
|
||||
machine = mach;
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>上面使用 JavaScript 定义过程使用了一种设置默认值的特殊惯用法:</p>
|
||||
<pre class="brush: js">this.name = name || "";
|
||||
</pre>
|
||||
<pre><code class="language-javascript">this.name = name || "";
|
||||
</code></pre>
|
||||
<p>JavaScript 的逻辑或操作符(<code>||</code>)会对第一个参数进行判断。如果该参数值运算后结果为真,则操作符返回该值。否则,操作符返回第二个参数的值。因此,这行代码首先检查 <code>name</code> 是否是对<code>name</code> 属性有效的值。如果是,则设置其为 <code>this.name</code> 的值。否则,设置 <code>this.name</code> 的值为空的字符串。尽管这种用法乍看起来有些费解,为了简洁起见,本章将使用这种习惯用法。</p>
|
||||
<div class="note">
|
||||
<p><strong>提示:</strong>如果调用构造器函数时,指定了可以转换为 <code><code>false</code></code> 的参数(比如<code>0</code>和空字符串),结果可能出乎调用者意料。此时,将使用默认值(译注:不是指定的参数值 0 和 "")。</p>
|
||||
</div>
|
||||
<p>使用这些定义,当创建对象的实例时,可以为本地定义的属性指定值。你可以使用以下语句创建一个新的<code>Engineer</code>:</p>
|
||||
<pre class="brush: js">var jane = new Engineer("belau");
|
||||
</pre>
|
||||
<pre><code class="language-javascript">var jane = new Engineer("belau");
|
||||
</code></pre>
|
||||
<p>此时,<code>Jane</code> 的属性如下所示:</p>
|
||||
<pre class="brush: js">jane.name == "";
|
||||
<pre><code class="language-javascript">jane.name == "";
|
||||
jane.dept == "engineering";
|
||||
jane.projects == [];
|
||||
jane.machine == "belau"
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p>注意,由上面对类的定义,您无法为诸如 <code>name</code> 这样的继承属性指定初始值。如果想在 JavaScript 中为继承的属性指定初始值,您需要在构造器函数中添加更多的代码。</p>
|
||||
<p>到目前为止,构造器函数已经能够创建一个普通对象,然后为新对象指定本地的属性和属性值。您还可以通过直接调用原型链上的更高层次对象的构造器函数,让构造器添加更多的属性。下图即实现了这一功能。</p>
|
||||
<p><img alt="" class="internal" src="/@api/deki/files/4430/=figure8.6.png" style="height: 534px; width: 1063px;"/><br/>
|
||||
<small><strong>Specifying properties in a constructor, take 2</strong></small></p>
|
||||
<p>我们来详细看一下这些定义。这是<code>Engineer</code>构造函数的新定义:</p>
|
||||
<pre class="brush: js">function Engineer (name, projs, mach) {
|
||||
<pre><code class="language-javascript">function Engineer (name, projs, mach) {
|
||||
this.base = WorkerBee;
|
||||
this.base(name, "engineering", projs);
|
||||
this.machine = mach || "";
|
||||
}
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p>假设您创建了一个新的 <code>Engineer</code> 对象,如下所示:</p>
|
||||
<pre class="brush: js">var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
|
||||
</pre>
|
||||
<pre><code class="language-javascript">var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
|
||||
</code></pre>
|
||||
<p>JavaScript 会按以下步骤执行:</p>
|
||||
<ol>
|
||||
<li><code>new</code> 操作符创建了一个新的通用对象,并将其 <code>__proto__</code> 属性设置为 <code>Engineer.prototype</code>。</li>
|
||||
@@ -382,16 +382,16 @@ jane.machine == "belau"
|
||||
<li>当从构造器返回时,JavaScript 将新对象赋值给 <code>jane</code> 变量。</li>
|
||||
</ol>
|
||||
<p>你可以认为,在 <code>Engineer</code> 的构造器中调用了 <code>WorkerBee</code> 的构造器,也就为 <code>Engineer</code> 对象设置好了继承关系。事实并非如此。调用 <code>WorkerBee</code> 构造器确保了<code>Engineer</code> 对象以所有在构造器中所指定的属性被调用。但是,如果后续在 <code>Employee</code> 或者 <code>WorkerBee</code> 原型中添加了属性,那些属性不会被 <code>Engineer</code> 对象继承。例如,假设如下语句:</p>
|
||||
<pre class="brush: js">function Engineer (name, projs, mach) {
|
||||
<pre><code class="language-javascript">function Engineer (name, projs, mach) {
|
||||
this.base = WorkerBee;
|
||||
this.base(name, "engineering", projs);
|
||||
this.machine = mach || "";
|
||||
}
|
||||
var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
|
||||
Employee.prototype.specialty = "none";
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p>对象 <code>jane</code> 不会继承 <code>specialty</code> 属性。您必须显式地设置原型才能确保动态的继承。如果修改成如下的语句:</p>
|
||||
<pre class="brush: js">function Engineer (name, projs, mach) {
|
||||
<pre><code class="language-javascript">function Engineer (name, projs, mach) {
|
||||
this.base = WorkerBee;
|
||||
this.base(name, "engineering", projs);
|
||||
this.machine = mach || "";
|
||||
@@ -399,28 +399,28 @@ Employee.prototype.specialty = "none";
|
||||
Engineer.prototype = new WorkerBee;
|
||||
var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
|
||||
Employee.prototype.specialty = "none";
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p>现在 <code>jane</code> 对象的 <code>specialty</code> 属性为 "none" 了。</p>
|
||||
<p>继承的另一种途径是使用<a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function/call" title="en-US/docs/JavaScript/Reference/Global Objects/Function/call"><code>call()</code></a> / <a href="/zh-CN/docs/JavaScript/Reference/Global_Objects/Function/apply" title="en-US/docs/JavaScript/Reference/Global Objects/Function/apply"><code>apply()</code></a> 方法。下面的方式都是等价的:</p>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<pre class="brush: js">
|
||||
<pre><code class="language-javascript">
|
||||
function Engineer (name, projs, mach) {
|
||||
this.base = WorkerBee;
|
||||
this.base(name, "engineering", projs);
|
||||
this.machine = mach || "";
|
||||
}
|
||||
</pre>
|
||||
</code></pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre class="brush: js">
|
||||
<pre><code class="language-javascript">
|
||||
function Engineer (name, projs, mach) {
|
||||
WorkerBee.call(this, name, "engineering", projs);
|
||||
this.machine = mach || "";
|
||||
}
|
||||
</pre>
|
||||
</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -437,7 +437,7 @@ function Engineer (name, projs, mach) {
|
||||
<li>如果这样的属性不存在,则对象没有该属性。</li>
|
||||
</ol>
|
||||
<p>以上步骤的结果依赖于你是如何定义的。最早的例子中有如下定义:</p>
|
||||
<pre class="brush: js">function Employee () {
|
||||
<pre><code class="language-javascript">function Employee () {
|
||||
this.name = "";
|
||||
this.dept = "general";
|
||||
}
|
||||
@@ -446,22 +446,22 @@ function WorkerBee () {
|
||||
this.projects = [];
|
||||
}
|
||||
WorkerBee.prototype = new Employee;
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p>基于这些定义,假定通过如下的语句创建 <code>WorkerBee</code> 的实例 <code>amy</code>:</p>
|
||||
<pre class="brush: js">var amy = new WorkerBee;
|
||||
</pre>
|
||||
<pre><code class="language-javascript">var amy = new WorkerBee;
|
||||
</code></pre>
|
||||
<p>则 <code>amy</code> 对象将具有一个本地属性 <code>projects</code>。<code>name</code>和 <code>dept</code> 则不是 <code>amy</code> 对象的本地属性,而是从 <code>amy</code> 对象的 <code>__proto__</code> 属性获得的。因此,<code>amy</code> 将具有如下的属性值:</p>
|
||||
<pre class="brush: js">amy.name == "";
|
||||
<pre><code class="language-javascript">amy.name == "";
|
||||
amy.dept == "general";
|
||||
amy.projects == [];
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p>现在,假设修改了与 <code>Employee</code> 的相关联原型中的 <code>name</code> 属性的值:</p>
|
||||
<pre class="brush: js">Employee.prototype.name = "Unknown"
|
||||
</pre>
|
||||
<pre><code class="language-javascript">Employee.prototype.name = "Unknown"
|
||||
</code></pre>
|
||||
<p>乍一看,你可能觉得新的值会传播给所有 <code>Employee</code> 的实例。然而,并非如此。</p>
|
||||
<p>在创建 <code>Employee</code> 对象的<em>任意</em>实例时,该实例的 <code>name</code> 属性将获得一个<strong>本地值</strong>(空的字符串)。这就意味着在创建一个新的 <code>Employee</code> 对象作为 <code>WorkerBee</code> 的原型时,<code>WorkerBee.prototype</code> 的 <code>name</code> 属性将具有一个本地值。因此,当 JavaScript 查找 <code>amy</code> 对象(<code>WorkerBee</code> 的实例)的 <code>name</code> 属性时,JavaScript 将找到 <code>WorkerBee.prototype</code> 中的本地值。因此,也就不会继续在原型链中向上找到 <code>Employee.prototype</code> 了。</p>
|
||||
<p>如果想在运行时修改一个对象的属性值并且希望该值被所有该对象的后代所继承,您就不能在该对象的构造器函数中定义该属性。而应该将该属性添加到该对象所关联的原型中。例如,假设将前面的代码作如下修改:</p>
|
||||
<pre class="brush: js">function Employee () {
|
||||
<pre><code class="language-javascript">function Employee () {
|
||||
this.dept = "general";
|
||||
}
|
||||
Employee.prototype.name = "";
|
||||
@@ -474,27 +474,27 @@ WorkerBee.prototype = new Employee;
|
||||
var amy = new WorkerBee;
|
||||
|
||||
Employee.prototype.name = "Unknown";
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p>在这种情况下,<code>amy</code> 的 <code>name</code> 属性将为 "Unknown"。</p>
|
||||
<p>正如这些例子所示,如果希望对象的属性具有默认值,并且希望在运行时修改这些默认值,应该在对象的原型中设置这些属性,而不是在构造器函数中。</p>
|
||||
<h3 id="判断实例的关系">判断实例的关系</h3>
|
||||
<p>JavaScript 的属性查找机制首先在对象自身的属性中查找,如果指定的属性名称没有找到,将在对象的特殊属性 <code>__proto__</code> 中查找。这个过程是递归的;被称为“在原型链中查找”。</p>
|
||||
<p>特殊的 <code>__proto__</code> 属性是在构建对象时设置的;设置为构造器的 <code>prototype</code> 属性的值。所以表达式 <code>new Foo()</code> 将创建一个对象,其 <code>__proto__ == <code class="moz-txt-verticalline">Foo.prototype</code></code>。因而,修改 <code class="moz-txt-verticalline">Foo.prototype</code> 的属性,将改变所有通过 <code>new Foo()</code> 创建的对象的属性的查找。</p>
|
||||
<p>每个对象都有一个 <code>__proto__</code> 对象属性(除了 <code>Object);每个函数都有一个</code> <code>prototype</code> 对象属性。因此,通过“原型继承”,对象与其它对象之间形成关系。通过比较对象的 <code>__proto__</code> 属性和函数的 <code>prototype</code> 属性可以检测对象的继承关系。JavaScript 提供了便捷方法:<code>instanceof</code> 操作符可以用来将一个对象和一个函数做检测,如果对象继承自函数的原型,则该操作符返回真。例如:</p>
|
||||
<pre class="brush: js">var f = new Foo();
|
||||
var isTrue = (f instanceof Foo);</pre>
|
||||
<pre><code class="language-javascript">var f = new Foo();
|
||||
var isTrue = (f instanceof Foo);</code></pre>
|
||||
<p>作为详细一点的例子,假定我们使用和在 <a href="#Inheriting_properties">Inheriting properties</a> 中相同的一组定义。创建 <code>Engineer</code> 对象如下:</p>
|
||||
<pre class="brush: js">var chris = new Engineer("Pigman, Chris", ["jsd"], "fiji");
|
||||
</pre>
|
||||
<pre><code class="language-javascript">var chris = new Engineer("Pigman, Chris", ["jsd"], "fiji");
|
||||
</code></pre>
|
||||
<p>对于该对象,以下所有语句均为真:</p>
|
||||
<pre class="brush: js">chris.__proto__ == Engineer.prototype;
|
||||
<pre><code class="language-javascript">chris.__proto__ == Engineer.prototype;
|
||||
chris.__proto__.__proto__ == WorkerBee.prototype;
|
||||
chris.__proto__.__proto__.__proto__ == Employee.prototype;
|
||||
chris.__proto__.__proto__.__proto__.__proto__ == Object.prototype;
|
||||
chris.__proto__.__proto__.__proto__.__proto__.__proto__ == null;
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p>基于此,可以写出一个如下所示的 <code>instanceOf</code> 函数:</p>
|
||||
<pre class="brush: js">function instanceOf(object, constructor) {
|
||||
<pre><code class="language-javascript">function instanceOf(object, constructor) {
|
||||
while (object != null) {
|
||||
if (object == constructor.prototype)
|
||||
return true;
|
||||
@@ -505,33 +505,33 @@ chris.__proto__.__proto__.__proto__.__proto__.__proto__ == null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
</pre>
|
||||
</code></pre>
|
||||
<div class="note"><strong>Note:</strong> 在上面的实现中,检查对象的类型是否为 "xml" 的目的在于解决新近版本的 JavaScript 中表达 XML 对象的特异之处。如果您想了解其中琐碎细节,可以参考 <a class="external" href="https://bugzilla.mozilla.org/show_bug.cgi?id=634150" rel="noopener" title="Infinite loop with increasing memory involving E4X and object.__proto__">bug 634150</a>。</div>
|
||||
<div>使用上面定义的 instanceOf 函数,这些表达式为真:</div>
|
||||
<div> </div>
|
||||
<pre class="brush: js">instanceOf (chris, Engineer)
|
||||
<pre><code class="language-javascript">instanceOf (chris, Engineer)
|
||||
instanceOf (chris, WorkerBee)
|
||||
instanceOf (chris, Employee)
|
||||
instanceOf (chris, Object)
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p>但如下表达式为假:</p>
|
||||
<pre class="brush: js">instanceOf (chris, SalesPerson)</pre>
|
||||
<pre><code class="language-javascript">instanceOf (chris, SalesPerson)</code></pre>
|
||||
<h3 id="构造器中的全局信息">构造器中的全局信息</h3>
|
||||
<p>在创建构造器时,在构造器中设置全局信息要小心。例如,假设希望为每一个雇员分配一个唯一标识。可能会为 <code>Employee</code> 使用如下定义:</p>
|
||||
<pre class="brush: js">var idCounter = 1;
|
||||
<pre><code class="language-javascript">var idCounter = 1;
|
||||
|
||||
function Employee (name, dept) {
|
||||
this.name = name || "";
|
||||
this.dept = dept || "general";
|
||||
this.id = idCounter++;
|
||||
}
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p>基于该定义,在创建新的 <code>Employee</code> 时,构造器为其分配了序列中的下一个标识符。然后递增全局的标识符计数器。因此,如果,如果随后的语句如下,则 <code>victoria.id</code> 为 1 而 <code>harry.id</code> 为 2:</p>
|
||||
<pre class="brush: js">var victoria = new Employee("Pigbert, Victoria", "pubs")
|
||||
<pre><code class="language-javascript">var victoria = new Employee("Pigbert, Victoria", "pubs")
|
||||
var harry = new Employee("Tschopik, Harry", "sales")
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p>乍一看似乎没问题。但是,无论什么目的,在每一次创建 <code>Employee</code> 对象时,<code>idCounter</code> 都将被递增一次。如果创建本章中所描述的整个 <code>Employee</code> 层级结构,每次设置原型的时候,<code>Employee</code> 构造器都将被调用一次。假设有如下代码:</p>
|
||||
<pre class="brush: js">var idCounter = 1;
|
||||
<pre><code class="language-javascript">var idCounter = 1;
|
||||
|
||||
function Employee (name, dept) {
|
||||
this.name = name || "";
|
||||
@@ -552,25 +552,25 @@ function SalesPerson (name, projs, quota) {...}
|
||||
SalesPerson.prototype = new WorkerBee;
|
||||
|
||||
var mac = new Engineer("Wood, Mac");
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p>还可以进一步假设上面省略掉的定义中包含 <code>base</code> 属性而且调用了原型链中高于它们的构造器。即便在现在这个情况下,在 <code>mac</code> 对象创建时,<code>mac.id</code> 为 5。</p>
|
||||
<p>依赖于应用程序,计数器额外的递增可能有问题,也可能没问题。如果确实需要准确的计数器,则以下构造器可以作为一个可行的方案:</p>
|
||||
<pre class="brush: js">function Employee (name, dept) {
|
||||
<pre><code class="language-javascript">function Employee (name, dept) {
|
||||
this.name = name || "";
|
||||
this.dept = dept || "general";
|
||||
if (name)
|
||||
this.id = idCounter++;
|
||||
}
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p>在用作原型而创建新的 <code>Employee</code> 实例时,不会指定参数。使用这个构造器定义,如果不指定参数,构造器不会指定标识符,也不会递增计数器。而如果想让 <code>Employee</code> 分配到标识符,则必需为雇员指定姓名。在这个例子中,<code>mac.id</code> 将为 1。</p>
|
||||
<p>或者,您可以创建一个 Employee 的原型对象的副本以分配给 WorkerBee:</p>
|
||||
<pre class="brush: js">WorkerBee.prototype = Object.create(Employee.prototype);
|
||||
// instead of WorkerBee.prototype = new Employee</pre>
|
||||
<pre><code class="language-javascript">WorkerBee.prototype = Object.create(Employee.prototype);
|
||||
// instead of WorkerBee.prototype = new Employee</code></pre>
|
||||
<h3 id="没有多重继承">没有多重继承</h3>
|
||||
<p>某些面向对象语言支持多重继承。也就是说,对象可以从无关的多个父对象中继承属性和属性值。JavaScript 不支持多重继承。</p>
|
||||
<p>JavaScript 属性值的继承是在运行时通过检索对象的原型链来实现的。因为对象只有一个原型与之关联,所以 JavaScript 无法动态地从多个原型链中继承。</p>
|
||||
<p>在 JavaScript 中,可以在构造器函数中调用多个其它的构造器函数。这一点造成了多重继承的假象。例如,考虑如下语句:</p>
|
||||
<pre class="brush: js">function Hobbyist (hobby) {
|
||||
<pre><code class="language-javascript">function Hobbyist (hobby) {
|
||||
this.hobby = hobby || "scuba";
|
||||
}
|
||||
|
||||
@@ -584,17 +584,17 @@ function Engineer (name, projs, mach, hobby) {
|
||||
Engineer.prototype = new WorkerBee;
|
||||
|
||||
var dennis = new Engineer("Doe, Dennis", ["collabra"], "hugo")
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p>进一步假设使用本章前面所属的 <code>WorkerBee</code> 的定义。此时 <code>dennis</code> 对象具有如下属性:</p>
|
||||
<pre class="brush: js">dennis.name == "Doe, Dennis"
|
||||
<pre><code class="language-javascript">dennis.name == "Doe, Dennis"
|
||||
dennis.dept == "engineering"
|
||||
dennis.projects == ["collabra"]
|
||||
dennis.machine == "hugo"
|
||||
dennis.hobby == "scuba"
|
||||
</pre>
|
||||
</code></pre>
|
||||
<p><code>dennis</code> 确实从 <code>Hobbyist</code> 构造器中获得了 <code>hobby</code> 属性。但是,假设添加了一个属性到 <code>Hobbyist</code> 构造器的原型:</p>
|
||||
<pre class="brush: js">Hobbyist.prototype.equipment = ["mask", "fins", "regulator", "bcd"]
|
||||
</pre>
|
||||
<pre><code class="language-javascript">Hobbyist.prototype.equipment = ["mask", "fins", "regulator", "bcd"]
|
||||
</code></pre>
|
||||
<p><code>dennis</code> 对象不会继承这个新属性。</p>
|
||||
<div><div class="prevnext" style="text-align: right;">
|
||||
<p><a href="/zh-CN/docs/JavaScript/Guide/Predefined_Core_Objects" style="float: left;">« 上一页</a><a href="/zh-CN/docs/JavaScript/Guide/Inheritance_Revisited">下一页 »</a></p>
|
||||
|
||||
Reference in New Issue
Block a user