JavaScript 10分钟入门

Standard

以下为译文,原文地址:http://www.codeproject.com/Articles/1006192/JavaScript-Summary


简介

JavaScript是一门面向对象的动态语言,他一般用来处理以下任务:

  1. 修饰网页
    • 生成HTML和CSS
    • 生成动态HTML内容
    • 生成一些特效
  2. 提供用户交互接口
    • 生成用户交互组件
    • 验证用户输入
    • 自动填充表单
  3. 能够读取本地或者远程数据的前端应用程序,例如http://web-engineering.info/JsFrontendApp-Book
  4. 通过Nodejs实现像JAVA,C#,C++一样的服务端程序
  5. 实现分布式WEB程序,包括前端和服务端

当前浏览器所支持的JavaScript的版本被称为“ECMAScript的5.1”,或简单的“ES5”,但接下来的两个版本,称为“ES6”和“ES7”(或“ES2015”和“ES2016”,新版以本年命名),有很多的附加功能和改进的语法,是非常值得期待的(并已部分被当前的浏览器和后端JS的环境支持)。

此篇博文,引自《Building Front-End Web Apps with Plain JavaScript》一书。

JavaScript类型和常量

JS有3个值类型:string,number和boolean,我们可以用一个变量v保存不同类型的值用来和typeof(v)比较, typeof(v)===”number”。

JS有5个引用类型:Object, Array, Function, Date 和 RegExp。数组,函数,日期和正则表达式是特殊类型的对象,但在概念上,日期和正则表达式是值类型,被包装成对象形式体现。

变量,数组,函数的参数和返回值都可以不声明,它们通常不会被JavaScript引擎检查,会被自动进行类型转换。

变量值可能为:

  1. 数据,如string,number,boolean
  2. 对象的引用:如普通对象,数组,函数,日期,正则表达式
  3. 特殊值null,其通常用作用于初始化的对象变量的默认值
  4. 特殊值undefined,已经声明但没有初始化的初始值

string是Unicode字符序列。字符串常量会被单引号或双引号包裹着,如“Hello world!”,“A3F0’,或者空字符串””。两个字符串表达式可以用+操作符连接,并可通过全等于比较:

<code class="hljs lisp"> if (<span class="hljs-name">firstName</span> + lastName === <span class="hljs-string">"James Bond"</span>) </code>

字符串的字符数量可以通过length属性获得:

<code class="hljs cpp">console.<span class="hljs-built_in">log</span>( <span class="hljs-string">"Hello world!"</span>.length);  <span class="hljs-comment">// 12</span></code>

所有的数字值都是在64位浮点数字。整数和浮点数之间没有明确的类型区别。如果一个数字常量不是数字,可以将其值设置为NaN(“not a number”),它可以用isNaN方法来判断。

不幸的是,直到ES6才有Number.isInteger方法,用于测试一个数是不是一个整数。因此在还不支持它的浏览器中,为确保一个数字值是一个整数,或者一个数字的字符串被转换为一个整数,就必须使用parseInt函数。类似地,包含小数的字符串可用与parseFloat方法转换。将一个数子n转换成字符串,最好的方法是使用String(n)。

就像Java,我们也有两个预先定义好的布尔型值,true与false,以及布尔运算符符号: ! (非),&&(与),||(或)。当非布尔型值与布尔型值比较时,非布尔型值会被隐式转换。空字符串,数字0,以及undefined和null,会被转换为false,其他所有值会转换为true。

通常我们需要使用全等符号符号(===和!==)而不是==和!=。否则,数字2是等于的字符串“2”的, (2 == “2”) is true

VAR= [] 和var a = new Array() 都可以定义一个空数组。(二胡:推荐前者)

VAR O ={} 和 var o = new Obejct() 都可以定义个空对象(二胡:还是推荐前者)。注意,一个空对象{}不是真的空的,因为它包含的Object.prototype继承属性。所以,一个真正的空对象必须以Null为原型, var o = Object.create(null)。

表1 类型测试和转换

变量作用域

在JavaScript的当前版本ES5,有两种范围变量:全局作用域和函数作用域,没有块作用域。因此,应该避免声明在块内声明变量。

<code class="hljs matlab"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">foo</span><span class="hljs-params">()</span> {</span>
  <span class="hljs-keyword">for</span> (var <span class="hljs-built_in">i</span>=<span class="hljs-number">0</span>; <span class="hljs-built_in">i</span> &lt; <span class="hljs-number">10</span>; <span class="hljs-built_in">i</span>++) {
    ...  // do something with i
  }
}</code>

我们应该这样写

<code class="hljs matlab"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">foo</span><span class="hljs-params">()</span> {</span>
  var <span class="hljs-built_in">i</span>=<span class="hljs-number">0</span>;
  <span class="hljs-keyword">for</span> (<span class="hljs-built_in">i</span>=<span class="hljs-number">0</span>; <span class="hljs-built_in">i</span> &lt; <span class="hljs-number">10</span>; <span class="hljs-built_in">i</span>++) {
    ...  // do something with i
  }
}</code>

所有变量应在函数的开始声明。只有在JavaScript的下一个版本ES6中,我们可以用let关键词声明一个块级变量。

严格模式

从ES5开始,我们可以使用严格模式,获得更多的运行时错误检查。例如,在严格模式下,所有变量都必须进行声明。给未声明的变量赋值抛出异常。

我们可以通过键入下面的语句作为一个JavaScript文件或script元素中的第一行开启严格模式:’use strict’;

通常建议您使用严格模式,除非你的代码依赖于与严格的模式不兼容的库。

不同类型的对象

JS对象与传统的OO/UML对象不同。它们可以不通过类实例化而来。它们有属性、方法、键值对三种扩展。

JS对象可以直接通过JSON产生,而不用实例化一个类。

<code class="hljs javascript"><span class="hljs-keyword">var</span> person1 = { lastName:<span class="hljs-string">"Smith"</span>, firstName:<span class="hljs-string">"Tom"</span>};
<span class="hljs-keyword">var</span> o1 = <span class="hljs-built_in">Object</span>.create( <span class="hljs-literal">null</span>);  <span class="hljs-comment">// an empty object with no slots</span></code>

对象属性可以以两种方式获得:

  1. 使用点符号(如在C ++/ Java的):

    person1.lastName = “Smith”

  2. 使用MAP方式

    person1[“lastName”] = “Smith”

JS对象有不同的使用方式。这里有五个例子:

  1. 记录,例如,

    var myRecord = {firstName:”Tom”, lastName:”Smith”, age:26}

  2. MAP(也称为“关联数组”,“词典”或其他语言的“哈希表”)

    var numeral2number = {“one”:”1″, “two”:”2″, “three”:”3″}

  3. 非类型化对象

    var person1 = { lastName: "Smith", firstName: "Tom", getFullName: function () { return this.firstName +" "+ this.lastName; } };

  4. 命名空间

    var myApp = { model:{}, view:{}, ctrl:{} };

可以由一个全局变量形式来定义,它的名称代表一个命名空间前缀。例如,上面的对象变量提供了基于模型 – 视图 – 控制器(MVC)架构模式,我们有相应的MVC应用程序的三个部分。

  1. 正常的类

数组

可以用一个JavaScript数组文本进行初始化变量:
var a = [1,2,3];

因为它们是数组列表,JS数组可动态增长:我们可以使用比数组的长度更大的索引。例如,上面的数组变量初始化后,数组长度为3,但我们仍然可以操作第5个元素 a[4] = 7;

我们可以通过数组的length属性得到数组长度:

<code class="hljs coffeescript">`<span class="javascript"><span class="hljs-keyword">for</span> (i=<span class="hljs-number">0</span>; i &lt; a.length; i++) { <span class="hljs-built_in">console</span>.log(a[i]);} <span class="hljs-comment">//1 2 3 undefined 7 </span></span>` </code>

我们可以通过 Array.isArray(a) 来检测一个变量是不是数组。

通过push方法给数组追加元素:a.push( newElement);

通过splice方法,删除指定位置的元素:a.splice( i, 1);

通过indexOf查找数组,返回位置或者-1:if (a.indexOf(v) > -1) …

通过for或者forEach(性能弱)遍历数组:

<code class="hljs matlab">var <span class="hljs-built_in">i</span>=<span class="hljs-number">0</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-built_in">i</span>=<span class="hljs-number">0</span>; <span class="hljs-built_in">i</span> &lt; a.<span class="hljs-built_in">length</span>; <span class="hljs-built_in">i</span>++) {
  console.log( a[i]);
}
a.forEach(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(elem)</span> {</span>
  console.<span class="hljs-built_in">log</span>( elem);
}) </code>

通过slice复制数组:var clone = a.slice(0);

Maps

map(也称为“散列映射”或“关联数组’)提供了从键及其相关值的映射。一个JS map的键是可以包含空格的字符串:

<code class="hljs swift"><span class="hljs-keyword">var</span> myTranslation = { 
<span class="hljs-string">"my house"</span>: <span class="hljs-string">"mein Haus"</span>, 
<span class="hljs-string">"my boat"</span>: <span class="hljs-string">"mein Boot"</span>, 
<span class="hljs-string">"my horse"</span>: <span class="hljs-string">"mein Pferd"</span>
}</code>

通过Object.keys(m)可以获得map中所有的键:

<code class="hljs perl">var i=<span class="hljs-number">0</span>, key=<span class="hljs-string">""</span>, <span class="hljs-keyword">keys</span>=[];
<span class="hljs-keyword">keys</span> = Object.<span class="hljs-keyword">keys</span>( myTranslation);
<span class="hljs-keyword">for</span> (i=<span class="hljs-number">0</span>; i &lt; <span class="hljs-keyword">keys</span>.<span class="hljs-keyword">length</span>; i++) {
  key = <span class="hljs-keyword">keys</span>[i];
  alert(<span class="hljs-string">'The translation of '</span>+ key +<span class="hljs-string">' is '</span>+ myTranslation[key]);
}</code>

通过直接给不存在的键赋值来新增元素:

<code class="hljs prolog">myTranslation[<span class="hljs-string">"my car"</span>] = <span class="hljs-string">"mein Auto"</span>;</code>

通过delete删除元素:

<code class="hljs sql"><span class="hljs-keyword">delete</span> myTranslation[<span class="hljs-string">"my boat"</span>];</code>

通过in搜索map:

<code class="hljs coffeescript">`<span class="javascript"><span class="hljs-keyword">if</span> (<span class="hljs-string">"my bike"</span> <span class="hljs-keyword">in</span> myTranslation)  ...</span>`</code>

通过for或者forEach(性能弱)和Object.keys()遍历map:

<code class="hljs perl">var i=<span class="hljs-number">0</span>, key=<span class="hljs-string">""</span>, <span class="hljs-keyword">keys</span>=[];
<span class="hljs-keyword">keys</span> = Object.<span class="hljs-keyword">keys</span>( <span class="hljs-keyword">m</span>);
<span class="hljs-keyword">for</span> (i=<span class="hljs-number">0</span>; i &lt; <span class="hljs-keyword">keys</span>.<span class="hljs-keyword">length</span>; i++) {
  key = <span class="hljs-keyword">keys</span>[i];
  console.<span class="hljs-keyword">log</span>( <span class="hljs-keyword">m</span>[key]);
}
Object.<span class="hljs-keyword">keys</span>( <span class="hljs-keyword">m</span>).forEach( function (key) {
  console.<span class="hljs-keyword">log</span>( <span class="hljs-keyword">m</span>[key]);
}) </code>

通过 JSON.stringify 将map序列化为JSON字符串,再JSON.parse将其反序列化为MAP对象 来实现复制:

<code class="hljs javascript"><span class="hljs-keyword">var</span> clone = <span class="hljs-built_in">JSON</span>.parse( <span class="hljs-built_in">JSON</span>.stringify( m)) </code>

请注意,如果map上只包含简单数据类型或(可能嵌套)数组/map,这种方法效果很好。在其他情况下,如果map包含Date对象,我们必须写我们自己的clone方法。

Functions

JS函数是特殊的JS的对象,它具有一个可选的名字属性和一个长度属性(参数的数目)。我们可以这样知道一个变量是不是一个函数:

<code class="hljs javascript"><span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span>( v) === <span class="hljs-string">"function"</span>) {...}</code>

JS函数可以保存在变量里、被当作参数传给其他函数,也可以被其他函数作为返回值返回。JS可以被看成一个函数式语言,函数在里面可以说是一等公民。

正常的定义函数方法是用一个函数表达式给一个变量赋值:

<code class="hljs javascript"><span class="hljs-keyword">var</span> myFunction = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">theNameOfMyFunction</span> () </span>{...}
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">theNameOfMyFunction</span> () </span>{...}</code>

其中函数名(theNameOfMyFunction)是可选的。如果省略它,其就是一个匿名函数。函数可以通过引用其的变量调用。在上述情况下,这意味着该函数通过myFunction()被调用,而不是通过theNameOfMyFunction()调用。

JS函数,可以嵌套内部函数。闭包机制允许在函数外部访问函数内部变量,并且创建闭包的函数会记住它们。

当执行一个函数时,我们可以通过使用内置的arguments参数,它类似一个参数数组,我们可以遍历它们,但由于它不是常规数组,forEach无法遍历它。arguments参数包含所有传递给函数的参数。我们可以这样定义一个不带参数的函数,并用任意数量的参数调用它,就像这样:

<code class="hljs javascript"><span class="hljs-keyword">var</span> sum = <span class="hljs-function"><span class="hljs-keyword">function</span> () </span>{
  <span class="hljs-keyword">var</span> result = <span class="hljs-number">0</span>, i=<span class="hljs-number">0</span>;
  <span class="hljs-keyword">for</span> (i=<span class="hljs-number">0</span>; i &lt; <span class="hljs-built_in">arguments</span>.length; i++) {
    result = result + <span class="hljs-built_in">arguments</span>[i];
  }
  <span class="hljs-keyword">return</span> result;
};
<span class="hljs-built_in">console</span>.log( sum(<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">5</span>,<span class="hljs-number">8</span>));  <span class="hljs-comment">// 20</span></code>

prototype原型链可以访问函数中的每一个元素,如Array.prototype.forEach(其中Array代表原型链中的数组的构造函数)。

<code class="hljs javascript"><span class="hljs-keyword">var</span> numbers = [<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>];  <span class="hljs-comment">// create an instance of Array</span>
numbers.forEach( <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">n</span>) </span>{
  <span class="hljs-built_in">console</span>.log( n);
});</code>

我们还可以通过原型链中的prototype.call方法来处理:

<code class="hljs javascript"><span class="hljs-keyword">var</span> sum = <span class="hljs-function"><span class="hljs-keyword">function</span> () </span>{
  <span class="hljs-keyword">var</span> result = <span class="hljs-number">0</span>;
  <span class="hljs-built_in">Array</span>.prototype.forEach.call( <span class="hljs-built_in">arguments</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">n</span>) </span>{
    result = result + n;
  });
  <span class="hljs-keyword">return</span> result;
};</code>

Function.prototype.apply是Function.prototype.call的一个变种,其只能接受一个参数数组。

立即调用的JS函数表达式优于使用纯命名对象,它可以获得一个命名空间对象,并可以控制其变量和方法哪些可以外部访问,哪些不是。这种机制也是JS模块概念的基础。在下面的例子中,我们定义了一个应用程序,它对外暴露了指定的元素和方法:

<code class="hljs javascript">myApp.model = <span class="hljs-function"><span class="hljs-keyword">function</span> () </span>{
  <span class="hljs-keyword">var</span> appName = <span class="hljs-string">"My app's name"</span>;
  <span class="hljs-keyword">var</span> someNonExposedVariable = ...;
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ModelClass1</span> () </span>{...}
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ModelClass2</span> () </span>{...}
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">someNonExposedMethod</span> (<span class="hljs-params">...</span>) </span>{...}
  <span class="hljs-keyword">return</span> {
    appName: appName,
    ModelClass1: ModelClass1,
    ModelClass2: ModelClass2
  }
}();  <span class="hljs-comment">// immediately invoked</span></code>

这种模式在WebPlatform.org被当作最佳实践提及:https://docs.webplatform.org/wiki/tutorials/javascript_best_practices

定义和使用类

类是在面向对象编程的基础概念。对象由类实例化而来。一个类定义了与它创建的对象的属性和方法。

目前在JavaScript中没有明确的类的概念。JavaScript中定义类有很多不同的模式被提出,并在不同的框架中被使用。用于定义类的两个最常用的方法是:

构造函数法,它通过原型链方法来实现继承,通过new创建新对象。这是Mozilla的JavaScript指南中推荐的经典方法。

工厂方法:使用预定义的Object.create方法创建类的新实例。在这种方法中,基于构造函数继承必须通过另一种机制来代替。

当构建一个应用程序时,我们可以使用这两种方法创建类,这取决于应用程序的需求 。mODELcLASSjs是一个比较成熟的库用来实现工厂方法,它有许多优点。(基于构造的方法有一定的性能优势)

ES6中构造函数法创建类

在ES6,用于定义基于构造函数的类的语法已推出(新的关键字类的构造函数,静态类和超类)。这种新的语法可以在三个步骤定义一个简单的类。

基类Person 定义了两个属性firstName 和lastName,以及实例方法toString和静态方法checkLastName:

<code class="hljs javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>{
  <span class="hljs-keyword">constructor</span>( first, last) {
    <span class="hljs-keyword">this</span>.firstName = first;
    <span class="hljs-keyword">this</span>.lastName = last;
  }
  toString() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.firstName + <span class="hljs-string">" "</span> +
        <span class="hljs-keyword">this</span>.lastName;
  }
  static checkLastName( ln) {
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span>(ln)!==<span class="hljs-string">"string"</span> || 
        ln.trim()===<span class="hljs-string">""</span>) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Error: "</span> +
          <span class="hljs-string">"invalid last name!"</span>);
    }
  }
}</code>

类的静态属性如下定义:

<code class="hljs">Person.instances = {};</code>

一个子类定义的附加属性和可能会覆盖超类的方法:

<code class="hljs scala"> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Student</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Person</span> </span>{
  constructor( first, last, studNo) {
    <span class="hljs-keyword">super</span>.constructor( first, last);
    <span class="hljs-keyword">this</span>.studNo = studNo; 
  }
  <span class="hljs-comment">// method overrides superclass method</span>
  toString() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.toString() + <span class="hljs-string">"("</span> +
        <span class="hljs-keyword">this</span>.studNo +<span class="hljs-string">")"</span>;
  }
}</code>

ES5中构造函数法创建类

在ES5,我们可以以构造函数的形式定义一个基于构造函数的类结构,下面是Mozilla的JavaScript指南中推荐的编码模式。此模式需要七个步骤来定义一个简单的类结构。由于这种复杂的模式可能很难记住,我们可能需要使用cLASSjs之类的库来帮助我们。

首先定义构造函数是隐式创建一个新的对象,并赋予它相应的值:

<code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Person</span>(<span class="hljs-params"> first, last</span>) </span>{
  <span class="hljs-keyword">this</span>.firstName = first; 
  <span class="hljs-keyword">this</span>.lastName = last; 
}</code>

这里的this指向新创建的对象。

在原型中定义实例方法:

<code class="hljs javascript">Person.prototype.toString = <span class="hljs-function"><span class="hljs-keyword">function</span> () </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.firstName + <span class="hljs-string">" "</span> + <span class="hljs-keyword">this</span>.lastName;
}</code>

可以在构造函数中定义静态方法,也可以用.直接定义:

<code class="hljs javascript">Person.checkLastName = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">ln</span>) </span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span>(ln)!==<span class="hljs-string">"string"</span> || ln.trim()===<span class="hljs-string">""</span>) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Error: invalid last name!"</span>);
  }
}</code>

定义静态属性:

<code class="hljs">Person.instances = {};</code>

定义子类并增加属性:

<code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Student</span>(<span class="hljs-params"> first, last, studNo</span>) </span>{
  <span class="hljs-comment">// invoke superclass constructor</span>
  Person.call( <span class="hljs-keyword">this</span>, first, last);
  <span class="hljs-comment">// define and assign additional properties</span>
  <span class="hljs-keyword">this</span>.studNo = studNo;  
}</code>

通过Person.call( this, …) 来调用基类的构造函数。

将子类的原型链改为基类的原型链,以实现实例方法的继承(构造函数得改回来):

<code class="hljs delphi"><span class="hljs-comment">// Student inherits from Person</span>
Student.prototype = <span class="hljs-keyword">Object</span>.create( 
    Person.prototype);
<span class="hljs-comment">// adjust the subtype's constructor property</span>
Student.prototype.<span class="hljs-keyword">constructor</span> = Student;</code>

通过Object.create( Person.prototype) 我们基于 Person.prototype创建了一个新的对象原型。

定义覆盖基类方法的子类方法:

<code class="hljs javascript">Student.prototype.toString = <span class="hljs-function"><span class="hljs-keyword">function</span> () </span>{
  <span class="hljs-keyword">return</span> Person.prototype.toString.call( <span class="hljs-keyword">this</span>) +
      <span class="hljs-string">"("</span> + <span class="hljs-keyword">this</span>.studNo + <span class="hljs-string">")"</span>;
};</code>

最后通过new关键字来实例化一个类

<code class="hljs javascript"><span class="hljs-keyword">var</span> pers1 = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">"Tom"</span>,<span class="hljs-string">"Smith"</span>);</code>

JavaScript的prototype

prototype是函数的一个属性(每个函数都有一个prototype属性),这个属性是一个指针,指向一个对象。它是显示修改对象的原型的属性。

__proto__是一个对象拥有的内置属性(prototype是函数的内置属性。__proto__是对象的内置属性),是JS内部使用寻找原型链的属性。

每个对象都有个constructor属性,其指向的是创建当前对象的构造函数。

工厂模式创建类

在这种方法中,我们定义了一个JS对象Person,并在其内部定义了一个create方法用来调用Object.create来创建类。

<code class="hljs javascript"><span class="hljs-keyword">var</span> Person = {
  name: <span class="hljs-string">"Person"</span>,
  properties: {
    firstName: {range:<span class="hljs-string">"NonEmptyString"</span>, label:<span class="hljs-string">"First name"</span>, 
        writable: <span class="hljs-literal">true</span>, enumerable: <span class="hljs-literal">true</span>},
    lastName: {range:<span class="hljs-string">"NonEmptyString"</span>, label:<span class="hljs-string">"Last name"</span>, 
        writable: <span class="hljs-literal">true</span>, enumerable: <span class="hljs-literal">true</span>}
  },
  methods: {
    getFullName: <span class="hljs-function"><span class="hljs-keyword">function</span> () </span>{
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.firstName +<span class="hljs-string">" "</span>+ <span class="hljs-keyword">this</span>.lastName; 
    }
  },
  create: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">slots</span>) </span>{
    <span class="hljs-comment">// create object</span>
    <span class="hljs-keyword">var</span> obj = <span class="hljs-built_in">Object</span>.create( <span class="hljs-keyword">this</span>.methods, <span class="hljs-keyword">this</span>.properties);
    <span class="hljs-comment">// add special property for *direct type* of object</span>
    <span class="hljs-built_in">Object</span>.defineProperty( obj, <span class="hljs-string">"type"</span>, 
        {value: <span class="hljs-keyword">this</span>, writable: <span class="hljs-literal">false</span>, enumerable: <span class="hljs-literal">true</span>});
    <span class="hljs-comment">// initialize object</span>
    <span class="hljs-built_in">Object</span>.keys( slots).forEach( <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">prop</span>) </span>{
      <span class="hljs-keyword">if</span> (prop <span class="hljs-keyword">in</span> <span class="hljs-keyword">this</span>.properties) obj[prop] = slots[prop];
    })
    <span class="hljs-keyword">return</span> obj;
  }
};  </code>

这样,我们就有了一个Person的工厂类,通过调用create方法来实例化对象。

<code class="hljs groovy">var pers1 = Person.create( {<span class="hljs-string">firstName:</span><span class="hljs-string">"Tom"</span>, <span class="hljs-string">lastName:</span><span class="hljs-string">"Smith"</span>});</code>

Leave a Reply

Your email address will not be published. Required fields are marked *