对象类型
JavaScript提供了一些内建的数据类型。除此之外,网页文档虚拟类型,比如说选择器、增强的伪类,比如说事件和一些你需要知道的和函数有关的概念。如果你想深入学习这些概念,请阅读MDN。
你可以尝试下面的示例,只要把它们复制到你的浏览器的JavaScript控制台里(带开发目录激活的Chrome、Safari以及IE8.0以上版本)或者火狐浏览器Bug控制台。
每当一个示例提到一个类型默认值是一个布尔值时,如果使用布尔上下文很容易知道结果:
var x = ""; if ( x ) { console.log( "x defaulted to true" ); } else { console.log( "x defaulted to false" ); }
在这个案例中,打印出了"x defaulted to false"。
为了保持示例的简短,取反操作符("not")以及双重否定可以用来显示一个布尔上下文:
var x = ""; !x // true !!x // false (双重否定:因为"not(empty string)"是true,所以否定它导致false)
关于实际类型。
Anything(不定型)
虚拟类型Anything用在jQuery文档中,用来表示任何类型都可以使用,或者可以期望任何类型。
String(字符串)
在JavaScript中,string是一个没有变化的对象,包含0个、1个或者很多字符。
"I'm a String in JavaScript!" 'So am I!'
string的类型是“string”。
typeof "some string"; // "string"
引号
string可以用单引号或双引号来定义。您可以把单引号嵌套在双引号里面,或者以其它方式。要想用双引号定义带双引号的string(或者用单引号定义带单引号的string),嵌套的引号必须用反斜杠转义掉。
"You make 'me' sad." 'That\'s "cranking" good fun!' "<a href=\"home\">Home</a>"
内建的方法
JavaScript中的string具有一些内建的方法,用来操纵string,虽然结果通常是一个新string——但也有例外,比如说,split返回一个Array。
"hello".charAt( 0 ) // "h" "hello".toUpperCase() // "HELLO" "Hello".toLowerCase() // "hello" "hello".replace( /e|o/g, "x" ) // "hxllx" "1,2,3".split( "," ) // [ "1", "2", "3" ]
length属性
任何string都有一个length属性。
"Hello".length // 5 "".length // 0
布尔默认值
一个空string的默认值是false
!"" // true !!"" // false !"hello" // false !"true" // false !new Boolean( false ) // false
htmlString
当一个string用来代表一个或更多的DOM元素的时候,它被指定为jQuery文档中的htmlString,它通常是被创建出来插入到文档中。如果作为一个函数参数传递给jQuery()函数,如果该string以<tag ... >开头,它会被识别为HTML,并按此解析,直到遇到最后的>字符。在jQuery 1.9以前的版本中,一个string会如果它内部任何地方包含了<tag ... >,它就会被视为HTML。
如果一个string作为一个参数传递给一个操纵函数,比如说.append(),它总是会被视为HTML,只要jQuery的别的string常用解读(CSS选择器)不能应用在那个上下文中。
为了把string明确地解析成HTML,jQuery 1.8版以后可以使用一个$.parseHTML()方法。
// 追加<b>hello</b>: $( "<b>hello</b>" ).appendTo( "body" ); // 追加<b>hello</b>: $( "<b>hello</b>bye" ).appendTo( "body" ); // 句法错误,不能识别的表达式:bye<b>hello</b> $( "bye<b>hello</b>" ).appendTo( "body" ); // 追加bye<b>hello</b>: $( $.parseHTML( "bye<b>hello</b>" ) ).appendTo( "body" ); // 追加<b>hello</b>wait<b>bye</b>: $( "<b>hello</b>wait<b>bye</b>" ).appendTo( "body" );
Number(数字)
Number在JavaScript中是双精度64位格式的IEEE 754值。它们没有改变,就像string那样。所有的在基于C的语言中常用的操作符(+、-、*、/、%、=、+=、-=、*=、/=、++、--)都可以对number起作用。
12 3.543
number的类型是“number”。
typeof 12 // "number" typeof 3.543 // "number"
布尔默认值
如果一个number是0,它的默认值是false:
!0 // true !!0 // false !1 // false !-1 // false
因为number的编译器是双精度值,以下的结果不是一个错误:
0.1 + 0.2 // 0.30000000000000004
Math
JavaScript为操作Math对象中的number提供了一些实用工具:
Math.PI // 3.141592653589793 Math.cos( Math.PI ) // -1
解析数字
parseInt和parseFloat用来把string解析成number。如果基数没有指定,这两者都会做一些隐式转换:
parseInt( "123" ) = 123 // (隐式十进制) parseInt( "010" ) = 8 // (隐式八进制) parseInt( "0xCAFE" ) = 51966 // (隐式十六进制) parseInt( "010", 10 ) = 10 // (显式十进制) parseInt( "11", 2 ) = 3 // (显式二进制) parseFloat( "10.10" ) = 10.1
number转换成string
如果把number追加到string,结果就会是一个string。操作符是相同的,因此需要小心:如果你想加一个number然后把它们追加到一个string,请把number用小括号括起来:
"" + 1 + 2; // "12" "" + ( 1 + 2 ); // "3" "" + 0.0000001; // "1e-7" parseInt( 0.0000001 ); // 1 (!)
或者你可以使用JavaScript提供的String类,它会试图把一个值解析成一个string:
String( 1 ) + String( 2 ); // "12" String( 1 + 2 ); // "3"
NaN和Infinity
解析一些不是数字的值,会得到结果NaN。isNaN用来帮助人们侦测是否是那种情况:
parseInt( "hello", 10 ) // NaN isNaN( parseInt("hello", 10) ) // true
除以零就会得到Infinity:
1 / 0 // Infinity
无论是NaN还是Infinity,它们的类型都是“number”:
typeof NaN // "number" typeof Infinity // "number"
注意对比NaN的方式比较奇特:
NaN == NaN // false (!)
但是:
Infinity == Infinity // true
Integer(整型数)
一个integer是一种纯number类型,但是每当显式提到它时,表示它期待一个非浮点数。
Float(浮点数)
一个float是一种纯number类型,就像integer,但是每当显式提到它时,表示它期待是一个浮点数。
Boolean(布尔值)
JavaScript中的布尔值可以是true或false:
if ( true ) console.log( "always!" ); if ( false ) console.log( "never!" );
Object(对象)
虽然JavaScript中的任何东西都是一个对象,但是有些对象更客观。创建一个Object最简单的方法是用对象符号(花括号):
var x = {}; var y = { name: "Pete", age: 15 };
Object的类型是“object”:
typeof {} // "object"
点记号法
你可以用点记号法读写一个Object的属性。
y.name // "Pete" y.age // 15 x.name = y.name + " Pan" // "Pete Pan" x.age = y.age + 1 // 16
数组记号法
或者你可以用数组记号法读写它的属性,这种记号法允许你动态选择属性:
var operations = { increase: "++", decrease: "--" }; var operation = "increase"; operations[ operation ] // "++" operations[ "multiply" ] = "*"; // "*"
迭代
可以用for-in循环来轻松迭代一个Object:
var obj = { name: "Pete", age: 15 }; for( key in obj ) { alert( "key is " + [ key ] + ", value is " + obj[ key ] ); }
注意,利用扩展的Object.prototype(参见Object.prototype is verboten),for-in循环可能会被破坏掉,所以在使用别的库的时候要仔细。
jQuery为迭代一个Object的属性提供了一个each函数,它还可以迭代array的每个元素:
jQuery.each( obj, function( key, value ) { console.log( "key", key, "value", value ); });
缺点是,在每个值的上下文中调用回调函数的时候,你可能失去你自己的Object的上下文,如果有的话。在下面的function部分详细讨论它。
布尔默认值
一个Object,无论它是否有属性,默认值都不是false:
!{} // false !!{} // true
原型
所有的Object都有原型属性。每当一个编译器查找到一个属性的时候,如果Object本身上找不到这个属性的话,编译器也会检查这个Object的原型。jQuery普遍地使用原型来给jQuery实例添加方法。jQuery在内部制作了一个jQuery.fn方法,作为jQuery.prototype的别名,因此你可以任选一个使用(虽然插件开发员一般使用fn)。
var form = $("#myform"); console.log( form.clearForm ); // undefined // jQuery.fn == jQuery.prototype jQuery.fn.clearForm = function() { return this.find( ":input" ).each(function() { this.value = ""; }).end(); }; // 对jQuery对象的所有实例都起作用,因为 // 该新方法是添加到原型上的 console.log( form.clearForm ); // function form.clearForm();
Array(数组)
在JavaScript中,Array是一个变化的列表,带有一些内建的方法。你可以用数组符号(方括号)来定义一个array:
var x = []; var y = [ 1, 2, 3 ];
array的类型是“object”
typeof []; // "object" typeof [ 1, 2, 3 ]; // "object"
可以使用数组记号法来读写一个array:
x[ 0 ] = 1; y[ 2 ] // 3
迭代
一个array具有一个length属性,可以用来做迭代。
for ( var i = 0; i < a.length; i++ ) { // 对a[i]做些事情 }
当性能是至关重要的时候,如果读只读length属性一次,可以加快速度。这应该只有在发现了一个性能瓶颈使用:
for ( var i = 0, j = a.length; i < j; i++ ) { // 对a[i]做些事情 }
另一种定义一个变量的方式是对每次迭代做填充,从循环体中册除数组记号法。如果array只包含0或者是一个空字符串的时候,它就不会起作用:
for ( var i = 0, item; item = a[i]; i++ ) { // 对每个项目做些事情 }
jQuery为迭代array的元素提供了一个each函数,它也可以迭代Object的属性:
var x = [ 1, 2, 3 ]; jQuery.each( x, function( index, value ) { console.log( "index", index, "value", value ); });
缺点是,在每个值的上下文中调用回调函数的时候,你可能失去你自己的Object的上下文,如果有的话。在下面的function部分详细讨论它。
length属性也可以用来在一个array的末尾添加元素。这等同于使用push方法:
var x = []; x.push( 1 ); x[ x.length ] = 2; x // [ 1, 2 ]
在你了大量JavaScript代码就多次看到这两种方法。
其它内建方法是:reverse、join、shift、unshift、pop、slice、splice和sort:
var x = [ 0, 3, 1, 2 ]; x.reverse() // [ 2, 1, 3, 0 ] x.join(" – ") // "2 - 1 - 3 - 0" x.pop() // [ 2, 1, 3 ] x.unshift( -1 ) // [ -1, 2, 1, 3 ] x.shift() // [ 2, 1, 3 ] x.sort() // [ 1, 2, 3 ] x.splice( 1, 2 ) // [ 2, 3 ]
注意:在Internet Explorer中,.unshift()方法不能返回一个length属性:
布尔默认值
一个array,无论它是否有元素,都永远不会返回false:
![] // false !![] // true
Array<Type>记号法
在jQuery API中,你经常会看到array<Type>记号法:
dragPrevention Array<String>
这表示该方法不仅仅期待一个array作为参数,而且还指定了期待的类型。该记号法借用之Java 5的常用记号法(或者C++模板)。
Array-Like Object(类数组对象)
无论是一个真正的JavaScript数组,还是一个JavaScript对象,都包含了一个非负的整型数length属性,以及一个从0开始到length-1的index属性,后一种情况包含了类数组对象,常用在基于web的代码中看到,比如说,作为一个arguments对象和很多DOM方法返回的NodeList对象。
如果一个jQuery API既接受一个纯Object也接受一个类数组对象,一个带有数字化的length属性的纯Object将触发类数组行为。
PlainObject
PlainObject类型是一个JavaScript对象,它包含了零个或更多的键值对。换句话说,该纯对象,是一个Object对象。在jQuery文档中,纯对象是指区别于JavaScript其它类型的对象:举个例子,null、用户定义的数组、以及宿主对象,比如说document这些都有一个typeof值,为“object”。jQuery.isPlainObject()方法用来识别传递进来的参数是否是一个纯对象,演示如下:
var a = []; var d = document; var o = {}; typeof a; // object typeof d; // object typeof o; // object jQuery.isPlainObject( a ); // false jQuery.isPlainObject( d ); // false jQuery.isPlainObject( o ); // true
Date
Date类型是一个JavaScript对象,代表了一个时间点。Date对象是用它们的构造函数来实例化的,该构造函数默认创建一个代表当前时间的对象。
new Date();
要想为一个替代的日期和时间创建一个Date对象,需要按以下顺序传递数字参数:年、月、日、时、分、秒、毫秒还需要注意到,月份是从0开始的,而别的都是从1开始的。下面的代码创建了一个新的Date对象,代表2014年1月1日 8:15。
new Date( 2014, 0, 1, 8, 15 );
Function(函数)
在JavaScript中,函数可以是命名函数,也可以是匿名函数。任何函数都可以分配给一个变量,或者传递给一个方法,但是用这种方法传递成员函数,可能导致它们在另一个对象的上下文中被调用(例如,用不同的this对象)。
function named() {} var handler = function() {}
在jQuery代码中你会看到很多很多匿名函数:
$( document ).ready(function() {}); $( "a" ).click(function() {}); $.ajax({ url: "someurl.php", success: function() {} });
一个function的类型是“function”。
Arguments(参数)
在函数内总是可以使用一个特殊变量arguments。它近似于一个array,它具有length属性,但是它缺少array内建的方法。伪数组的元素是函数所调用的参数:
function log( x ) { console.log( typeof x, arguments.length ); } log(); // "undefined", 0 log( 1 ); // "number", 1 log( "1", "2", "3" ); // "string", 3
该arguments对象还有一个callee属性,它引用了那个函数。举个例子:
var awesome = function() { return arguments.callee; } awesome() == awesome // true
上下文、Call和Apply
在JavaScript中,变量this引用了当前上下文。默认情况下,this引用Window对象。在一个函数内部,上下文可以改变,取决于如何调用该函数。
在jQuery中,所有的事件处理函数都用调用它们时所处理的元素作为上下文:
$( document ).ready(function() { // this refers to window.document }); $( "a" ).click(function() { // this refers to an anchor DOM element });
你可以用函数内建方法call和apply为一个函数指定上下文。两者的区别在于它们如何传递参数。call把所有的参数传递给函数作为参数,arguments,与此同时,apply接受一个数组作为参数。
function scope() { console.log( this, arguments.length ); } scope() // window, 0 scope.call( "foobar", [ 1, 2 ] ); // "foobar", 1 scope.apply( "foobar", [ 1, 2 ] ); // "foobar", 2
作用域
在JavaScript中,所有的定义在函数内部的变量只能在函数作用域内可见。考虑以下示例:
// global var x = 0; (function() { // private var x = 1; console.log( x ); // 1 })(); console.log( x ); // 0
它在全局作用域内定义了一个变量x,然后定义了一个匿名函数并立即执行它(额外的小括号对立即执行来说是必不可少的)。在函数内部定义了另一个变量x,带有不同的值。它只在函数内部可见,不会覆盖全局变量。
闭包
每当一个定义在当前作用域之外的变量从某个内部作用域中访问时,就创建了一个闭包。在以下的示例中,变量counter在create、increment和print函数内部可见,但是不能在它们的外部可见。
function create() { var counter = 0; return { increment: function() { counter++; }, print: function() { console.log( counter ); } } } var c = create(); c.increment(); c.print(); // 1
该模式允许你创建一个对象,对象带有操作数据和方法,该方法不能在对象外部可见——这是面向对象编程的基础。
代理模式
结合上面的知识,给你作为JavaScript程序员很大的能力。结合它们的其中一种方法是在JavaScript中实现一个代理模式,启用面向方面编程(AOP)的基础:
(function() { // 记录所有对setArray的调用 var proxied = jQuery.fn.setArray; jQuery.fn.setArray = function() { console.log( this, arguments ); return proxied.apply( this, arguments ); }; })();
上面在一个函数中封闭它的代码以隐藏变量proxied。它把jQuery的setArray方法保存到一个闭包里,并重写它。然后该代理记录了所有对该方法的调用,并把该调用委托到原始对象。使用apply(this, arguments)保证了调用者不能够注意到原始对象和proxied方法之间的差异。
Callback(回调函数)
callback是一个纯JavaScript函数,传递给某些方法作为参数或者选项。某些callback就是事件,在触发某种状态的时候,调用它给用户一个反应的机会。jQuery的事件系统处处使用了这种回调函数:
$( "body" ).click(function( event ) { console.log( "clicked: " + event.target ); });
大多数回调函数都提供了参数和上下文。在事件处理函数事件中,调用回调函数只带一个参数,一个事件。上下文被设置为要处理的元素,在上面的示例中,是document.body。
有些回调函数必须返回一些东西,另一些回调函数的返回值是可有可无的。要想防止提交一个表单,submit事件处理函数可以返回false:
$( "#myform" ).submit(function() { return false; });
并非总是返回false,该回调函数会检查表单的字段的有效性哪表单无效时,返回false。
Selector(选择器)
在jQuery中,用一个selector从一个DOM文档中选择DOM元素。在大多数情况中,该文档,即出现在所有浏览器中的DOM文档,但也有可能是通过Ajax获得的XML文档。
选择器是CSS和自定义附加物的合成。在jQuery中所有可用的选择器列出在Selectors API 页面上。
在很多插件,以其他方式利用jQuery的选择器。该验证插件接受一个选择器以指定一个依赖性,即输入是否是必不可少的。
emailrules: { required: "#email:filled" }
如果用户在email字段中输入了一个电子邮箱地址,它将使一个名称为“emailrules”勾选框变成必填项,通过它的id选中它,通过有效性验证插件提供的自定义的选择器":filled"来筛选。
如果某个参数的类型被指定为选择器,它接受jQuery构造函数接受的一切选择器,例如,字符串、元素、元素列表。
Event(事件)
jQuery的事件系统根据W3C标准,规范化了event对象。该event对象保证会被传递给事件处理函数(不检查window.event必要)它规范化了target、relatedTarget、which、metaKey以及pageX和pageY属性,并提供了两个方法stopPropagation()和preventDefault()。
Event对象页列出了所有的属性,并配有示例。
文档对象模型(DOM)中的标准事件是:blur、 focus、 load、 resize、scroll、 unload、 beforeunload、 click、dblclick、 mousedown、mouseup、 mousemove、 mouseover、 mouseout、 mouseenter、 mouseleave、 change、 select、 submit、 keydown、 keypress和keyup。因为DOM事件名称为某些元素预定义了含义,不建议为别的目的使用它们。jQuery的事件模型可以用一个元素上的任一个名称触发一个事件,而且它会沿着DOM树向上冒泡,如果有DOM树的话。
Element(元素)
文档对象模型(DOM)中的元素具有元素属性、文本和子元素。它提供了一些方法,用来遍历父元素和子元素,并访问它们的元素属性。然而,因为DOM API规范文档和编译器的不一致性,这些方法用起来可能会是一个挑战。jQuery为那些元素提供了一个“包裹器”以帮助该DOM相互作用。但是有时候你还是需要直接操作元素,或者看到方法还接受DOM元素作为参数。
每当你调用jQuery的.each方法,或者在一个jQuery集合上调用它的事件方法之一,回调函数的上下文——this会被设为一个DOM元素。
DOM元素的有些属性在不同的浏览器中相当一致。考虑一下下面的一个简单的onblur验证的示例:
$( "input[type='text']" ).on( "blur", function() { if( !this.value ) { alert( "Please enter some text!" ); } });
你可以用$(this).val()来代替this.value,以通过jQuery访问文本输入框的值,但是这样的话,你也不会有什么收益。
jQuery
jQuery对象包含了一个文档对象模型(DOM)元素的集合,从一个HTMLString创建而来,或者从文档中选中。因为jQuery经常用CSS选择器从文档中匹配元素,所以在jQuery对象中的元素的集合经常被称为“匹配的元素”或者“选中的元素”。
jQuery对象本身的行为很像一个array;它有length属性,而且对象中的元素可以通过它们的数字索引号[0]到[length-1]来访问。注意,一个jQuery对象并不是一个实际的JavaScript数组对象,所以它不具有一个真实的Array对象的所有方法,比如说join()方法。
你会十分频繁地使用jQuery()函数来创建一个jQuery对象。jQuery()可以通过它的广为人知的单字符别名$()来访问,除非你已经调用jQuery.noConflict()禁用了这个选项。很多jQuery方法会返回jQuery对象本身,所以可以连缀调用那些方法:
任何调用返回jQuery的API,返回的值都会是原来的jQuery对象,除非API中已经有所说明。API方法,比如说.filter()或者.not()会修改它们进来的集合,并返回一个新的jQuery对象。
$( "p" ).css( "color", "red" ).find( ".special" ).css( "color", "green" );
每当你使用了一个“破坏性的”jQuery方法,可能改变jQuery对象中的元素集合,比如说.filter()或者.find(),这些方法实际上将返回一个带有结果元素的新jQuery对象。要想返回之前的jQuery对象,请使用.end()方法。
一个jQuery对象可能是空的,不包含DOM元素。你可以用$()来创建一个空的jQuery对象(也就是说不传递任何参数)。如果选择器没有选中任何元素,或者一个连缀方法筛选出了所有的元素,jQuery对象也有可能变成空的。它不是一个错误;在那种jQuery对象上调用任何方法都不会有任何效果,因为它们不对任何元素作操作。因此,在这个示例中,如果网页中没有坏项目,则没有元素会加红色:
$( ".badEntry" ).css({ color: "red" });
XMLHttpRequest
有些jQuery的Ajax函数会返回原生的XMLHttpRequest(XHR)对象,或者把它作为一个参数传递给success/error/complete处理函数。从而你可以对这个请求做额外的处理,或者监视这个请求。注意只有当一个XHR对象实际用在某个请求中时,Ajax函数才会返回或者传递这一个XHR对象。举个例子,JSONP请求和跨域GET请求使用了一个脚本元素,而不是使用了一个XHR对象。
虽然XHR对象是一个标准,但是在不同的浏览器上,它的行为中有很多变种。请参阅W3C网站以及浏览器的说明书以获得更多信息:
Google公司似乎并没有为Chrome浏览器的XHR做一个官方说明页。从v5版以来,Chrome不再支持使用针对XHR请求的文件协议。
jqXHR
从jQuery 1.5版以来,$.ajax()方法返回该jqXHR对象,它是XMLHTTPRequest对象的一个超级。欲知更多信息,请参阅$.ajax项目的jQXHR部分。
Deferred Object(延迟对象)
从jQuery 1.5版以来,该Deferred对象提供了一个方法,能把多个回调函数注册到一个自管理的回调队列中,以适当的方式调遣回调函数队列,并接力任何同步或异步函数的success或failure状态。
Promise Object(应答对象)
该对象提供了Deferred对象的方法的子集(then、done、fail、always、pipe、progress、state和promise以防止用户改变Deferred的状态。
Callbacks Object(回调函数对象)
一个多目的的对象,提供了一个管理回调函数列表的强大的方法。它支持添加回调函数、删除回调函数、引发回调函数、禁用回调函数。该Callbacks对象由$.Callbacks函数创建并返回,随后由大多数函数的方法返回。
XML Document
由XML DOM解析器创建的文档对象,通常来自一个代表XML的string。XML文档具有与HTML文档不同的语义,但是jQuery提供的大多数遍历和操纵方法会对它起作用。
Assert
对象的参考或者对象的实例支持所有的QUnit的断言。参见API documentation for QUnit.assert以了解详情。