转自:http://www.uml.org.cn/AJAX/201307264.asp

写的不错,对我有很多帮助,最近准备全面的学习研究一下ES5,先转载一下这篇文章。

JavaScript函数

1.函数的定义

函数名称只能包含字母、数字、下划线或$,且不能以数字开头。定义时可用函数定义表达式或者函数声明语句。

var f = function fact(x){}

函数定义表达式包含名称,名称将作为函数的局部变量,在函数内部使用,代指函数。

函数声明语句不是真正的语句,不能出现在循环、条件、try/catch/finally以及with语句中;声明语句置于在不会执行到的位置,仍可被整个作用域可访问,可在被定义代码之前使用。定义表达式的变量声明被提前了,但是对变量赋值不会提前,函数在被定义之前无法使用,否则调用时会出现错误:"TypeError: undefined is not a function"

return语句没有一个与之相关的表达式,则它返回undefined值;如果一个函数不包含return语句,那它只执行函数体内语句,并返回undefined给调用者;没有返回值的函数,有时称为过程。

2.函数执行

函数执行的几种方式,当作函数、方法、构造函数、间接调用。如果构造函数没有形参,可以省略实参列表和圆括号,调用函数传实参有间隔时,可用null或undefined占位符替代空白的参数。

构造函数返回值情况

  1. function MyClass(name) {
  2. this.name = name;
  3. return name; // 构造函数的返回值?
  4. }
  5. var obj1 = new MyClass('foo'); // MyClass对象
  6. var obj2 = MyClass('foo'); // ‘foo’
  7. var obj3 = new MyClass({}); // {}
  8. var obj4 = MyClass({}); // {}

3.实参对象

实参对象是类数组对象,可用arguments.callee递归调用,如果你把参数命名为arguments,那么这个参数就会覆盖它原有的特殊变量。

4.函数的行参和实参

定义的函数括号内靠后面的形参没传入相应的实参,则默认值为undefined,有人利用这个,隐式定义函数内部的局部变量。函数传入参数的校验及抛出错误,函数中实参传入的是引用,函数内部对其操作,对外部是可见的。

  1. // 函数传参引用
  2. var oo = {x:1,y:2,get z(){    (----------- 这种写法,要研究下。)
  3. return 3;
  4. }}
  5. function fns(obj){
  6. obj.h = 4;
  7. }
  8. fns(oo);

5.函数属性、方法

函数也是对象,所以也有属性和方法,函数的length属性,函数形参的个数。

apply方法的第二个参数可以是数组或类数组对象。

bind方法是ES5中新增,将函数“绑定至”对象并传入一部分参数,传入的实参放在完整实参列表的左侧。

中文注释是本人添上去的,这个例子考虑到bind返回的函数被当成构造函数使用情况。

  1. /**
  2. * ES5.0支持bind函数,ES3.0不支持bind,这里在ES3中模拟实现,能应用于大部分场景,
  3. * 如有问题,欢迎一起探讨
  4. * https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
  5. */
  6. Function.prototype.bind || (Function.prototype.bind = function (that) {
  7. var target = this;
  8. // If IsCallable(func) is false, throw a TypeError exception.
  9. // 通过call、apply调用时,校验传入的上下文
  10. if (typeof target !== 'function') {
  11. throw new TypeError('Bind must be called on a function');
  12. }
  13. var boundArgs = slice.call(arguments, 1);
  14. function bound() {
  15. // 返回的bind函数被当构造函数
  16. if (this instanceof bound) {
  17. var self = createObject(target.prototype);
  18. var result = target.apply(
  19. self,
  20. boundArgs.concat(slice.call(arguments)));
  21. // Object(result) === result 判断调用返回是不是对象
  22. return Object(result) === result ? result : self;
  23. }
  24. // 返回的bind函数以一般函数形式调用
  25. else {
  26. return target.apply(
  27. that,
  28. boundArgs.concat(slice.call(arguments)));
  29. }
  30. }
  31. // NOTICE: The function.length is not writable.
  32. bound.length = Math.max(target.length - boundArgs.length, 0);
  33. return bound;
  34. });

6.高阶函数

如果函数作为参数或返回值使用时,就称为高阶函数。

7.作为命名空间的函数

函数命名空间暴露接口有以下几种方法:

  1. var mylib = (function (global) {
  2. function log(msg) {
  3. console.log(msg);
  4. }
  5. log1 = log; // 法一:利用没有var的变量声明的默认行为,在log1成为全局变量(不推荐)
  6. global.log2 = log; // 法二:直接在全局对象上添加log2属性,赋值为log函数(推荐)
  7. return {       // 法三:通过匿名函数返回值得到一系列接口函数集合对象,赋值给全局变量mylib(推荐)
  8. log: log
  9. };
  10. }(window));

8.自更新函数

  1. function selfUpdate() {
  2. window.selfUpdate = function() {
  3. alert('second run!');
  4. };
  5. alert('first run!');
  6. }
  7. selfUpdate(); // first run!
  8. selfUpdate(); // second run!

这种函数可以用于只运行一次的逻辑,在第一次运行之后就整个替换成一段新的逻辑。

9.函数书写规范

1) 函数参数定义的几种注释

  1. /*,...*/
  2. AP.reduce || (AP.reduce = function(fn /*, initial*/) {});
  3. getPropertyNames(o,/*optional*/a) // /*optional*/表示参数可选
  4. function arraycopy(/*array */ from,/*index*/from_start){};

2) 其它

  1. // bad
  2. function a() {
  3. test();
  4. console.log('doing stuff..');
  5. //..other stuff..
  6. var name = getName();
  7. if (name === 'test') {
  8. return false;
  9. }
  10. return name;
  11. }
  12.  
  13. // good
  14. function a() {
  15. var name = getName();// 定义变量放在前面
  16. test();
  17. console.log('doing stuff..');
  18. //..other stuff..
  19. if (name === 'test') {
  20. return false;
  21. }
  22. return name;
  23. }
  24.  
  25. // bad
  26. function a() {
  27. var name = getName();
  28. if (!arguments.length) {
  29. return false;
  30. }
  31. return true;
  32. }
  33.  
  34. // good
  35. function a() {
  36. if (!arguments.length) {// 参数校验放在前面
  37. return false;
  38. }
  39. var name = getName();
  40. return true;
  41. }

10.具有记忆功能的函数

  1. /**
  2. * 记忆函数
  3. */
  4. function memorize(f) {
  5. var cache = {};
  6. return function () {
  7. var key = arguments.length + '' + Array.prototype.join.call(arguments, ',');
  8. if (!(key in cache))
  9. cache[key] = f.apply(null, arguments);
  10. return cache[key];
  11. }
  12. }

JavaScript数组

1.稀疏数组

  1. var a1 = [,,,];
  2. var a2 = new Array(3);
  3. var a3 = [1,2,3];
  4.  
  5. console.log( 0 in a1);//false
  6. console.log( 0 in a2);//false
  7. console.log( 0 in a3);//true
  8.  
  9. delete a3[0];
  10. console.log( 0 in a3);//false

(这几个看着好神奇。)

2.数组元素的增减

length设置小于原值,删除溢出的;新增一数组元素,length始终元素序号+1。

push/pop在数组尾部操作,与a[a.length]赋值一样;可支持多参数。

unshift/shift在数组头部操作。

3.数组遍历

  1. if(!a[i])       //null/undefined/不存在的元素
  2. if(a[i]===undefined)
  3. if(!(i in a))    //不存在的元素

可用for in处理稀疏数组,不过数组不推荐用这个,比如能够枚举继承的属性名。

4.数组的校验和类数组

  1. Array.isArray = Array.isArray || function(o){
  2. return typeof o ==="object" &&
  3. Object.prototype.toString.call(o) === "[object Array]";
  4. }

类数组对象:可用针对真正数组遍历的代码来遍历;可用数组的通用方法。

  1. function isArrayLike(o){
  2. if(o &&
  3. typeof o ==='object' &&
  4. o.nodeType != 3 &&
  5. isFinite(o.length) &&
  6. o.length >= 0 &&
  7. o.length === Math.floor(o.length) &&
  8. o.length < 4294967296)
  9. return true;
  10. else
  11. return false;
  12. }

5.作为数组的字符串

在ES5(包括IE8)中,字符串行为类似只读数组。除了用charAt访问单个的字符外,还可以使用方括号。数组的通用方法可以用到字符串上。例如:

  1. s = "JavaScript"
  2. Array.prototype.join.call(s," ") // => "J a v a S c r i p t"
  3. Array.prototype.filter.call(s, // 过滤字符串中的字符
  4. function(x){
  5. return x.match(/[^aeiou]/); // 只匹配非元音字母
  6. }).join("");           // => "JvScrpt"

注意,字符串是只读的,如果使用修改调用数组的方法,会报错。譬如:push()、sort()、reverse()、splice()等数组方法。

6.ES3中数组支持的方法

concat()—结果返回、sort() 、reverse() 、join()—结果返回、slice()—结果返回、splice()、push()、pop()、unshift()、shift()、toString()、toLocaleString()

concat:返回一个新创建的数组,元素包含调用concat的原始数组的元素和concat的每个参数,如果这些参数中的任何一个自身是数组,则连接的数组的元素,而非数组本身。但要注意,concat不会递归扁平化数组的数组,也不会修改调用的数组。

7.数组的slice和splice方法

slice不改变原数组,截取原数组片段返回。索引从0开始,参数为正数时,第一个参数和不到第二个参数(从零算起,相对于索引)数组;参数为负数时,倒数第一个参数和倒数第二个参数的数组。

splice改变原数组。第一个参数(从零算起),插入或删除的起始位置,第二个参数:删除元素的个数,第三或其它任意参数,要插入的元素。

删除数组元素,保持数组连续,就用splice,返回的由删除元素组成的数组。复制数组的时候,请使用Array#slice。

  1. var len = items.length,
  2. itemsCopy = [],
  3. i;
  4.  
  5. // bad
  6. for (i = 0; i < len; i++) {
  7. itemsCopy[i] = items[i];
  8. }
  9.  
  10. // good
  11. itemsCopy = items.slice();

8.ES5中数组支持的方法

1)forEach()

  1. var data = [1,2,3,4,5];
  2. data.forEach(function(v,i,a){
  3. a[i] = v + 1;
  4. });

不能像for中使用break跳出循环,在forEach()传入参数的函数中抛出foreach.break异常。

  1. function foreach(a,f,t){ // a为数组,f为函数,t为函数f的执行环境
  2. try{
  3. a.forEach(f,t);
  4. } catch(e) {
  5. if( e === foreach.break)
  6. return;
  7. else
  8. throw e;
  9. }
  10. }
  11. foreach.break = new Error("StopIteration");

在ES3不支持forEach()可引入以下方法:

  1. Array.prototype.forEach || (Array.prototype.forEach = function(fn, context) {
  2. for (var i = 0, len = this.length >>> 0; i < len; i++) {
  3. if (i in this) {
  4. fn.call(context, this[i], i, this);
  5. }
  6. }
  7. });

2)map()

  1. a = [1,2,3];
  2. b = a.map(function(x){
  3. return x *x;
  4. });

传递的参数跟forEach()一样,不同的是map()调用的函数要有返回值。该函数返回新创建的数组,不修改调用的数组。

  1. Array.prototype.map = Array.prototype.map || function (callback, thisArg) {
  2. var T, A, k;
  3. if (this == null) {
  4. throw new TypeError(" this is null or not defined");
  5. }
  6.  
  7. // 1. 将O赋值为调用map方法的数组.
  8. var O = Object(this);
  9.  
  10. // 2.将len赋值为数组O的长度.
  11. var len = O.length >>> 0;
  12.  
  13. // 4.如果callback不是函数,则抛出TypeError异常.
  14. if ({}.toString.call(callback) != "[object Function]") {
  15. throw new TypeError(callback + " is not a function");
  16. }
  17.  
  18. // 5. 如果参数thisArg有值,则将T赋值为thisArg;否则T为undefined.
  19. if (thisArg) {
  20. T = thisArg;
  21. }
  22.  
  23. // 6. 创建新数组A,长度为原数组O长度len
  24. A = new Array(len);
  25.  
  26. // 7. 将k赋值为0
  27. k = 0;
  28.  
  29. // 8. 当 k < len 时,执行循环.
  30. while (k < len) {
  31. var kValue, mappedValue;
  32. //遍历O,k为原数组索引
  33. if (k in O) {
  34. //kValue为索引k对应的值.
  35. kValue = O[ k ];
  36. // 执行callback,this指向T,参数有三个.分别是kValue:值,k:索引,O:原数组.
  37. mappedValue = callback.call(T, kValue, k, O);
  38. // 返回值添加到新书组A中.
  39. A[ k ] = mappedValue;
  40. }
  41. // k自增1
  42. k++;
  43. }
  44.  
  45. // 9. 返回新数组A
  46. return A;
  47. };

3)filter()

调用和forEach一样,返回的数组元素是调用的数组的一个子集。

  1. a = [5,4,3,2,1];
  2.  
  3. smallvalues = a.filter(function(x){
  4. return x<3;
  5. });// [2,1]
  6.  
  7. everyother = a.filter(function(x,i){
  8. return i%2 ==0;
  9. });// [5,3,1]
  10.  
  11. // 跳过稀疏数组中缺少的元素,返回的数组总是稠密的
  12. var dense = sparse.filter(function(){
  13. return true;
  14. });
  15.  
  16. // 压缩空缺并删除undefined和null元素
  17. a = a.filter(function(x){
  18. return x !==undefined x != null;
  19. })

4)every()和some()

对数组进行逻辑判定,返回true或false;注意every()和some()确定该返回什么值它们就会停止遍历数组元素。

5)reduce()和reduceRight()

使用指定的函数将数组元素进行组合,生成单个值。这在函数式编程中是常见的操作,称为“注入”和“折叠”。reduce需要两个参数,第一个参数是执行化简的函数,函数的参数分别为:化简操作累计的结果或初始化值、数组元素、元素的索引、数组的本身;第二个参数(可选)是传递给函数的初始值。

  1. var a = [1,2,3,4,5];
  2. var sum = a.reduce(function(x,y){
  3. return x + y;
  4. },0);
  5. var product = a.reduce(function(x,y){
  6. return x * y;
  7. },1);
  8. var max = a.reduce(function(x,y){
  9. return x>y?x:y;
  10. });

reduceRight()的工作原理和reduce()一样,不同的是它按照数组索引从高到低(从右到左)处理数组。

6)indexOf()和lastIndexOf()

第一个参数代表要搜索的元素,第二个元素代表搜索的起始位置。可为负数,它代表相对数组末尾的偏移量,-1时,指定数组的最后一个元素。

  1. var a= [0,1,2,1,0];
  2. a.indexOf(1);   // => 1:a[1]是1
  3. a.lastIndexOf(1) // => 3:a[3]是1
  4. a.indexOf(3)   // =>-1: 没有值为3的元素
  5.  
  6. function findAll(a,x){
  7. var result = [],
  8. len = a.length,
  9. pos = 0;
  10.  
  11. while(pos<len){
  12. pos = a.indexOf(x,pos);
  13. if(pos === -1){
  14. break;
  15. }
  16. result.push(pos);
  17. pos++;
  18. }
  19. return result;
  20. }

字符串也有indexOf()和lastIndexOf()方法。

[转]JavaScript函数和数组总结的更多相关文章

  1. JavaScript函数和数组总结

    JavaScript函数 1.      函数的定义 函数名称只能包含字母.数字.下划线或$,且不能以数字开头.定义时可用函数定义表达式或者函数声明语句. var f = function fact( ...

  2. JavaScript 函数 伪数组 arguments

    一.函数 函数:函数就是将一些语言进行封装,然后通过调用的形式,执行这些语句. 函数的作用: 1.将大量重复的语句写在函数里,以后需要这些语句的时候,可以直接调用函数,避免重复劳动 2.简化编程,让变 ...

  3. javascript函数一共可分为五类: ·常规函数 ·数组函数 ·日期函数 ·数学函数 ·字符串函数

    javascript函数一共可分为五类:    ·常规函数    ·数组函数    ·日期函数    ·数学函数    ·字符串函数    1.常规函数    javascript常规函数包括以下9个 ...

  4. 思维导图(自己整理,希望对大家有用):JavaScript函数+canvas绘图+Array数组

    1.javascript函数: 2.Array数组: 3.canvas绘图:

  5. JavaScript回调函数及数组方法测试

    JavaScript回调函数及数组方法测试 具体代码如下: <!DOCTYPE html> <html lang="en"> <head> &l ...

  6. javascript之Array()数组函数讲解

    Array()是一个用来构建数组的内建构造器函数.数组主要由如下三种创建方式: array = new Array() array = new Array([size]) array = new Ar ...

  7. JavaScript函数、对象和数组

    一.JavaScript函数 1.定义函数:函数的通用语法如下 function function_name([parameter [, ...]]) { statements; } 由关键字func ...

  8. JavaScript权威设计--JavaScript函数(简要学习笔记十一)

    1.函数调用的四种方式 第三种:构造函数调用 如果构造函数调用在圆括号内包含一组实参列表,先计算这些实参表达式,然后传入函数内.这和函数调用和方法调用是一致的.但如果构造函数没有形参,JavaScri ...

  9. 前端开发:Javascript中的数组,常用方法解析

    前端开发:Javascript中的数组,常用方法解析 前言 Array是Javascript构成的一个重要的部分,它可以用来存储字符串.对象.函数.Number,它是非常强大的.因此深入了解Array ...

随机推荐

  1. A - Til the Cows Come Home

    裸的最短路,试一下刚看的spfa,虽然没有看代码,不过明白了大致的思想,先写一下试试吧,而且是个稀疏图,应该会很快吧. SPFA 算法采用图的存储结构是邻接表,方法是动态优化逼近法.算法中设立了一个先 ...

  2. hdoj 1711 Number Sequence【求字串在母串中第一次出现的位置】

    Number Sequence Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  3. 什么是method swizzling

    其实跟字面的意思很相近.方法的调和.可以去修改oc中两个方法的调用. 这张图看起来会比较形象 20130718230430859.png 就是把两个实现调换具体的做法,首先,用Categroy建立自己 ...

  4. java随机数与数组的使用。

    java随机数与数组的使用.    一:题目 二 代码:  public class Students {    int number;  // 学号    int State ;   // 年级   ...

  5. pull解析和sax解析的差别

    假设在一个XML文档中我们仅仅须要前面一部分数据.可是使用SAX方式或DOM方式会对整个文档进行解析,虽然XML文档中后面的大部分数据我们事实上都不须要解析.因此这样实际上就浪费了处理资源. 使用PU ...

  6. [置顶] 数据持久层(DAO)常用功能–通用API的实现

    在Web开发中,一般都分3层. Controller/Action 控制层, Service/Business 服务层/业务逻辑层, Dao 数据访问层/数据持久层. 在学习和工作的实践过程中,我发现 ...

  7. linux常用命令 http://mirrors.163.com/ubuntu-releases/12.04/

    由于记忆力有限,把平时常用的Linux命令整理出来,以便随时查阅: linux 基本命令 ls     (list 显示当前目录下文件和目录 ls -l 详细显示 =ll ) [root@linux ...

  8. 重新启动linux上的tomcat

    1.进入tomcat安装文件夹 2.cd bin 3../shutdown.sh 4../startup.sh

  9. Qt知识点、疑难杂症的治疗

    Q: QVariant 保存指针数据   A1: 1,使用QVariant::fromValue((void*)target)保存数据 2,使用(ShortcutItem*)(v.value<v ...

  10. DTD简单使用

    DTD:Document Type Definition DTD是一种简单的XML约束模式语言 DTD文档必须以utf-8或unicode编码 注释方式与HTML.XML文档相同 DTD文档的引用:紧 ...