JavaScript学习笔记【3】数组、函数、服务器端JavaScript概述
笔记来自《JavaScript权威指南(第六版)》
包含的内容:
- 数组
- 函数
- 服务器端JavaScript概述
数组
数组是动态的:根据需要它们会增长或缩减,并且在创建数组时无须声明一个固定的大小或在数组大小变化时无须重新分配空间。
数组可能是稀疏的:索引不一定要连续的,它们之间可以有空缺。
通常,数组的实现是经过优化的,用数字索引来访问数组元素一般来说比访问常规的对象属性要快很多。
数组继承自Array.prototype中的属性,它定义了一套丰富的数组操作方法。
如果省略数组直接量中的某个值,省略的元素将被赋予undefined值。
数组直接量的语法允许有可选的结尾的逗号,所以[,,]只有两个元素而非三个。
Array():另一种创建数组的方法,三种实现方式。
1、 var a = new Array(); // 等同于[]
2、 var a = new Array(10); //指定数组的长度,只分配空间,没有存储值、没有索引属性
3、 var a = new Array(1, 2, 3);
所有的索引都是属性名,但只有在0~232-2之间的整数属性名才是索引。
可以使用负数或非整数来索引数组,这种情况下,数组转换为字符串,字符串作为属性名来用。既然名字不是非负整数,它就只能当做常规的对象属性,而非数组的索引。
【图】数组索引特殊情况例子
数组索引仅仅是对象属性的一种特殊类型,数组没有“越界”错误的概念。当时图查询任何对象中不存在的属性,不会报错,只会得到undefined值。
设置length属性为一个小于当前长度的非负整数n时,当前数组中那些索引值大于或等于n的元素将从中删除。
添加数组元素最简单的方法:为新索引赋值。也可以用push()方法在数组末尾增加一个或多个元素。可以使用unshift()方法在数组的首部插入一个元素。
可以像删除对象属性一样,使用delete运算符来删除数组元素。不会修改数组的length属性。
pop()删除数组最后一个元素,并返回被删除的元素的值。shift()从数组头部删除一个元素,并将所有元素下移到比当前索引低1的地方。
splice()是一个通用的方法来插入、删除或替换数组元素。它会根据需要修改length属性并移动元素到更高或更低的索引处。
数组方法:
join():将数组中的所有元素都转化为字符串并连接在一起,返回最后生成的字符串。
reverse():将数组中的元素颠倒顺序,返回逆序的数组。
sort():将数组中的元素排序并返回排序后的数组。
concat():数组连接。
slice():返回指定数组的一个片段或子数组。
splice():在数组中插入或删除元素的通用方法。
push():在数组的尾部添加一个或多个元素,并返回数组的新长度。
pop():删除数组的最后一个元素,减少数组长度并返回它删除的值。
unshift()和shift():在数组的头部插入或删除元素。
toString()和toLocaleString():将每个元素转换为字符串,并且输出用逗号分隔的字符串列表。
forEach():从头到尾遍历数组,为每个元素调用指定的函数。
map():调用的数组的每个元素传递给指定的函数,并返回一个数组,它包含该函数的返回值。
filter():返回的数组元素是调用的数组的一个子集。
every()和some():数组的逻辑判定,它们对数组元素应用指定的函数进行判定,返回true或false。
reduce()和reduceRight():使用指定的函数将数组元素进行组合,生成单个值。
indexOf()和lastIndexOf():搜索整个数组中具有给定值的元素,返回找到的第一个元素的索引或者如果没有找到就返回-1。
在ECMAScript 5中,可以使用Array.isArray()函数来判断对象是否是数组。
【图】检测类数组对象
函数
如果函数挂载在一个对象上,作为对象的一个属性,就称它为对象的方法。
以表达式方式定义的函数,函数的名称是可选的。
var square = function(x) { return x * x;}
函数声明语句“被提前”到外部脚本或外部函数作用域的顶部,所以以这种方式声明的函数,可以被在它定义之前出现的代码所调用。以表达式方式定义的函数在定义之前无法调用。
如果函数不包含return语句,那它就只执行函数体中的每条语句,并返回undefined值给调用者。
非严格模式下调用的上下文(this的值)是全局变量,但是在严格模式下,调用上下文则是undefined。
// 判断是否为严格模式
var strict = (function) { return !this; }());
this是一个关键字,不是变量,也不是属性名。不允许给this赋值。
没有形参的构造函数调用都可以省略圆括号。
var o = newObject;
call()和apply()可以用来间接地调用函数。两个方法都允许显式指定调用所需的this值,也就是说,任何函数可以作为任何对象的方法来调用,哪怕这个函数不是那个对象的方法。
当调用函数的时候传入的实参比函数声明时指定的形参个数要少,剩下的形参都将设置为undefined值。
在函数体内,标识符arguments是指向实参对象的引用,实参对象是一个类数组对象,这样就可以通过数字下标就能访问传入函数的实参值,而不用非要通过名字来得到实参。
实参对象有一个重要的用处,就是让函数可以操作任意数量的实参。
通过实参名字来修改实参值的话,通过arguments[]数组也可以获取到更改后的值。
在非严格模式下,callee属性指代当前正在执行的函数。caller指代调用当前正在执行的函数的函数。通过caller属性可以访问调用栈。
函数不仅是一种语法,也是值,也就是说,可以将函数赋值给变量,存储在对象的属性或数组的元素中,作为参数传入另外一个函数等。
function square(x) { return x * x; }
var s = square;
s(4) // => 16
在函数中声明的变量在整个函数体内都是可见的(包括在嵌套的函数中),在函数的外部是不可见的。常常简单地定义一个函数用做临时的命名空间,在这个命名空间内定义的变量都不会污染到全局命名空间。
函数的执行依赖于变量作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的。为了实现这种词法作用域,函数对象的内部状态不仅包含函数的代码逻辑,还必须引用当前的作用域链。函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性称为“闭包”。
闭包就是能够读取其他函数内部变量的函数。
在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
闭包最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
使用闭包的注意点
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
【图】闭包例子
上面的checkscope()()将返回“global scope”。
将作用域链描述为一个对象列表,不是绑定的栈。每次调用函数的时候,都会为之创建一个新的对象用来保存局部变量,把这个对象添加至作用域链中。当函数返回的时候,就从作用域中将这个绑定变量的对象删除。如果不存在嵌套的函数,也没有其他引用指向这个绑定对象,它就会被当做垃圾回收掉。如果定义了嵌套的函数,每个嵌套的函数都各自对应一个作用域链,并且这个作用域链指向一个变量绑定对象。
在函数体里,arguments.length表示传入函数的实参的个数。arguments.callee.length表示期望传入的实参个数。
每一个函数都包含一个prototype属性,这个属性是指向一个对象的引用,这个对象称为“原型对象”。
bind()主要作用就是将函数绑定至某个对象。当在函数f()上调用bind()方法并传入一个对象o作为参数,这个方法将返回一个新的函数。调用新的函数将会把原始的函数f()当做o的方法来调用。
ECMAScript 5中的bind()的方法不仅仅是将函数绑定至一个对象,它还附带一些其他应用:除了第一个实参之外,传入bind()的实参也会绑定至this,这个附带的应用是一种常见的函数式编程技术,有时也被称为“柯里化”。
和对象一样,函数也有toString()方法,这个方法返回一个字符串,这个字符串和函数声明的语句相关。
也可以通过Function()构造函数来定义,比如:
var f = newFunction(“x”, “y”, “return x * y;”);
等价于
var f =function(x, y) { return x*y; }
可以传入任意数量的字符串实参,最后一个实参所表示的文本就是函数体。
Function()构造函数创建一个匿名函数。
“可调用的对象”是一个对象,可以在函数调用表达式中调用这个对象。所有的函数都是可调用的,但并非所有的可调用对象都是函数。
JavaScript并非函数式编程语言,但在JavaScript中可以像操控对象一样操控函数,也就是说可以应用函数式编程技术。
高阶函数就是操作函数的函数,它接收一个或多个函数作为参数,并返回一个新的函数。
可以将上次计算结果缓存起来,在函数式编程当中,这种缓存技巧叫做“记忆”。
服务器端JavaScript概述
Rhino是基于Java的JavaScript解析器,实现了通过JavaScript程序访问整个JavaAPI。
Node是Google的V8JavaScript解析器的一个特别版本,它是在底层绑定了POSIX(Unix)API,包括文件、进程、流和套接字等,并侧重于异步I/O、网络和HTTP。由于API是异步的,因此Node依赖事件处理程序,其通常使用嵌套函数和闭包来实现。
文档信息
- 版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0
- 最后修改时间:2014年06月01日 04:12
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。