1、数组编程
1.数组是值的有序集合。每一个值叫作一个元素,而每一个元素在数组中有一个位置,以数字表示,称为索引。JavaScript数组是无类型的:数组元素能够是任意类型,而且同一个数组中的不一样元素也可能有不一样的类型。数组的元素甚至也多是对象或其余数组,这容许建立复杂的数据结构,如对象的数组和数组的数组。JavaScript数组的索引是基于零的32位数值:第一个元素的索引为0,最大可能的索引为4294967294(232-2),数组最大能容纳4294967295个元素。数组
全部的索引都是属性名,但只有在0~232-2之间的整数属性名才是索引。全部的数组都是对象,能够为其建立任意名字的属性。但若是使用的属性是数组的索引,数组的特殊行为就是将根据须要更新它们的length属性值。
注意,可使用负数或非整数来索引数组。这种状况下,数值转换为字符串,字符串做为属性名来用。既然名字不是非负整数,它就只能当作常规的对象属性,而非数组的索引。一样,若是凑巧使用了是非负整数的字符串,它就当作数组索引,而非对象属性。当使用的一个浮点数和一个整数相等时状况也是同样的:数据结构
a[-1.23] = true; // 这将建立一个名为"-1.23"的属性 a["1000"] = 0; // 这是数组的第1001个元素 a[1.000] // 和a[1]相等
a = new Array(5); // 数组没有元素,可是a.length是5 a = []; // 建立一个空数组,length = 0 a[1000] = 0; // 赋值添加一个元素,可是设置length为1001
2.数组的实现是通过优化的,用数字索引来访问数组元素通常来讲比访问常规的对象属性要快不少。app
var isArray = Function.isArray || function(o){ return typeof o === "object" && Object.prototype.toString.call(o)=== "[object Array]"; };
3.indexOf()和lastIndexOf()方法不接收一个函数做为其参数。第一个参数是须要搜索的值,第二个参数是可选的:它指定数组中的一个索引,从那里开始搜索。若是省略该参数,indexOf()从头开始搜索,而lastIndexOf()从末尾开始搜索。第二个参数也能够是负数,它表明相对数组末尾的偏移量,对于splice()方法:例如,-1指定数组的最后一个元素。函数
4.reduce()时只有一个参数:没有指定初始值。当不指定初始值调用reduce()时,它将使用数组的第一个元素做为其初始值。这意味着第一次调用化简函数就使用了第一个和第二个数组元素做为其第一个和第二个参数优化
5.一旦every()和some()确认该返回什么值它们就会中止遍历数组元素。some()在断定函数第一次返回true后就返回true,但若是断定函数一直返回false,它将会遍历整个数组。every()刚好相反:它在断定函数第一次返回false后就返回false,但若是断定函数一直返回true,它将会遍历整个数组。注意,根据数学上的惯例,在空数组上调用时,every()返回true,some()返回false。ui
6.Array.sort()方法将数组中的元素排序并返回排序后的数组。当不带参数调用sort()时,数组元素以字母表顺序排序。若是数组包含undefined元素,它们会被排到数组的尾部。为了按照其余方式而非字母表顺序进行数组排序,必须给sort()方法传递一个比较函数。this
7.字符串是不可变值,故当把它们做为数组看待时,它们是只读的。如push()、sort()、reverse()和splice()等数组方法会修改数组,它们在字符串上是无效的。spa
2、函数prototype
1.函数声明语句的语法以下:
function funcname([arg1[, arg2[..., argn]]]){
statements
}
funcname是要声明的函数的名称的标识符。函数名以后的圆括号中是参数列表,参数之间使用逗号分隔。当调用函数时,这些标识符则指代传入函数的实参。
2.函数声明语句并不是真正的语句,ECMAScript规范只是容许它们做为顶级语句。它们能够出如今全局代码里,或者内嵌在其余函数中,但它们不能出如今循环、条件判断,或者try/cache/finally以及with语句中。注意,此限制仅适用于以语句声明形式定义的函数。函数定义表达式能够出如今JavaScript代码的任何地方。
3.一个典型的函数定义表达式包含关键字function,跟随其后的是一对圆括号,括号内是一个以逗号分割的列表,列表含有0个或多个标识符(参数名),而后再跟随一个由花括号包裹的JavaScript代码段(函数体),例如:
// 这个函数返回传入参数值的平方 var square = function(x){ return x * x; }
4.用于初始化一个新建立的对象的函数称为构造函数。构造函数的命名规则(首字母大写)和普通函数是如此不一样还有另一个缘由,构造函数调用和普通函数调用是不尽相同的。构造函数就是用来“构造新对象”的,它必须经过关键字new调用,若是将构造函数用作普通函数的话,每每不会正常工做。若是构造函数调用在圆括号内包含一组实参列表,先计算这些实参表达式,而后传入函数内,这和函数调用和方法调用是一致的。但若是构造函数没有形参,JavaScript构造函数调用的语法是容许省略实参列表和圆括号的。凡是没有形参的构造函数调用均可以省略圆括号。
5.若是函数挂载在一个对象上,做为对象的一个属性,就称它为对象的方法。当经过这个对象来调用函数时,该对象就是这次调用的上下文(context),也就是该函数的this的值。一个方法无非是个保存在一个对象的属性里的JavaScript函数。
6.this是一个关键字,不是变量,也不是属性名。JavaScript的语法不容许给this赋值。和变量不一样,关键字this没有做用域的限制,嵌套的函数不会从调用它的函数中继承this。若是嵌套函数做为方法调用,其this的值指向调用它的对象。若是嵌套函数做为函数调用,其this值不是全局对象(非严格模式下)就是undefined(严格模式下)。不少人误觉得调用嵌套函数时this会指向调用外层函数的上下文。若是你想访问这个外部函数的this值,须要将this的值保存在一个变量里,这个变量和内部函数都同在一个做用域内。一般使用变量self来保存this。
7.arguments.callee 表明函数名,多用于递归调用
8.大多数(非所有)的toString()方法的实现都返回函数的完整源码。内置函数每每返回一个相似“[native code]”的字符串做为函数体。
9.不彻底函数编程是一种函数编程技巧,即把一次完整的函数调用拆成屡次函数调用,每次传入的参数都是完成参数的一部分,每次才分开的函数就叫作不彻底函数。每次函数调用就叫作不彻底调用。
10.
(function(){ // mymodule()函数重写为匿名的函数表达式 // 模块代码 }()); // 结束函数定义并当即调用它
这种定义匿名函数并当即在单个表达式中调用它的写法很是常见,已经成为一种惯用法了。注意上面代码的圆括号的用法,function以前的左圆括号是必需的,由于若是不写这个左圆括号,JavaScript解释器会试图将关键字function解析为函数声明语句。使用圆括号JavaScript解释器才会正确地将其解析为函数定义表达式。使用圆括号是习惯用法,尽管有些时候没有必要也不该当省略。这里定义的函数会当即调用。
11.每一个JavaScript函数(ECMAScript 5中的Function.bind()方法返回的函数除外)都自动拥有一个prototype属性。这个属性的值是一个对象,这个对象包含惟一一个不可枚举属性constructor。constructor属性的值是一个函数对象:
var F = function(){}; // 这是一个函数对象 var p = F.prototype; // 这是F相关联的原型对象 var c = p.constructor; // 这是与原型相关联的函数 c === F // => true: 对于任意函数F.prototype.constructor==F
能够看到构造函数的原型中存在预先定义好的constructor属性,这意味着对象一般继承的constructor均指代它们的构造函数。因为构造函数是类的“公共标识”,所以这个constructor属性为对象提供了类。
var o = new F(); //建立类F的一个对象 o.constructor === F // => true,constructor属性指代这个类
12.构造函数是类的公有标识。在JavaScript中也能够定义对象的类,让每一个对象都共享某些属性,这种“共享”的特性是很是有用的。类的成员或实例都包含一些属性,用以存放或定义它们的状态,其中有些属性定义了它们的行为(一般称为方法)。这些行为一般是由类定义的,并且为全部实例所共享。例如,假设有一个名为Complex的类用来表示复数,同时还定义了一些复数运算。一个Complex实例应当包含复数的实部和虚部(状态),一样Complex类还会定义复数的加法和乘法操做(行为)。在JavaScript中,类的实现是基于其原型继承机制的。若是两个实例都从同一个原型对象上继承了属性,咱们说它们是同一个类的实例。
13.判断是不是函数
function isFunction(x){ return Object.prototype.toString.call(x)=== "[object Function]"; }
14.bind
var sum = function(x,y){ return x + y }; //返回两个实参的和值 // 建立一个相似sum的新函数,但this的值绑定到null // 而且第一个参数绑定到1,这个新的函数指望只传入一个实参 var succ = sum.bind(null, 1); succ(2)// => 3: x绑定到1,并传入2做为实参y function f(y,z){ return this.x + y + z }; //另一个作累加计算的函数 var g = f.bind({x:1}, 2); //绑定this和y g(3) // => 6: this.x绑定到1,y绑定到2,z绑定到3
if(!Function.prototype.bind){ Function.prototype.bind = function(o /*, args */){ // 将this和arguments的值保存至变量中 // 以便在后面嵌套的函数中可使用它们 var self = this, boundArgs = arguments; // bind()方法的返回值是一个函数 return function(){ // 建立一个实参列表,将传入bind()的第二个及后续的实参都传入这个函数 var args = [], i; for(i = 1; i < boundArgs.length; i++)args.push(boundArgs[i]); for(i = 0; i < arguments.length; i++)args.push(arguments[i]); // 如今将self做为o的方法来调用,传入这些实参 return self.apply(o, args); }; }; }
15.try/catch语句已经可使用多catch从句了,在catch从句的参数中加入关键字if以及一个条件判断表达式:
try { // 这里可能会抛出多种类型的异常 throw 1; } catch(e if e instanceof ReferenceError){ // 这里处理引用错误 } catch(e if e === "quit"){ // 这里处理抛出的字符串是"quit"的状况 } catch(e if typeof e === "string"){ // 处理其余字符串的状况 } catch(e){ // 处理余下的异常状况 } finally { // finally从句正常执行 }
16.若是函数只计算一个表达式并返回它的值,关键字return和花括号均可以省略
let succ=function(x)x+1, yes=function()true, no=function()false;
17.内联命名函数
var func1 = function func2(){ console.log(func1 === func2) } func1() // true func2() // Uncaught ReferenceError: func2 is not defined
尽管能够给内联函数进行命名,但这些名称只能在自身函数内部可见。内联函数的名称和变量名称有点像,它们的做用域仅限于声明它们的函数。