jQury 基本原理

jQuery 基本原理

Rebecca Murphey

http://github.com/rmurphey/jqfundamentals

With contributions by James Padolsey, Paul Irish, and others. See the GitHub repository for a complete history of contributions.中文版由灰狐翻译团队完成:Allen、Hxgdzyuyi、Jack Hsing、Julian Wong、Leegorous、黎展波、Sky hx、Zengzhan(按字母顺序)

Licensed by Rebecca Murphey under the Creative Commons Attribution-Share Alike 3.0 United States license. You are free to copy, distribute, transmit, and remix this work, provided you attribute the work to Rebecca Murphey as the original author and reference the GitHub repository for the work. If you alter, transform, or build upon this work, you may distribute the resulting work only under the same, similar or a compatible license. Any of the above conditions can be waived if you get permission from the copyright holder. For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to the license.


Table of Contents

1. 欢迎
获得代码
软件
在你的页面里添加JavaScript
JavaScript的调试
练习
本书所使用的一些约定
相关阅读材料
I. JavaScript 101
2. JavaScript 基础
概述
基础语法
运算符
基本运算符
对数字和字符串进行运算
逻辑运算符
比较运算符
条件语句
真与假
三元运算符的赋值
Switch分支语句
循环语句
For循环
while 循环
do-while 循环
暂停和继续
关键字
数组
对象
函数
使用函数
自执行匿名函数
函数作为参数
测试类型
作用域
闭包
II. jQuery: 基础概念
3. jQuery 基础
$(document).ready()
选择元素
做包含任何元素的选择器?
保留的选择器
改善 & 过滤选择器
选择Form元素
使用选择器
链接
Getters & Setters
CSS, Styling, & Dimensions
为样式使用CSS类
尺寸
属性
遍历
操作元素
获取和设置元素信息
移动,拷贝和删除元素
创建新元素
操作属性
练习
Selecting
Traversing
Manipulating
4. jQuery核心
$ vs $()
实用方法
校验类型
数据方法
特色 & 浏览器探测
避免与其它库的冲突
5. 事件
概述
为元素绑定事件Connecting Events to Elements
绑定事件到只执行一次
取消事件绑定
命名空间事件
在事件处理函数中的函数 Inside the Event Handling Function
触发事件处理函数
使用事件委托提高性能
解除委托事件绑定
事件助手
$.fn.hover
$.fn.toggle
练习
Create an Input Hint
Add Tabbed Navigation
6. Effects 特效
概述
基本特效
改变基本效果持续时间
特效完成后做一些处理
使用$.fn.animate自定义效果
Easing
管理效果
练习
Reveal Hidden Text
Create Dropdown Menus
Create a Slideshow
7. Ajax
Overview
Key Concepts
GET vs. Post
Data Types
A is for Asynchronous
Same-Origin Policy and JSONP
Ajax and Firebug
jQuery's Ajax-Related Methods
$.ajax
Convenience Methods
$.fn.load
Ajax and Forms
Working with JSONP
Ajax Events
Exercises
Load External Content
Load Content Using JSON
8. 插件
准确来说,什么是一个插件?
如何创建一个基本的插件
寻觅插件
自己动手写插件
使用 jQuery UI Widget Factory 编写有状态的插件(Stateful Plugins)
给 widget 添加方法
Widget 的参数处理
添加回调功能
清扫处理
结论
练习
Make a Table Sortable
Write a Table-Striping Plugin
III. 高级主题
工作进度
9. 性能调优的最佳实践
在循环中缓存 length
在循环外使用 append
保持 DRY
当心匿名函数
优化选择器
ID 选择器
具体指定
避免使用无定向选择器
使用事件委派
先将元素 detach 出来再操作
应该使用样式表给大量元素修改 CSS
使用 $.data 而不是 $.fn.data
别费时间在空白的选择结果上了
变量定义
条件判断
别把 jQuery 当作黑盒子
10. 代码组织
概述
关键概念
封装
对象原语
组件模式
管理依赖
获取RequireJS
在jQuery中使用RequireJS
通过RequireJS创建可重用的模块
代码优化:RequireJS构建工具
练习
创建Portlet模块
11. Custom Events
Introducing Custom Events
A Sample Application

List of Examples

1.1.  页面内嵌JavaScript的例子
1.2.  引用外部JavaScript的例子
1.3.  例子的样式
2.1.  一个简单的变量声明
2.2.  引号外的空格和制表符是没有意义的
2.3.  括号内的表达式拥有更高的优先级
2.4.  制表符只是为了增加代码可读性,并没有什么其他的作用
2.5.  连接字符串
2.6.  乘法和除法
2.7.  自加和自减
2.8.  如果把数字和字符串相加,最后得到字符串
2.9.  把字符串强制转换成数字类型
2.10.  使用一元运算符的+号,把运算符后的变量转换成数字类型。
2.11.  逻辑与和逻辑或操作符
2.12.  比较运算符
2.13.  流程控制
2.14.  被判断义为  true的值
2.15.  被判定为 false的值
2.16.  三元运算符
2.17.  一个switch分支语句
2.18.  循环语句
2.19.  典型的 for 循环
2.20.  典型的  while循环
2.21.  while 循环,在条件判断部分对计数器i进行自加
2.22.  一个  do-while 循环
2.23.  停止循环
2.24.  跳过下一个循环迭代
2.25.  简单数组
2.26.  通过索引访问数组项
2.27.  测试数组长度
2.28.  改变数组项值
2.29.  加入元素到数组中
2.30.  关于数组
2.31.  创建一个对象常量
2.32.  函数申明
2.33.  命名函数表达式
2.34.  一个简单函数
2.35.  函数返回一个值
2.36.  函数返回另一个函数
2.37.  一个自执行的匿名函数
2.38.  以参数的方式传递一个匿名函数
2.39.  以参数的方式传递一个命名函数
2.40.  测试各种变量的类型
2.41.  函数访问同一作用域内定义的变量
2.42.  代码作用域外定义的变量不能访问该变量Code outside the scope in which a variable was defined does not have access to the variable
2.43.  拥有相同名字的变量可以以不同的值存在不同的作用域中
2.44.  函数定义后可看见变量值的改变
2.45.  Scope insanity
2.46.  如何锁定 i的值?
2.47.  以一个闭包的方式锁定 i的值
3.1.  A $(document).ready() block
3.2.  $(document).ready() 简写
3.3.  用命名函数替代匿名函数传递
3.4.  通过ID选择元素
3.5.  通过类名选择元素
3.6.  通过属性选择元素
3.7.  通过组合CSS选择器选择元素
3.8.  伪选择器
3.9.  测试选择器是否包含多个元素
3.10.  在变量中保存选择器
3.11.  改善选择器
3.12.  使用表单相关的伪选择器
3.13.  链式
3.14.  格式化链式代码
3.15.  使用  $.fn.end恢复你原来的选择器
3.16.  $.fn.html 方法作为一个 setter 使用
3.17.  html 方法作为一个 getter 使用
3.18.  取得 CSS 属性
3.19.  Setting CSS properties
3.20.  使用类
3.21.  基本尺寸方法
3.22.  设置属性
3.23.  取得属性
3.24.  使用遍历方法围绕DOM移动
3.25.  通过选择器迭代
3.26.  改变一个元素的HTML
3.27.  使用不同的方法移动元素
3.28.  拷贝一个元素
3.29.  创建新元素
3.30.  创建一个包含属性对象的新元素
3.31.  从页中获得一个新元素
3.32.  同一时刻创建和添加元素到页面
3.33.  操作单一属性
3.34.  操作多个属性
3.35.  使用函数去确定新的属性值
4.1.  校验任意值的类型e
4.2.  存储和检索一个元素的相关数据
4.3.  使用  $.fn.data 存储元素之间的关系
4.4.  将 jQuery 设为 no-conflict 模式
4.5.  在自执行匿名函数中使用 $
5.1.  使用便捷的方式绑定
5.2.  使用 $.fn.bind方法绑定事件
5.3.  使用 $.fn.bind方法将数据绑定到事件
5.4.  使用 $.fn.one方法转换处理函数
5.5.  取消选择器下所有的点击事件处理函数绑定
5.6.  取消特定点击事件处理函数绑定
5.7.  命名空间事件 Namespacing events
5.8.  阻止链接被访问
5.9.  以正确的方式触发事件处理函数
5.10.  使用 $.fn.delegate委托事件
5.11.  使用 $.fn.live委托事件
5.12.  解除委托事件的绑定
5.13.  hover助手函数
5.14.  toggle助手函数
6.1.  基本的动画效果
6.2.  设置动画效果持续时间
6.3.  增加  jQuery.fx.speeds 自定义动画速度
6.4.  动画执行完后运行代码
6.5.  运行回调函数即使没设置任何参数
6.6.  使用 $.fn.animate自定义效果
6.7.  easing属性
7.1.  Using the core $.ajax method
7.2.  Using jQuery's Ajax convenience methods
7.3.  Using  $.fn.load to populate an element
7.4.  Using  $.fn.load to populate an element based on a selector
7.5.  Turning form data into a query string
7.6.  Creating an array of objects containing form data
7.7.  Using YQL and JSONP
7.8.  Setting up a loading indicator using Ajax Events
8.1.  这个插件用于 hover(鼠标划过)时添加/删除一个 class
8.2.  Mike Alsup 的 jQuery 插件设计模式
8.3.  用 jQuery UI widget factory 创建一个简单的有状态的插件
8.4.  给 widget 传递参数
8.5.  给 widget 设置默认值
8.6.  创建 widget 的方法
8.7.  调用插件实例的方法
8.8.  当参数被修改时执行一些操作
8.9.  提供回调功能让用户进行扩展
8.10.  绑定 widget 事件
8.11.  给 widget 添加 destroy 方法
10.1.  对象原语
10.2.  将对象原语用到jQuery特性中
10.3.  组件模式
10.4.  通过jQuery使用组件模式
10.5.  使用RequireJS:一个简单示例
10.6.  使用依赖的简单JavaScript文件
10.7.  定义一个没有依赖性的RequireJS模块
10.8.  定义一个有依赖性的RequireJS模块
10.9.  定义一个返回函数的RequireJS模块
10.10.  RequireJS构建配置文件

Chapter 1. 欢迎

jQuery正迅速地变成前端开发人员必需技能。 这本书的目的是提供jQuery JavaScript库的概述;当你完成这本书阅读的时候, 你应该能够用jQuery完成基本的任务并且有能继续学习的坚实基础。 这本书是作为课堂教学教材设计的,但你会发现它对自学也很有用。

这是一个需要动手的课程。我们将会花费一点时间说明一个概念, 然后你将会有机会去做一个与这个概念有关的练习。 可能有些练习会让你觉得烦琐;其它的可能是十足令人气馁的。 这些练习都是没有评分的; 练习的目的只是让你在工作中能轻松地解决使用jQuery常会出现的问题。 练习的示例解决方案都被包含在示例代码中。

获得代码

这本书用到的代码托管在 Github的库里。 你也可以下载代码的.zip或者.tar文件,解压后在你的服务器上使用。 如果你愿意使用git,欢迎你复制或fork这个库。

软件

在大部分的课程中你会需要以下的工具:

  • Firefox浏览器

  • Firefox附加组件Firebug

  • 纯文本编辑器

  • Ajax部分:本地服务器(例如MAMP、WAMP), 或者可以访问远程服务器的FTP、SSH客户端

在你的页面里添加JavaScript

JavaScript可以内嵌在页面里,也可以引用外部使用script标签的文件。 引用JavaScript的先后顺序很重要:脚本必须在依赖其的脚本前被引用。

出于页面性能考虑,应在离HTML结尾尽可能近的地方引用JavaScript。 数量较多的JavaScript文件应在部署的时候合并起来。

Example 1.1. 页面内嵌JavaScript的例子


Example 1.2. 引用外部JavaScript的例子


JavaScript的调试

调试工具对JavaScript开发来说是很重要的。 Firefox提供了一款叫Firebug的调试器,这个调试器可以通过附件组件获得; Safari和Chrome则内嵌了调试控制台。

各种控制台的功用:

  • 用来编写JavaScript的单行或多行编辑器

  • 用来查看生成的页面源代码的监视器

  • 用来检查网络请求情况的网络或资源视图

当你在编写JavaScript代码的时候,可以通过如下的方法在控制台输出消息:

  • 输出普通日志消息:console.log()

  • 输出可浏览的对象的日志:console.dir()

  • 输出警告日志:console.warn()

  • 输出错误日志:console.error()

还有其他的控制台方法,但是它们可能会因为浏览器而有所不同。 控制台还提供了设置断点、查看代码中的表达式等方法以供调试使用。

练习

这本书大多数的章节都以一个或多个练习来作出结论。 其中的一些练习,你可以直接在Firebug里完成; 其他的你需要像独立的练习指导的那样,在jQuery脚本标签后引用其他的脚本。

在一些情况下,你需要按顺序查阅jQuery的文档来完成一个练习, 毕竟这本书没有覆盖所有的相关信息。 这是故意的,因为jQuery有很庞大的文档库, 学习如何在文档中找答案是一个很重要的学习过程。

解决问题的几点建议:

  • 首先,你需要确定你完全理解了你要解决的问题。

  • 接下来,确定你要从哪个元素入手解决问题,然后决定如何获得这些元素。 使用Firebug核实你确实获得了你想要的元素

  • 最后,确定你要如何处理这些元素以解决问题。 在写代码前先写注释解释你将如何处理将会很有帮助。

不要害怕犯错误!不要在第一次的时候就试图让你的代码完美! 犯错误然后尝试不同解决方法是学习这个库的一个部分,通过尝试,你会变成一个更好的开发者。 练习的示例解决方案可以从示例代码的/solutions目录获得。

本书所使用的一些约定

可以被jQuery对象调用的方法使用$.fn.methodName描述。 jQuery命名空间中存在的但是不能被jQuery对象调用的方法使用$.methodName描述。 如果你不能理解这些,不用担心,随着你对本书阅读的深入,这些概念会越来越清晰。

Example 1.3. 例子的样式

//示例代码以这种样式显示

评论以这种样式显示。

Note

关于标题的批注以这种样式显示。

相关阅读材料

有很多文章和博客涉及jQuery的一些方面。 其中有一些是了不起的;一些是完全错误的。 当你在阅读这些关于jQuery的文章时,要确定它说的是你正在使用的版本, 不要马上复制粘贴代码——花点时间去理解文章里的代码。

这里有一些很优秀的资源可供学习jQuery的过程中使用。 这些jQuery资源最重要的地方是jQuery的源代码:它以代码的形式包含了库里的所有文档。 这不是一个黑盒子——你对库的理解将随着你重复的阅读而呈现指数级的深入—— 我非常建议将这些资源添加到你浏览器的书签中以便经常查阅。

  •  jQuery源代码

  • jQuery 文档

  • jQuery 论坛

  • 宜人的书签们

  • Freenod上的#jquery IRC频道

Part I. JavaScript 101

Chapter 2. JavaScript 基础

概述

jQuery 构建在 JavaScript 之上,是一个丰富和极具表现力的语言。这一章节将覆盖 JavaScript 的基本概念,除一些常见陷阱外,大家在此之前不需要使用过 JavaScript。 除个别的地方外也不需要有程序设计经验,有过其它编程语言的使用经验也会对 javaScript 的学习有所帮助。

如果你有兴趣了解更多JavaScript语言,我强力推荐你阅读由Douglas Crockford编写的JavaScript: The Good Parts

基础语法

理解语句,变量名称,空格,制表符,以及其他的一些基本javascript语法

Example 2.1. 一个简单的变量声明

var foo = 'hello world';

Example 2.2. 引号外的空格和制表符是没有意义的

var foo =         'hello world';

Example 2.3. 括号内的表达式拥有更高的优先级

2 * 3 + 5;    // 返回11,先进行乘法运算
2 * (3 + 5);  // 返回16,先进行的是括号内的加法运算

Example 2.4. 制表符只是为了增加代码可读性,并没有什么其他的作用

var foo = function() {
    console.log('hello');
};

运算符

基本运算符

通过基本运算符可以方便的操作数据的值

Example 2.5. 连接字符串

var foo = 'hello';
var bar = 'world';

console.log(foo + ' ' + bar); // 'hello world'


Example 2.6. 乘法和除法

2 * 3;
2 / 3;


Example 2.7. 自加和自减

var i = 1;

var j = ++i;  // 自加运算符在i之前:  j 等于 2; i 等于 2
var k = i++;  // 自加运算符在i之后: k 等于 2; i 等于 3


对数字和字符串进行运算

在javascript中,对数字和字符串的操作,偶尔会得到意料之外的结果

Example 2.8. 如果把数字和字符串相加,最后得到字符串

var foo = 1;
var bar = '2';

console.log(foo + bar);  // 12. uh oh


Example 2.9. 把字符串强制转换成数字类型

var foo = 1;
var bar = '2';

// 把字符串转换成数字
console.log(foo + Number(bar));

上例中,当Number对象的构造函数作为一个函数被调用的时候,它会把传入的参数自动转换成数字。除了这种方法,你还可以使用一元运算符+进行强制类型转换,如下例所示。

Example 2.10. 使用一元运算符的+号,把运算符后的变量转换成数字类型。

console.log(foo + +bar);

逻辑运算符

逻辑运算符使用and和or对操作数进行逻辑判断

Example 2.11. 逻辑与和逻辑或操作符

var foo = 1;
var bar = 0;
var baz = 2;

foo || bar;   // 返回1,也就是返回true,判断结果为真。
bar || foo;   // 返回1。

foo && bar;   // 返回0,也就是返回false,判断结果为假。
foo && baz;   // 返回baz的,返回值为2,判断结果为真。
baz && foo;   // 返回1,判断结果为真。


也许无法从例子中清晰的反应出来,其中或运算符( ||) 返回第一个值为真的操作数, 如果两个操作数的值都为假,则返回最后一个操作数。 类似的,与运算符( &&) 返回第一个值为假的运算符,如果两个操作数的值都为真,则返回最后一个操作数

跳到the section called “真与假” 查看更多关于什么时候判断运算结果为true 和什么时候判断运算结果为 false的资料。

Note

你有的时候会看到开发者使用以下语句代替if进行流程控制

// 当foo的值为真的时候执行doSomething来处理foo
foo && doSomething(foo);

// 如果baz为真,则把baz的值赋给bar
// 否则bar的值为函数craetBar的返回值
var bar = baz || createBar();

这种风格的代码非常的简洁和优雅,但是同时,特别对于初学者而言,往往晦涩难懂。把它放在这里是希望当你在阅读到这类代码的时候可以读懂。但是如果你还不能够理解它的本质,且没有熟练掌握的话,我们不建议你使用此类代码

比较运算符

比较运算符用来判断两个操作数是否相等

Example 2.12. 比较运算符

var foo = 1;
var bar = 0;
var baz = '1';
var bim = 2;

foo == bar;   // 返回false,返回假。
foo != bar;   // 返回true,返回真。
foo == baz;   返回真,(注意!)

foo === baz;             // 返回false
foo !== baz;             // 返回true
foo === parseInt(baz);   // 返回true

foo > bim;    // 返回false
bim > baz;    // 返回true
foo <= baz;   // 返回true

条件语句

有时,你需要当符合某种特定条件的时候再运行你的代码。你可以通过流程控制语句if-else,来让代码在符合某种条件的时候运行。

Example 2.13. 流程控制

var foo = true;
var bar = false;

if (bar) {
    // 这里的代码将不会运行。
    console.log('hello!');
}

if (bar) {
    // 这里的代码不会运行。
} else {
    if (foo) {
        // 这里的代码会运行
    } else {
        // 如果foo和bar都为false,则这里的代码会被运行。
    }
}

Note

虽然当if语句后面只跟有一行代码时,该代码不加括号也是可以运行的。但是为了代码可读性,代码前后通常也加上括号

请注意,不要在if/esle代码段中多次定义同一个函数,这会引起意想不到的结果

真与假

为了熟练的使用流程控制语句,我们必须要知道在变量值中哪些类型的值会被判定为真,哪些类型的值会被判定为假,有时看起来像是假的值却被判定为真

Example 2.14. 被判断义为 true的值

'0'; //字符串0。
		'any string';//任意字符串。
[];  // 一个空数组。
{};  // 一个空对象。
1;   // 不为0的数。

Example 2.15. 被判定为false的值

0;
'';  // 一个空串。
NaN; // JavaScript中的 "not-a-number"(NaN是一个不确定的数)。 
null;
undefined;  // 注意 -- undefined 可以被重新定义!

三元运算符的赋值

[Definition:  三元运算符 通过判定条件,如果条件为真返回第一个值 如果条件为假,返回第二个值]

Example 2.16. 三元运算符

// 如果bar为1则,foo值为1。
// 否则,foo的值为0。
var foo = bar ? 1 : 0;

三元运算符不一定必须要把返回值赋值给变量。

Switch分支语句

[Definition:  Switch 分支语句 分支语句根据一个 变量或者表达式的值,来运行不同的代码段。]

Example 2.17. 一个switch分支语句

switch (foo) {

    case 'bar':
        alert('the value was bar -- yay!');
    break;

    case 'baz':
        alert('boo baz :(');
    break;

    default:
        alert('everything else is just ok');
    break;

}

Switch语句在JavaScript中并不是经常被人们用到,通常人们可以通过创建 一个对象来更好的完成这项工作,下面就是一个例子。

var stuffToDo = {
    'bar' : function() { 
        alert('the value was bar -- yay!');
    },

    'baz' : function() { 
        alert('boo baz :(');
    },

    'default' : function() { 
        alert('everything else is just ok');
    }
};

if (stuffToDo[foo]) {
    stuffToDo[foo]();
} else {
    stuffToDo['default']();
}

我们在以后的章节来了解对象。

循环语句

循环语句可以让一段代码执行一定的次数。

Example 2.18. 循环语句

// logs 'try 0', 'try 1', ..., 'try 4'
for (var i=0; i<5; i++) {
    console.log('try ' + i);
}


在 Example 2.18, “循环语句”,即使我们在变量名 i前使用关键字var,这也并不意味着 i 变量的作用域在 循环体内。我们将在后面的章节讨论变量的作用域。

For循环

for 循环由以下几个部分构成

for ([initialisation初始化]; [conditional条件判断]; [iteration迭代])
 [loopBody循环体]

初始化部分在循环开始前执行一次。可以在此声明循 欢中需要用到的变量

条件判断部分在每次循环前执行,它的返回值决定了 循环是否继续。如果返回值为false,那么循环将被终止

迭代部分该部分在每次循环结束时执行,你可以借此改变重要变 量的状态和值。通常在这里进行自加和自减运算,让循环更接近终止。

循环体 每次循环时执行,你可以在( {...})中放入你想运行的代码。

这是一个典型的 for 循环:

Example 2.19. 典型的for 循环

for (var i = 0, limit = 100; i < limit; i++) {
    // 代码将要执行100次。
    console.log('Currently at ' + i);
    // 最后输出的i值为99。
}

while 循环

while 循环和if语句类似,除了它的函数体 会一直循环执行,直到条件部分返回false。

while ([条件判断]) [循环体]

这里是一个典型的 while 循环:

Example 2.20. 典型的 while循环

var i = 0;
while (i < 100) {

    // 代码会被执行100次。
    console.log('Currently at ' + i);
    
    i++; // i的自加。
    
}

你会看到我们在循环体内进行计数器i的自加运算。事实上我们也可以在条件判断部分进行自加运算,比如:

Example 2.21.  while 循环,在条件判断部分对计数器i进行自加

var i = -1;
while (++i < 100) {
    // 这里的代码会被执行100次
    console.log('Currently at ' + i);
}

注意我们是从-1 开始并且把自加运算符放在变量前(++i).

do-while 循环

该循环和while循环类似,循环体在条件判断之前执行。

do [循环体] while ([条件判断])

这是一个 do-while 循环:

Example 2.22. 一个 do-while 循环

do {

    // 即使条件判断返回值为false,循环体还是被执行了一次。
    
    alert('Hi there!');
    
} while (false);

这些循环类型很少用,仅仅在至少执行一次的情况下才需要这种循环。无论如何,意识到这一点就很好。

暂停和继续

通常,一个循环的终止从条件语句来判断其结果并不一定是true,它可能是在循环体中使用了break语句而停止了循环。

Example 2.23. 停止循环

for (var i = 0; i < 10; i++) {
    if (something) {
        break;
    }
}

你不需要执行更多的循环体就可以继续循环。这里将使用 continue语句。

Example 2.24. 跳过下一个循环迭代

for (var i = 0; i < 10; i++) {
    
    if (something) {
        continue;
    }
    
    // 以下语句将被执行
    // 如果条件"something" 没有匹配
    console.log('I have been reached');
    
}

关键字

JavaScript 有一些保留的 “关键字,” 或者这些单词在语言中有其它含义。 除非你以那样的含义使用它们,否则你应该避免在你的代码中使用这些关键字。

  • break

  • case

  • catch

  • continue

  • default

  • delete

  • do

  • else

  • finally

  • for

  • function

  • if

  • in

  • instanceof

  • new

  • return

  • switch

  • this

  • throw

  • try

  • typeof

  • var

  • void

  • while

  • with

  • abstract

  • boolean

  • byte

  • char

  • class

  • const

  • debugger

  • double

  • enum

  • export

  • extends

  • final

  • float

  • goto

  • implements

  • import

  • int

  • interface

  • long

  • native

  • package

  • private

  • protected

  • public

  • short

  • static

  • super

  • synchronized

  • throws

  • transient

  • volatile

数组

数组是一列没有索引的数值。它们是存储一组相同类型(如字符串)数组项的便捷方法,尽管实际上,一个数组可以包含多种类型数组项,甚至包含其它数组。

Example 2.25. 简单数组

var myArray = [ 'hello', 'world' ];

Example 2.26. 通过索引访问数组项

var myArray = [ 'hello', 'world', 'foo', 'bar' ];
console.log(myArray[3]);   // logs 'bar'

Example 2.27. 测试数组长度

var myArray = [ 'hello', 'world' ];
console.log(myArray.length);   // logs 2

Example 2.28. 改变数组项值

var myArray = [ 'hello', 'world' ];
myArray[1] = 'changed';

当数组值可能以 Example 2.28, “改变数组项值” 的方式改变时,它们通常不被考虑。

Example 2.29. 加入元素到数组中

var myArray = [ 'hello', 'world' ];
myArray.push('new');

Example 2.30. 关于数组

var myArray = [ 'h', 'e', 'l', 'l', 'o' ];
var myString = myArray.join('');   // 'hello'
var mySplit = myString.split('');  // [ 'h', 'e', 'l', 'l', 'o' ]

对象

对象包含一个或多个key-value对。其中 key 可以是任何字符。value 部分可以是任何数值类型:a number, a string, an array, a function, 甚至可以是另外一个 object。

[Definition: 当这些数值中有一个函数时,它们调用对象的一个 method 方法。] 否则,它们调用属性。

恰好,JavaScript 中所有东西都是一个对象 - 数组、函数、成员、甚至字符串 — 它们都拥有属性和方法。

Example 2.31. 创建一个对象常量

var myObject = {
    sayHello : function() {
        console.log('hello');
    },

    myName : 'Rebecca'
};

myObject.sayHello();            // logs 'hello'
console.log(myObject.myName);   // logs 'Rebecca'

Note

当创建一个对象常量时,你应该注意每一对 key-value 中的 key 都能被写成任何有效的 javaScript 标识符,一个字符串(带引号) 或是一个数值:

var myObject = {
    validIdentifier: 123,
    'some string': 456,
    99999: 789
};

对象常量在代码组织上非常有用;更多信息,请阅读 Rebecca Murphey 写得 Using Objects to Organize Your Code。

函数

函数是包含需要反复执行的代码块。函数可以没有参数或包含多个参数,能返回任意一个值。

函数的创建有多种方法:

Example 2.32. 函数申明

function foo() { /* do something */ }

Example 2.33. 命名函数表达式

var foo = function() { /* do something */ }

在设置一个函数名时我更喜欢命名函数表达式,这有相当的深度和技术因素。 你可能在其它的 JavaScript 代码中看到过这两种方法的使用。

使用函数

Example 2.34. 一个简单函数

var greet = function(person, greeting) {
    var text = greeting + ', ' + person;
    console.log(text);
};


greet('Rebecca', 'Hello');

Example 2.35. 函数返回一个值

var greet = function(person, greeting) {
    var text = greeting + ', ' + person;
    return text;
};

console.log(greet('Rebecca','hello'));

Example 2.36. 函数返回另一个函数

var greet = function(person, greeting) {
    var text = greeting + ', ' + person;
    return function() { console.log(text); };
};


var greeting = greet('Rebecca', 'Hello');
greeting();

自执行匿名函数

JavaScript中一个常见的模式是自执行匿名函数。这个模式创建一个函数表述式然后立即执行函数。这个模式为避免你在代码中乱用全局命名空间将非常有用 -- 没有在函数内声明的变量在函数外也是可见的

Example 2.37. 一个自执行的匿名函数

(function(){
    var foo = 'Hello world';
})();


console.log(foo);   // undefined!

函数作为参数

在 JavaScript 中, 函数是"一等公民" -- 它们能赋予变量或作为参数传递给其它函数。函数作为参数传递在 jQuery 中是一个非常普遍的习惯。

Example 2.38. 以参数的方式传递一个匿名函数

var myFn = function(fn) {
    var result = fn();
    console.log(result);
};

myFn(function() { return 'hello world'; });   // logs 'hello world'

Example 2.39. 以参数的方式传递一个命名函数

var myFn = function(fn) {
    var result = fn();
    console.log(result);
};

var myOtherFn = function() {
    return 'hello world';
};

myFn(myOtherFn);   // logs 'hello world'

测试类型

JavaScript 提供了一个方法来测试变量类型。但是,其结果可能是令人困惑的 -- 比如,一个数组类型是 "object"。

当准备检测特定值的类型时,通常惯例是使用 typeof 运算符。

Example 2.40. 测试各种变量的类型

var myFunction = function() {
    console.log('hello');
};

var myObject = {
    foo : 'bar'
};

var myArray = [ 'a', 'b', 'c' ];

var myString = 'hello';

var myNumber = 3;

typeof myFunction;   // 返回 'function'
typeof myObject;     // 返回 'object'
typeof myArray;      // returns 'object' -- careful!
typeof myString;     // 返回 'string';
typeof myNumber;     // 返回 'number'

typeof null;         // returns 'object' -- careful!


if (myArray.push && myArray.slice && myArray.join) {
    // 可能是个数组
    // (这叫动态类型"duck typing")
}

if (Object.prototype.toString.call(myArray) === '[object Array]') {
    // 定义一个数组!
    // 这是一个被广泛验证过的可靠方法
    // to 判断一个特殊值是不是一个数组。
}

jQuery 提供了实用方法来帮助你检测一个任意值的类型。这些内容将在后面涉及。

作用域

"Scope" 引用的变量在指定时间内的一段代码中的可用性refers to the variables that are available to a piece of code at a given time. 一个不标准的作用域将导致令人沮丧的调试体验。

当使用 var 关键字描述函数中的一个变量时,它作为那个函数中的代码仅仅是个变量 -- 而函数外的代码不能访问这个变量。在其它方面,定义为 inside 的函数 will 能访问到所描述的变量。

此外,在函数里没有使用 var 关键字描述的变量对函数来讲不是局部的 -- JavaScript 将贯穿所有作用域直到 window 作用域以发现之前定义的变量位置。如果变量之前没有定义,它将创建一个全局变量,这会是一个意想不到的结果。

Example 2.41. 函数访问同一作用域内定义的变量

var foo = 'hello';

var sayHello = function() {
    console.log(foo);
};

sayHello();         // logs 'hello'
console.log(foo);   // also logs 'hello'

Example 2.42. 代码作用域外定义的变量不能访问该变量Code outside the scope in which a variable was defined does not have access to the variable

var sayHello = function() {
    var foo = 'hello';
    console.log(foo);
};

sayHello();         // logs 'hello'
console.log(foo);   // doesn't log anything

Example 2.43. 拥有相同名字的变量可以以不同的值存在不同的作用域中

var foo = 'world';

var sayHello = function() {
    var foo = 'hello';
    console.log(foo);
};

sayHello();         // logs 'hello'
console.log(foo);   // logs 'world'

Example 2.44. 函数定义后可看见变量值的改变

var myFunction = function() {
    var foo = 'hello';

    var myFn = function() {
        console.log(foo);
    };

    foo = 'world';

    return myFn;
};

var f = myFunction();
f();  // logs 'world' -- uh oh

Example 2.45. Scope insanity

// 一个自执行的匿名函数
(function() {
    var baz = 1;
    var bim = function() { alert(baz); };
    bar = function() { alert(baz); };
})();

console.log(baz);  // baz 在函数外没有定义

bar();  // bar 在匿名函数外被定义 
        // 因为它没有描述为var;而且,
        // 因为它是作为 baz 在同一作用域中被定义的,
        // 它能访问 baz 即使其它代码
        // 在函数之外 

bim();  // bim 没有在匿名函数外定义,
        // 于是其结果将是一个错误

闭包

闭包是作用域概念的一个扩展 — 函数能访问函数创建时作用域的变量functions have access to variables that were available in the scope where the function was created. 如果这很困惑,不要担心:通过例子你能更好的理解闭包。

在 Example 2.44, “函数定义后可看见变量值的改变” 我们了解到函数是如何访问到改变的变量值we saw how functions have access to changing variable values. 这种行为同样存在于循环的函数定义中 -- The same sort of behavior exists with functions defined within loops -- 函数观察到变量在函数定义后的改变,产生5次点击警告。the function "sees" the change in the variable's value even after the function is defined, resulting in all clicks alerting 5.

Example 2.46. 如何锁定i的值?

/* this won't behave as we want it to; */
/* every click will alert 5 */
for (var i=0; i<5; i++) {
    $('

click me

').appendTo('body').click(function() { alert(i); }); }

Example 2.47. 以一个闭包的方式锁定i的值

/* fix: “close” the value of i inside createFunction, so it won't change */
var createFunction = function(i) {
    return function() { alert(i); };
};

for (var i=0; i<5; i++) {
    $('

click me

').appendTo('body').click(createFunction(i)); }

Part II. jQuery: 基础概念

Chapter 3. jQuery 基础

$(document).ready()

你不能安全的操作此文档,除非文档处于 “ready.” 状态 jQuery 会为你检测准备状态是否就绪; 代码包含的 $(document).ready() 只有在页面被 JavaScript 代码执行时才运行。

Example 3.1. A $(document).ready() block

$(document).ready(function() {
    console.log('ready!');
});

这是 $(document).ready() 的简写,那样你就可以不时查看它; 然而, 如果你使用jQuery并不是那样娴熟,我建议你最好别用它。

Example 3.2. $(document).ready() 简写

$(function() {
    console.log('ready!');
});

你也能传递一个命名函数到 $(document).ready() 用来替换匿名函数的传递。

Example 3.3. 用命名函数替代匿名函数传递

function readyFn() {
    // 代码在文档准备好后就运行
}


$(document).ready(readyFn);

选择元素

这是 jQuery 最基础的概念,意思是 “选择一些元素然后通过它们做一些事” 除一些非标准的选择器外,jQuery 支持大部分的 CSS3 选择器。若要了解完整的选择器参考, 请访问http://api.jquery.com/category/selectors/.

以下是一些通用选择技术的例子

Example 3.4. 通过ID选择元素

$('#myId'); // 每一页ID都必须是唯一的

Example 3.5. 通过类名选择元素

$('div.myClass'); // 如果指定元素类型性能将得以提升

Example 3.6. 通过属性选择元素

$('input[name=first_name]'); // 当心,这可能会非常慢

Example 3.7. 通过组合CSS选择器选择元素

$('#contents ul.people li');

Example 3.8. 伪选择器

$('a.external:first'); 
$('tr:odd');
$('#myForm :input');   // 在一个form中选择所有的输入项
$('div:visible');
$('div:gt(2)');        // 除去1,3之外的所有项 
$('div:animated');     // 所有当前项动态区分 all currently animated divs

Note

当你使用 :visible 和 :hidden 伪选择器时, jQuery 会测试元素的真实可见性, 而不是它的CSS的可见性或显示 — 就是说, 如果physical height and width on the page 都大于零,它就可以看见. 然而,这个测试不能与  元素一起工作; 在这种情况下, jQuery 检测 CSS display 属性, 如果 它的 display 属性被设置成none 那就认为这个元素将隐藏。 即使 CSS 将影响它们的视觉渲染,元素也不会被添加到被隐藏的DOM中。 (请看这一章的后面操作小节有关如何创建和增加元素到DOM中的介绍。)

作为参考, 这里的jQuery代码被用于检测此元素是显示还是隐藏,为了清楚也添加了注释:

jQuery.expr.filters.hidden = function( elem ) {
    var width = elem.offsetWidth, height = elem.offsetHeight,
        skip = elem.nodeName.toLowerCase() === "tr";

    // 元素的高度为0,宽度为0, 
    // 并且它不是 ?
    return width === 0 && height === 0 && !skip ?

        // 所以它必须隐藏
        true :

        // 但是如果它拥有高度和宽度值 
        // 并且它不是 
        width > 0 && height > 0 && !skip ?

            // 所以它必须显示
            false :

            // 如果我们到了这,元素拥有宽度
            // 和高度, 但它也是一个 ,
            // 所以检查显示属性以
            // 确定是否隐藏
            jQuery.curCSS(elem, "display") === "none";
};

jQuery.expr.filters.visible = function( elem ) {
    return !jQuery.expr.filters.hidden( elem );
};

做包含任何元素的选择器?

一旦你已经指定一个选择器,你将希望知道它是否正常工作。你可能倾向于这样做:

if ($('div.foo')) { ... }

这不会工作的。当你使用 $() 指定一个选择器,一个对象将返回,对象也将计算为 true。 即使你的选择器没有包含任何元素,包含 if 语句的代码仍将执行。

相反,你需要测试选择器的长度属性,并告诉你包含了多少元素。如果回答是 0, 当以布尔值使用时候起长度属性将被赋予 false // 当长度属性作为布尔值时它的计算值将为 false。

Example 3.9. 测试选择器是否包含多个元素

if ($('div.foo').length) { ... }

保留的选择器

每次你指定了一个选择器,一段代码运行,jQuery 都不会为你做任何的 caching 工作。如果你已经指定了选择器而你又需要重新指定它时,它将在变量中保存选择器,而不是反复的指定它。

Example 3.10. 在变量中保存选择器

var $divs = $('div');

Note

在 Example 3.10, “在变量中保存选择器”, 变量名以一个美元符号开始。不像在其它的语言中,在 JavaScript 中没有特定的指定美元符号 -- 而是使用其它字符 。我们在这里使用它是为了表明变量包含一个 jQuery 对象。这是惯例 -- 一种 匈牙利命名法 -- 这仅仅是惯例,而不是强制性的。

一旦你保存了选择器,你就能在保存的变量中调用 jQuery 方法,就像在原来的选择器中调用一样。

Note

只有当你指定一个选择器后,选择器才会从页面取回元素。如果你添加元素到页面延迟了,你必须重新选择或将它们添加到存储在变量中的选择器中。当 DOM 改变时被保存的选择器不会自动更新。

改善 & 过滤选择器

有时你有一个选择器包含比此后的还要多;在这种情况下,你需要改善你的选择器。 jQuery 提供了多种方法用来校正你之后的精确 offers several methods for zeroing in on exactly what you're after.

Example 3.11. 改善选择器

$('div.foo').has('p');          // 包含lt;p> 的元素
$('h1').not('.bar');            // h1 元素被包含 bar 这个类
$('ul li').filter('.current');  // 当前类的所有无序项
$('ul li').first();             // 第一项
$('ul li').eq(5);               // 第六项 

选择Form元素

jQuery 提供了多个伪选择器帮助你发现表单中的元素;这些尤其有帮助,因为它能在使用标准CSS选择器的基于状态或类型的form元素中艰难区分these are especially helpful because it can be difficult to distinguish between form elements based on their state or type using standard CSS selectors.

:button

选择 

:checkbox

选择输入 type="checkbox" 类型

:checked

选择选中输入

:disabled

选择禁用表单元素

:enabled

选择启用表单元素

:file

选择 type="file" 输入类型

:image

选择 type="image" 输入类型

:input

选择