javascript原型是什么_javascript常用框架介绍

嵌入式操作系统

57人已加入

描述

  JavaScript 是面向对象的脚本语言,长期以来用作 Web 浏览器应用程序的客户端脚本接口。JavaScript 让 Web 开发人员能以编程方式处理 Web 页面上的对象,并提供了一个能够动态操作这些对象的平台。在最初引入 JavaScript 时,通常只用于提供 Web 页面上的一些不重要的特性,如时钟功能和浏览器状态栏中的滚动文本等。

  另一个常见的特性是 “rolloverlink”,就是当用户将鼠标移到图片或文本链接上时,图片或文本链接的颜色会改变。然而,近年来,随着AsynchronousJavaScript and XML (Ajax) 概念将基于 Web 的编程的交互性提升到一个新高度,JavaScript 也变得越来越重要。在出现 Ajax 之前,所有服务器端处理或数据库访问都需要 “刷新” 整个页面或通过浏览器呈现一个新页面。这不仅减慢了速度并使用户感到沮丧,而且还浪费带宽和资源。

  JavaScript原型

  原型是JavaScript中一个比较难理解的概念,原型相关的属性也比较多,对象有“[[prototype]]”属性,函数对象有“prototype”属性,原型对象有“constructor”属性。

  为了弄清原型,以及原型相关的这些属性关系,就有了这篇文章。

  相信通过这篇文章一定能够清楚的认识到原型,现在就开始原型之旅吧。

  认识原型

  开始原型的介绍之前,首先来认识一下什么是原型?

  在JavaScript中,原型也是一个对象,通过原型可以实现对象的属性继承,JavaScript的对象中都包含了一个“ [[Prototype]]”内部属性,这个属性所对应的就是该对象的原型。

  “[[Prototype]]”作为对象的内部属性,是不能被直接访问的。所以为了方便查看一个对象的原型,Firefox和Chrome中提供了“__proto__”这个非标准(不是所有浏览器都支持)的访问器(ECMA引入了标准对象原型访问器“Object.getPrototype(object)”)。

  实例分析

  下面通过一个例子来看看原型相关概念:

  function Person(name, age){

  this.name = name;

  this.age = age;

  this.getInfo = function(){

  console.log(this.name + “ is ” + this.age + “ years old”);

  };

  }

  var will = new Person(“Will”, 28);

  在上面的代码中,通过了Person这个构造函数创建了一个will对象。下面就通过will这个对象一步步展开了解原型。

  Step 1: 查看对象will的原型

  通过下面代码,可以查看对象will的原型:

  console.log(will.__proto__);

  console.log(will.constructor);

  结果分析:

  “Person {}”对象就是对象will的原型,通过Chrome展开可以看到,“Person {}”作为一个原型对象,也有“__proto__”属性(对应原型的原型)。

  在这段代码中,还用到了“constructor”属性。在JavaScript的原型对象中,还包含一个“constructor”属性,这个属性对应创建所有指向该原型的实例的构造函数。

  通过“constructor”这个属性,我们可以来判断一个对象是不是数组类型

  function isArray(myArray) {

  return myArray.constructor.toString().indexOf(“Array”) 》 -1;

  }

  在这里,will对象本身并没有“constructor”这个属性,但是通过原型链查找,找到了will原型(will.__proto__)的“constructor”属性,并得到了Person函数。

  代码

  Step 2: 查看对象will的原型(will.__proto__)的原型

  既然will的原型“Person {}”也是一个对象,那么我们就同样可以来查看“will的原型(will.__proto__)的原型”。

  运行下面的代码:

  console.log(will.__proto__ === Person.prototype);

  console.log(Person.prototype.__proto__);

  console.log(Person.prototype.constructor);

  console.log(Person.prototype.constructor === Person);

  结果分析:

  首先看 “will.__proto__ === Person.prototype”,在JavaScript中,每个函数都有一个prototype属性,当一个函数被用作构造函数来创建实例时,该函数的prototype属性值将被作为原型赋值给所有对象实例(也就是设置实例的__proto__属性),也就是说,所有实例的原型引用的是函数的prototype属性。了解了构造函数的prototype属性之后,一定就明白为什么第一句结果为true了。

  prototype属性是函数对象特有的,如果不是函数对象,将不会有这样一个属性。

  当通过“Person.prototype.__proto__”语句获取will对象原型的原型时候,将得到“Object {}”对象,后面将会看到所有对象的原型都将追溯到“Object {}”对象。

  对于原型对象“Person.prototype”的“constructor”,根据前面的介绍,将对应Person函数本身。

  通过上面可以看到,“Person.prototype”对象和Person函数对象通过“constructor”和“prototype”属性实现了相互引用(后面会有图展示这个相互引用的关系)。

  代码

  Step 3: 查看对象Object的原型

  通过前一部分可以看到,will的原型的原型是“Object {}”对象。实际上在JavaScript中,所有对象的原型都将追溯到“Object {}”对象。

  下面通过一段代码看看“Object {}”对象:

  console.log(Person.prototype.__proto__ === Object.prototype);

  console.log(typeof Object);

  console.log(Object);

  console.log(Object.prototype);

  console.log(Object.prototype.__proto__);

  console.log(Object.prototype.constructor);

  通过下面的代码可以看到:

  Object对象本身是一个函数对象。

  既然是Object函数,就肯定会有prototype属性,所以可以看到“Object.prototype”的值就是“Object {}”这个原型对象。

  反过来,当访问“Object.prototype”对象的“constructor”这个属性的时候,就得到了Obejct函数。

  另外,当通过“Object.prototype.__proto__”获取Object原型的原型的时候,将会得到“null”,也就是说“Object {}”原型对象就是原型链的终点了。

  代码

  Step 4: 查看对象Function的原型

  在上面的例子中,Person是一个构造函数,在JavaScript中函数也是对象,所以,我们也可以通过“__proto__”属性来查找Person函数对象的原型。

  console.log(Person.__proto__ === Function.prototype);

  console.log(Person.constructor === Function)

  console.log(typeof Function);

  console.log(Function);

  console.log(Function.prototype);

  console.log(Function.prototype.__proto__);

  console.log(Function.prototype.constructor);

  结果分析 :

  在JavaScript中有个Function对象(类似Object),这个对象本身是个函数;所有的函数(包括Function,Object)的原型(__proto__)都是“Function.prototype”。

  Function对象作为一个函数,就会有prototype属性,该属性将对应“function () {}”对象。

  Function对象作为一个对象,就有“__proto__”属性,该属性对应“Function.prototype”,也就是说,“Function.__proto__ === Function.prototype”

  对于Function的原型对象“Function.prototype”,该原型对象的“__proto__”属性将对应“Object {}”

  代码

  对比prototype和__proto__

  对于“prototype”和“__proto__”这两个属性有的时候可能会弄混,“Person.prototype”和“Person.__proto__”是完全不同的。

  在这里对“prototype”和“__proto__”进行简单的介绍:

  对于所有的对象,都有__proto__属性,这个属性对应该对象的原型

  对于函数对象,除了__proto__属性之外,还有prototype属性,当一个函数被用作构造函数来创建实例时,该函数的prototype属性值将被作为原型赋值给所有对象实例(也就是设置实例的__proto__属性)

  图解实例

  通过上面结合实例的分析,相信你一定了解了原型中的很多内容。

  但是现在肯定对上面例子中的关系感觉很凌乱,一会儿原型,一会儿原型的原型,还有Function,Object,constructor,prototype等等关系。

  现在就对上面的例子中分析得到的结果/关系进行图解,相信这张图可以让你豁然开朗。

  代码

  对于上图的总结如下:

  所有的对象都有“__proto__”属性,该属性对应该对象的原型

  所有的函数对象都有“prototype”属性,该属性的值会被赋值给该函数创建的对象的“__proto__”属性

  所有的原型对象都有“constructor”属性,该属性对应创建所有指向该原型的实例的构造函数

  函数对象和原型对象通过“prototype”和“constructor”属性进行相互关联

  通过原型改进例子

  在上面例子中,“getInfo”方法是构造函数Person的一个成员,当通过Person构造两个实例的时候,每个实例都会包含一个“getInfo”方法。

  var will = new Person(“Will”, 28);

  var wilber = new Person(“Wilber”, 27);

  代码

  前面了解到,原型就是为了方便实现属性的继承,所以可以将“getInfo”方法当作Person原型(Person.__proto__)的一个属性,这样所有的实例都可以通过原型继承的方式来使用“getInfo”这个方法了。

  所以对例子进行如下修改:

  function Person(name, age){

  this.name = name;

  this.age = age;

  }

  Person.prototype.getInfo = function(){

  console.log(this.name + “ is ” + this.age + “ years old”);

  };

  修改后的结果为:

  代码

  原型链

  因为每个对象和原型都有原型,对象的原型指向对象的父,而父的原型又指向父的父,这种原型层层连接起来的就构成了原型链。

  在“理解JavaScript的作用域链”一文中,已经介绍了标识符和属性通过作用域链和原型链的查找。

  这里就继续看一下基于原型链的属性查找。

  属性查找

  当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止,到查找到达原型链的顶部(也就是 “Object.prototype”), 如果仍然没有找到指定的属性,就会返回 undefined。

  看一个例子:

  function Person(name, age){

  this.name = name;

  this.age = age;

  }

  Person.prototype.MaxNumber = 9999;

  Person.__proto__.MinNumber = -9999;

  var will = new Person(“Will”, 28);

  console.log(will.MaxNumber);

  // 9999

  console.log(will.MinNumber);

  // undefined

  在这个例子中分别给“Person.prototype ”和“ Person.__proto__”这两个原型对象添加了“MaxNumber ”和“MinNumber”属性,这里就需要弄清“prototype”和“__proto__”的区别了。

  “Person.prototype ”对应的就是Person构造出来所有实例的原型,也就是说“Person.prototype ”属于这些实例原型链的一部分,所以当这些实例进行属性查找时候,就会引用到“Person.prototype ”中的属性。

  属性隐藏

  当通过原型链查找一个属性的时候,首先查找的是对象本身的属性,如果找不到才会继续按照原型链进行查找。

  这样一来,如果想要覆盖原型链上的一些属性,我们就可以直接在对象中引入这些属性,达到属性隐藏的效果。

  看一个简单的例子:

  function Person(name, age){

  this.name = name;

  this.age = age;

  }

  Person.prototype.getInfo = function(){

  console.log(this.name + “ is ” + this.age + “ years old”);

  };

  var will = new Person(“Will”, 28);

  will.getInfo = function(){

  console.log(“getInfo method from will instead of prototype”);

  };

  will.getInfo();

  // getInfo method from will instead of prototype

  对象创建方式影响原型链

  会到本文开始的例子,will对象通过Person构造函数创建,所以will的原型(will.__proto__)就是“Person.prototype”。

  同样,我们可以通过下面的方式创建一个对象:

  var July = {

  name: “July”,

  age: 28,

  getInfo: function(){

  console.log(this.name + “ is ” + this.age + “ years old”);

  },

  }

  console.log(July.getInfo());

  当使用这种方式创建一个对象的时候,原型链就变成下图了,July对象的原型是“Object.prototype”也就是说对象的构建方式会影响原型链的形式。

  代码

  hasOwnProperty

  “hasOwnProperty”是“Object.prototype”的一个方法,该方法能判断一个对象是否包含自定义属性而不是原型链上的属性,因为“hasOwnProperty” 是 JavaScript 中唯一一个处理属性但是不查找原型链的函数。

  相信你还记得文章最开始的例子中,通过will我们可以访问“constructor”这个属性,并得到will的构造函数Person。这里结合“hasOwnProperty”这个函数就可以看到,will对象并没有“constructor”这个属性。

  从下面的输出可以看到,“constructor”是will的原型(will.__proto__)的属性,但是通过原型链的查找,will对象可以发现并使用“constructor”属性。

  代码

  “hasOwnProperty”还有一个重要的使用场景,就是用来遍历对象的属性。

  function Person(name, age){

  this.name = name;

  this.age = age;

  }

  Person.prototype.getInfo = function(){

  console.log(this.name + “ is ” + this.age + “ years old”);

  };

  var will = new Person(“Will”, 28);

  for(var attr in will){

  console.log(attr);

  }

  // name

  // age

  // getInfo

  for(var attr in will){

  if(will.hasOwnProperty(attr)){

  console.log(attr);

  }

  }

  // name

  // age

  什么是JavaScript 框架?

  JavaScript 本身就是一种功能强大的语言,您不需要额外的框架就可创建富互联网应用程序(RIA)。然而使用JavaScript 并不是件容易的事,主要是由于支持多个 Web 浏览器产生的复杂性。与 HTML 和 CSS一样,不同的浏览器有不同的 JavaScript 实现。让 JavaScript 代码实现跨浏览器兼容简直是个噩梦。

  JavaScript 框架或库是一组能轻松生成跨浏览器兼容的 JavaScript 代码的工具和函数。每一个库都在众多流行的 Web浏览器的现代版本上进行了可靠的测试,因此,您可以放心地使用这些框架,您的基于 JavaScript 的 RIA 将会在不同浏览器和平台上以类似的方式工作。

  除了解决跨浏览器问题,使用 JavaScript 框架可以更容易地编写检索、遍历、操作 DOM 元素的代码。它们不仅提供获取 DOM 元素引用的快捷函数,而且还允许 DOM 遍历函数以菊花链(daisy-chaining)方式查找任意深度的父元素、子元素、兄弟元素。最后,框架还提供一系列函数来更轻松地操作这些对象,可以改变、添加或删除内容本身;或者使用 CSS 样式类来改变元素的外观。

  框架的另一重要特性是其改进的事件处理支持。由于不同浏览器的实现方式各不相同,跨浏览器事件处理将会非常艰难。因此 JavaScript 框架通常封装浏览器事件,并提供一组有用的跨浏览器兼容的函数来进行处理。有些框架还会提供一组标准键盘代码来表示基于键盘的事件(如按下 Escape 键、Return 键、光标键,等等)。

  所有这些特性都非常有用,但 JavaScript 框架有一个特性对于它最近的流行非常重要 — 支持 Ajax。与 JavaScript 的其他许多方面一样,每个 Web 浏览器往往以不同方式支持 Ajax,这使得以一种在所有 Web 浏览器中都受支持的方式处理 Ajax 变得十分复杂。几乎所有 JavaScript 框架都包含某种形式的 Ajax 库支持,通常提供 Ajax 请求和响应对象,以及用于评价响应、更新 DOM 元素、查询特定请求的帮助函数(helper)。

  JavaScript 框架的典型特性

  现在,让我们看一看大多数 JavaScript 框架都具备的有用特性。包括:

  · 选择器(Selector)

  · DOM 遍历

  · DOM 操作

  · 实用(Utility)函数

  · 事件处理

  · Ajax

  在解释每个特性时,我将会用以下的一个或几个 JavaScript 框架举例说明:Prototype、jQuery、YUI、ExtJS 和 MooTools。尽管每个框架的实现和语法都各不相同,但概念都是相同的。每个框架都有一个详细的 API 参考,可帮助您理解如何使用该特定库中的特性。

 

  选择器

  大多数可用的 JavaScript 框架都会实现某种形式的对快速元素选取的支持。通常来说,这些选择器会使获得 HTML 元素引用的过程快很多,并允许通过 ID、类名、元素类型甚至使用一组伪选择器(pseudo-selector)来查找元素。

  例如,使用常规 JavaScript,您也许会用以下代码通过 ID 来选择 DOM 元素:

  var theElement = document.getElementById(‘the_element’);

  与其他框架一样,MooTools 提供了执行此操作的快捷方法。除了选取该元素,MooTools 还可通过一系列实用函数扩展此元素。其语法如下:

  var theElement = $(‘the_element’);

  如上所示的单美元符号(dollar)函数,在很多(但不是所有)流行的 JavaScript 框架中都可用,而且语法也大体一致。Prototype 库则更进一步,允许通过 ID 一次选取多个元素,并返回元素数组。和 MooTools 一样,可用Prototype 实用函数扩展这些元素。用 Prototype 一次选取多个元素的语法是:

  var elementArray = $(‘element_one’, ‘element_two’,‘element_three’);

  在 实用函数 一节中,您将会学到更多 JavaScript 框架所提供的简化集合迭代的函数。

  在前面的例子中,必须提供需要选取的元素的 ID。然而,如果要选取多个元素(例如,所有图片)或是具有特定 CSS类名的所有表行,那又怎么办呢?MooTools(还有其他库)提供了一个简单的方法来实现此功能 — 双美元符号(dollar-dollar)函数。它的工作方式与单美元符号函数相同,不同之处在于它接受 CSS 元素名、类名、伪选择器作为参数,而不是接受元素 ID 作为参数。例如,要使用 MooTools 选取 Web 页面上的所有图片,将用以下代码:

  var allImages = $$(‘img’);

  这将返回一个包含文档中的所有图片的数组,其中每一个图片都使用单美元符号函数进行扩展,以包含 MooTools 实用函数。

  根据标记名选取元素非常有用,但如果只是想根据 CSS 类选择一个元素子集,该怎么办呢?这也很简单。在下面的例子中,MooTools 将会选择 CSS 类名为 “odd” 的所有表行。这在实现表行条状化(在表行之间交替变化背景色)时将非常有用:

  var allOddRows = $$(‘tr.odd’);

  实际上,MooTools 提供了实现表行条状化(row striping)的更好方法。在上面的例子中,假设表中的所有奇数行的CSS 类名为 “odd”。以下代码不要求对表行定义任何 CSS 类名:

  var allOddRows = $$(‘tbody:odd’);

  这是一个伪选择器的例子,将会返回所有符合条件的对象,在本例中为页面中的 tbody(表主体)的所有奇数子元素。MooTools 伪选择器的其他例子包括:

  · checked— 选取所有选中的元素(例如,选中的复选框)

  · enabled— 选取所有启用的元素

  · contains— 选取所有包含作为参数传递给选择器的文本的元素(例如,contains(‘thistext’))

  如前所述,并非所有 JavaScript 框架都使用单美元符号函数选取 DOM 元素。在 YUI (Yahoo!User Interface) 库第 3 版中,用以下代码根据 ID 选取元素(请注意 YUI 3 要求在 ID 前传递 ID 选择器符号 #):

  var theElement = Y.one(‘#the_element’);

  同样,与使用双美元符号函数根据标记或类名检索元素不同的是,YUI 使用了 Y.all 函数:

  var allOddRows = Y.all(‘tr.odd’);

  ExtJS 使用类似的方式,用以下语法根据 ID 选取元素:

  var theElement = Ext.get(‘the_element’);

  以下语法用于根据标记和类名选取元素:

  var allOddRows = Ext.select(‘tr.odd’);

  在下一节中,您将看到 JavaScript 框架如何轻松遍历 DOM,换句话说,就是查找选定元素的父元素、子元素、兄弟元素。您还会学到如何使用库操作 DOM 以修改元素。

 

  DOM 遍历

  根据 ID、元素类型或 CSS 类名查找元素非常有用,但如何根据元素在 DOM 树中的位置执行查找呢?换而言之,根据一个给定的元素查找其父元素、子元素、前一个或后一个兄弟元素。例如,看一下清单 1 的 HTML 片段。

  清单 1. HTML 片段(一个 HTML 表)

  《table》 《thead》 《tr》《th》Name《/th》 《th》Email Address《/th》《th》Actions《/th》 《/tr》 《/thead》 《tbody》 《trid=“row-001”》 《td》Joe Lennon《/td》《td》joe@joelennon.ie《/td》 《td》《ahref=“#”》Edit《/a》  《ahref=“#”》Delete《/a》《/td》 《/tr》 《trid=“row-002”》 《td》Jill Mac Sweeney《/td》 《td》jill@example.com《/td》《td》《a href=“#”》Edit《/a》  《ahref=“#”》Delete《/a》《/td》 《/tr》《/tbody》《/table》

  清单 1 用缩进表示每个元素在 DOM 节点树中的位置。在该例中,table 元素是根元素,它有两个子节点,thead 和 tbody。thead 元素只有一个子节点 tr,后者有三个子节点 — 所有 th 元素。tbody 元素有两个子节点,均为 tr 元素,每个 tr 元素又有三个子元素。每行的第三个子元素又有两个子节点,都是 a (锚点)标记。

  如您所知,可以使用 JavaScript 框架的 Selector 函数根据 ID 轻松选取元素。在该例中,有两个元素具有 ID — 均为 tr(表行)元素,ID 分别为 row-001 和 row-002。要使用 Prototype 选取第一个 tr 元素,需要用到以下代码:

  var theRow = $(‘row-001’);

  在前面的小节中,您学会了如何使用选择器根据类型或 CSS 类检索元素。在本例中,可以使用以下语法选取所有 td 元素。

  var allCells = $$(‘td’);

  这段代码的问题是它将返回 DOM 中的所有 td 元素。但是,如果只希望获取 ID 为 row-001 的行中的 td 元素,怎么办呢?这时就该使用 DOM 遍历函数了。首先,使用 Prototype 选取 ID 为 row-001 的 tr 元素的所有子节点:

  var firstRowCells = theRow.childElements();

  这将返回 theRow 变量(之前已设为 ID 为 row-001 的元素)的所有子元素的数组。

  下一步,假设只希望取得该行的第一个子节点,在本例中,是内容为 “Joe Lennon” 的 td 元素。应使用以下语句:

  var firstRowFirstCell = theRow.down();

  很简单吧?这种特别的用法等价于:

  var firstRowFirstCell = theRow.childElements()[0];

  也可以表示为:

  var firstRowFirstCell = theRow.down(0);

  JavaScript 索引值从零(0)开始,所以以上语句实际上是告诉 JavaScript 选取第一个子元素。要选取第二个子元素(包含joe@joelennon.ie 邮件地址的单元格),可以使用下面的语句:

  var firstRowSecondCell = theRow.down(1);

  或者,可以在 DOM 兄弟节点间导航。本例中,第二个单元格是第一个单元格的下一个兄弟节点,因此可以使用以下语句:

  var firstRowSecondCell = firstRowFirstCell.next();

  这与 down() 函数使用了相同的方式,因此可以使用下面的语句选择第三个单元格:

  var firstRowThirdCell = firstRowFirstCell.next(1);

  除了使用索引查找特定节点外,Prototype 还允许使用 CSS 选择器语法。考虑 清单 1 的例子,找到包含 Jill Mac Sweeney 的明细的行的第二个链接(“Delete” 链接):

  var secondRowSecondLink = $(‘row-002’).down(‘a’, 1);

  在本例中,可以使用美元符号函数找到 ID 为 row-002 的元素,然后向下遍历 DOM,直到找到下一个后代 a(锚点)元素。

  有些框架可以使用 “菊花链” 遍历函数,表示可以将遍历命令互相连接。在 Prototype 中实现前一个例子的另一种方法是:

  var secondRowSecondLink = $(‘row-002’).down(‘a’).next();

  考虑下面的例子:

  var domTraversal =$(‘row-001’).down().up().next().previous();

  如您所见,菊花链方式可以将几个 DOM 遍历语句连接起来。实际上,上例实际上选择 tr 元素 row-001,因此菊花链刚好回到了起点!

  DOM 操作

  上文中,您已经看到如何使用 JavaScript 框架的选择器和 DOM 遍历来简化特定元素的选取。然而,要想改变 Web 页面中的特定元素的外观或内容,需要操作 DOM 并应用改变。如果使用纯 JavaScript 将会非常繁琐,幸运的是,大多数JavaScript 框架提供了有用的函数,简化了这些操作。

  假设您有一个 div 元素,其 id 是 the-box:

  《div id=“the-box”》Message goeshere《/div》

  如果要用 jQuery 改变 “Message goes here” 文本,方法如下:

  $(‘the-box’).html(‘This is the new message!’);

  实际上,可以在函数内部使用 HTML 代码,它将由浏览器解析。例如:

  $(‘the-box’).html(‘This is the 《strong》new《/strong》message!’);

  在本例中,div 元素的内容在 DOM 中呈现为:

  《div id=“the-box”》This is the《strong》new《/strong》 message!《/div》

  当然,在一些情况下您需要使用特殊字符,如大于号或小于号。可以不指定专门的 HTML 实体代码,而是使用 jQuery的 text 函数:

  $(‘the-box’).text(‘300 》 200’);

  这将把 div 元素更新为以下代码:

  《div id=“the-box”》300 》200《/div》

  在上面的例子中,原有内容被新内容取代。如果只是想把消息添加到文本的后面,该怎么做呢?幸好,jQuery 提供了专门的 append 函数:

  $(‘the-box’).append(‘, here goes message’);

  将这个函数应用到初始的 div 元素,div 元素的内容就变成下面这样:

  《div id=“the-box”》Message goes here, heregoes message《/div》

  除了附加以外,您还可以 “前置” 内容,即在已有内容的前面而不是末尾插入新内容。另外,jQuery 提供了在给定元素之外插入内容的函数,不管是在开头还是在末尾。这类函数可以替换内容、清空内容、从 DOM 移除所有元素、克隆元素等等。

  除了 DOM 操作函数,JavaScript 框架还包含一些用于以编程方式处理元素样式和 CSS 类的函数。例如,假设您有一个表,您想要在鼠标移到某一行时高亮显示该行。您创建了一个特定的名叫 hover 的 CSS 类,并且您想要将这个类动态添加到行中。在 YUI 中,可以使用以下代码检查行中是否已经具有 hover 类,如果已经有的话,则删除它,如果没有的话,则添加它:

  if(row.hasClass(‘hover’)) row.removeClass(‘hover’); elserow.addClass(‘hover’);

  而且,大多数 JavaScript 框架都有内置的 CSS 操作函数。

 

  实用函数

  很多 JavaScript 框架提供了大量实用函数,可使 JavaScript 开发变得很容易。由于这些函数非常多,因此本文无法一一介绍。我将只讨论大多数框架都具备的一些比较重要的函数。

  如果您曾经使用 JavaScript 处理过数组,你应该熟悉使用 for 循环来遍历数组以处理数组值。例如,看一下清单 2 的代码:

  清单 2. 遍历 JavaScript 数组的传统方法

  var fruit = [‘apple’, ‘banana’, ‘orange’];for(var i = 0;i 《 fruit.length; i++) { alert(fruit[i]);}

  清单 2 中的代码没有问题,但有些冗长。大多数 JavaScript 框架包含 each 函数,它会对数据组的每个元素调用一个指定的函数。使用 MooTools,可以用清单 3 的代码执行与清单 2 相同的操作。

  清单 3. 使用 MooTools 中的 each 函数

  [‘apple’, ‘banana’, ‘orange’].each(function(item) {alert(item);});

  清单 3 中的语法与 Prototype 和 jQuery 中的语法相同,而与 YUI 和 ExtJS 中的语法有细微差异。然而,当用于 hash映射或对象而不是数组时,各框架的语法都不一样。例如在 MooTools 中,将用到清单 4 的代码:

  清单 4. 在 MooTools 中对基于键/值对的对象使用 each

  var hash = new Hash({name: “Joe Lennon”, email:“joe@joelennon.ie”});hash.each(function(value, key) { alert(key +“: ” + value);});

  在 Prototype 中,将用到清单 5 中的代码。

  清单 5. 在 Prototype 中对基于键/值对的对象使用 each

  var hash = $H({name: “Joe Lennon”, email:“joe@joelennon.ie”});hash.each(function(pair) { alert(pair.key +“: ” + pair.value);});

  每个框架都包含很多有用的函数,通常划分为 String 函数、Number 函数、Array 函数、Hash 函数、Date 函数等等。更多信息,请查阅相关 JavaScript 框架的 API 参考资料。

 

  事件处理

  每个 JavaScript 框架都实现了跨浏览器事件处理支持,鼓励您从旧式的内联事件连接转向一种流线化方法。看一下清单6 中的 jQuery 示例,其中在 hover 事件中高亮显示 div 元素。

  清单 6. 使用 jQuery 连接 hover Event

  $(‘the-box’).hover(function() {$(this).addClass(‘highlight’);}, function() {$(this).removeClass(‘highlight’);});

  这是一个由 jQuery 实现的特殊事件,请注意它有两个函数,触发 onMouseOver 事件时调用第一个,触发 onMouseOut 事件时调用第二个。这是因为 hover 没有标准的 DOM 事件。让我们查看一个更典型的事件,例如 click(查看清单 7)。

  清单 7. 使用 jQuery 连接 click Event

  $(‘the-button’).click(function() { alert(‘You pushed thebutton!’);});

  如您所见,本例中只有一个函数参数。jQuery 使用这种方式处理大多数 JavaScript 事件。在 jQuery 中使用事件处理函数时,上下文变量是指触发事件的元素。有些框架并不使用这种处理方式。以 Prototype 为例,清单 8 显示了用 Prototype 实现的与清单 7 等价的代码。

  清单 8. 使用 Prototype 连接 click Event

  $(‘the-button’).observe(‘click’, function(e) { alert(‘Youpushed the button!’);});

  您首先将注意到没有 click 函数,而是使用了 observe 函数,该函数在引用它自身之前将事件作为参数。您还可能注意到该函数的参数 e。这就是指向触发事件的元素的上下文变量。为了探究其工作原理,让我们针对 Prototype 重写 清单6 的代码(请看清单 9)。

  清单 9. 使用 Prototype 连接 hover Event

  $(‘the-box’).observe(‘mouseover’, function(e) { var el =Event.element(e); el.addClassName(‘highlight’);});$(‘the-box’).observe(‘mouseout’,function(e) { var el = Event.element(e); el.removeClassName(‘highlight’);});

  与 jQuery 中使用美元符号函数获取上下文变量不同的是,在 Prototype 中需要使用 Event.element() 函数。并且,您需要对 mouseover 和mouseout 使用不同的函数。

  在阅读本文的过程中,您也许会注意到函数使用内联方式创建且都没有命名。这意味着它们无法被重用。Prototype 的 hover 例子展示了如何使用已命名的函数作为替代方法。如清单 10 所示。

  清单 10. Prototype 中改进的 hover 例子

  function toggleClass(e) { var el = Event.element(e);if(el.hasClassName(‘highlight’)) row.removeClassName(‘highlight’); else row.addClassName(‘highlight’);}$(‘the-box’).observe(‘mouseover’,toggleClass);$(‘the-box’).observe(‘mouseout’, toggleClass);

  您会注意到,这次只定义了一个函数供 mouseover 和 mouseout 事件调用。该函数会判断元素是否已经高亮显示了类名,并根据查找结果执行添加或删除。您也许会注意到 e 参数是隐式传递的。换句话说,不需要在 observe 函数中以参数形式显式传递事件。

 

  Ajax

  使用 JavaScript 框架的另一个有说服力的理由是标准化的跨浏览器 Ajax 请求。Ajax 请求是一个异步 HTTP 请求,通常发送给服务器端脚本,后者返回 XML、JSON、HTML 或普通文本格式的响应。大多数 JavaScript 框架都有某种形式的Ajax 对象,以及一个以参数形式接受一组选项的请求方法。这些选项通常包含 callback 函数,当脚本一接收到来自Web 服务器的响应时,就会调用此函数。让我们看一下 ExtJS、MooTools 和 Prototype 中的 Ajax 请求的样子。

  首先,看一下典型的 ExtJS Ajax 请求(请看清单 11)。

  清单 11. 一个 ExtJS Ajax 请求

  Ext.Ajax.request({ url: ‘server_script.php’, params: {name1: ‘value1’, name2: ‘value2’ }, method: ‘POST’, success:function(transport) { alert(transport.responseText); }});

  ExtJS 中的 request 方法只有一个参数,这是一个包含 url、params、method 和 success 等不同字段的对象。url 字段包含服务器端脚本的 URL,该脚本将被 Ajax 请求调用。params 字段本身就是一个对象,包含有将被传递给服务器端脚本的键/值对。method 字段可以取两个值:GET 或 POST。它的默认值为未定义,但如果请求中有 params,将会默认作为 POST 处理。最后一个字段 success 是 Web 服务器返回成功响应时调用的函数。在本例中,假设服务器端脚本返回普通文本,并且文本会通过警告框显示给用户。

  下一步,我们看看同样的请求在 MooTools 中是什么样子(请看清单 12)。

  清单 12. 一个 MooTools Ajax 请求

  new Request({ url: ‘server-script.php’, data: { name1:‘value1’, name2: ‘value2’ }, method: ‘post’, onComplete: function(response) {alert(response); }}).send();

  如您所见,MooTools 与 ExtJS 非常相似。你也许注意到,与使用 params 不同,这里使用 data 字段传递变量,而且必须使用小写指定方法。还有,没有使用 success callback 函数,MooTools 使用了一个 onComplete 函数。最后,与 ExtJS 不同的是,在 MooTools 中,您需要使用Request 对象的 send() 函数发送请求。

  最后,让我们看看 Prototype 中的请求是否具有显著的不同(请看清单 13)。

  清单 13. 一个 Prototype Ajax 请求

  new Ajax.Request(‘server-script.php’, { params: { name1:‘value1’, name2: ‘value2’ }, method: ‘post’, onSuccess: function(transport) {alert(transport.responseText); }});

  同样,Prototype 的工作方式基本一致,只是有些句法上的小差别。首先,Prototype 的 Request 对象为其构造函数获取两个参数。第一个参数是请求将被发送到的 URL,第二个参数是一个具有典型 Ajax 选项的对象,如前两个例子所见。当然,由于 URL 现在作为单独的参数传递,它没有出现在选项列表中。同样需要注意,与 MooTools 不同,Prototype Ajax Request 对象构造函数隐式地发送请求,因此不需要调用任何方法来实际发起 HTTP 请求。

  大多数 JavaScript 框架中的 Ajax 支持要比此处演示的内容更加深入。重要的增强功能包括使用接收到的响应自动更新元素,而不需要任何特殊的 onSuccess 函数。一些库甚至包含预建的自动完成功能,如您在 Google 搜索引擎中所看到的,在输入时会出现常见搜索项。

  在下一节中,您将学习 JavaScript 框架为 Web 开发人员提供的用户体验(UX)增强功能。

 

  UX 增强功能

  到目前为止,本文全部关注的是使用 JavaScript 框架的编程优势以及它们如何简化交互式应用程序的编写。然而,对于大多数框架,还有另外一个更吸引人的方面:用户界面(UI)组件以及用户体验增强,这些在以前需要付出很大努力构建的工作现在可以轻松完成。

  本节将分别介绍以下框架的 UX 增强功能:Prototype、jQuery、YUI、ExtJS 和 MooTools。

  Prototype

  Prototype 是少数几个不提供开箱即用 UI 组件和 UX 增强功能的 JavaScript 框架之一。它将这些内容转移到其姊妹库script.aculo.us(最新版本是 Scripty2)中。Script.aculo.us 还添加了对 Prototype 中的各种效果和行为的支持。包括 highlighting、morphing、folding、shaking、sliding、puffing 等等。Script.aculo.us还提供拖放支持,例如滑块、in-place Ajax 编辑器和 autocompleters。与其他框架不同,Script.aculo.us 将所有控件(例如滑块和 autocompleters)的设计留给开发人员,并且未提供标准界面。

  jQuery

  与 Prototype 不同,jQuery 核心库中包含一些基本的 UX 增强。这些增强与script.aculo.us 中的一些基本效果类似。例如 sliding 和 fading。然而,要获得更高级的 UX 特性,就需要下载 jQuery UI 库,它包含比 jQuery 核心库更多的效果,以及交互特性,如拖放、调整大小和排序。与 script.aculo.us 不同的是,jQuery UI 还包含一些小部件或组件,它们使开发具有吸引力的界面变得更加容易。目前,这些组件包括 Accordion、Datepicker、Dialog、Progressbar、Slider 和 Tabs。这些小部件都可以划分主题,并且 jQuery UI 包含各种各样的主题,可以适合您自己的特定 Web 站点或 Web 应用程序的组件。图 1 演示了 jQuery UIDatepicker 小部件的例子,该小部件的主题为 Cupertino。

  图 1. jQuery UI Datepicker Widget

  YUI

  Prototype 和 jQuery 不包含开箱即用的 UI 小部件,但是 Yahoo! User Interface 库 (YUI) 包含一个 bucketload。除了支持拖放和调整大小外,YUI 第二版还包含autocompleters、calendar 控件、carousel 组件、绘图、对话框、进度条、富文本编辑器(所见即所得文本区)、滑块、选项卡、树等等。在撰写本文时,上述小部件都没有包含在 YUI 第三版中。图 2 是结合使用这些组件的一个例子。

  图 2. 复杂的 YUI 应用程序示例

  ExtJS

  和 YUI 一样,ExtJS 包含大量开箱即用的组件,其中有很多功能强大的网格控件,支持内联编辑、分页、筛选、分组、汇总、缓冲和数据绑定。ExtJS 组件具有非常专业的外观,并且分门别类。其他小部件包括选项卡、图表、窗口(对话框)、树、布局管理器、增强的表单控件、工具栏和菜单、拖放操作和直接远程功能(directremoting)。这仅仅是ExtJS 所提供的一小部分,如果要查找更多 RIA 组件,请登录 ExtJS 网站。图 3 是用 ExtJS 开发的 Web 桌面程序示例,展示了这个库的丰富特性。

  图 3. ExtJS 桌面应用程序示例

  MooTools

  MooTools 和 Prototype、jQuery 一样,也不包含开箱即用的 UI 控件和小部件。与 jQuery 一样,它包含一组有限的效果。其更高级的 UX 增强包含在MooTools.More.js 扩展中。这个扩展不仅仅是简单的 UX/UI 插件,而是包含对 Array、Date、Hash 和 String 类以及额外的 Element 扩展的一些有趣的附加功能。至于 UX 增强功能,MooTools.More.js包含拖放支持以及一些其他效果。这些附加功能还包括一些 UI 控件,如 accordion、可排序的HTML 表、scroller、工具提示和 Ajax spinneroverlays。然而,与 script.aculo.us 一样,您需要自己设计这些控件。

 

  Framework 比较

  表 1 是本文介绍的五个框架所含特性的详细比较。

  表 1. 框架特性比较

  代码

  其他重要框架

  限于篇幅,本文只介绍了五个比较常见的 JavaScript 框架。这并不表示它们是最流行的、最好的或是功能最多的框架。

  其他一些 JavaScript 框架也值得注意,包括:

  · Cappuccino

  · Dojo

  · Glow

  · GWT

  · MochiKit

  · Qooxdoo

  · Rialto

  · Rico

  · SproutCore

  · Spry

  · UIZE

 

  结束语

  本文介绍了JavaScript中原型相关的概念,对于原型可以归纳出下面一些点:

  所有的对象都有“[[prototype]]”属性(通过__proto__访问),该属性对应对象的原型

  所有的函数对象都有“prototype”属性,该属性的值会被赋值给该函数创建的对象的“__proto__”属性

  所有的原型对象都有“constructor”属性,该属性对应创建所有指向该原型的实例的构造函数

  函数对象和原型对象通过“prototype”和“constructor”属性进行相互关联

  还有要强调的是文章开始的例子,以及通过例子得到的一张“普通对象”,“函数对象”和“原型对象”之间的关系图,当你对原型的关系迷惑的时候,就想想这张图(或者重画一张当前对象的关系图),就可以理清这里面的复杂关系了。

  通过这些介绍,相信一定可以对原型有个清晰的认识。

  JavaScript 框架的概念以及它为什么会给 Web 网站和 Web 应用程序开发带来好处。本文对这些框架的常见功能作了简要描述,并举例说明在较常见的库中如何实现这些特性。本文还分别讲解了作为这五个框架的一部分或作为单独的附加功能的 UI 和 UX 增强。最后,还提供了一个直观的特性对比图表,其中列出了各个框架各自具备和缺乏的选项。有了这些知识,您应该就可以进行更深入的研究,然后明智地选择适合您及您的开发团队的框架。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分