JavaScript函数

1.      函数的定义

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

var f = function fact(x){}

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

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

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

2.      函数执行

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

构造函数返回值情况

function MyClass(name) {
  this.name = name;
  return name;  // 构造函数的返回值?
}
 
var obj1 = new MyClass('foo');// MyClass对象
var obj2 = MyClass('foo');// ‘foo’
var obj3 = new MyClass({});// {}

var obj4 = MyClass({});// {}

3.      实参对象

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

4.      函数的形参和实参

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

// 函数传参引用

var oo = {x:1,y:2,get z(){

return 3;

}}

function fns(obj){

obj.h = 4;

}

fns(oo);

5.      函数属性、方法

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

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

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

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

/**

* ES5.0支持bind函数,ES3.0不支持bind,这里在ES3中模拟实现,能应用于大部分场景,

* 如有问题,欢迎一起探讨

* https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

*/

Function.prototype.bind || (Function.prototype.bind = function (that) {

var target = this;

// If IsCallable(func) is false, throw a TypeError exception.

// 通过call、apply调用时,校验传入的上下文

if (typeof target !== 'function') {

throw new TypeError('Bind must be called on a function');

}

var boundArgs = slice.call(arguments, 1);

function bound() {

// 返回的bind函数被当构造函数

if (this instanceof bound) {

var self = createObject(target.prototype);

var result = target.apply(

self,

boundArgs.concat(slice.call(arguments)));

// Object(result) === result 判断调用返回是不是对象

return Object(result) === result ? result : self;

}

// 返回的bind函数以一般函数形式调用

else {

return target.apply(

that,

boundArgs.concat(slice.call(arguments)));

}

}

// NOTICE: The function.length is not writable.

bound.length = Math.max(target.length - boundArgs.length, 0);

return bound;

});

6.      高阶函数

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

7.      作为命名空间的函数

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

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

8.      自更新函数

function selfUpdate() {
  window.selfUpdate = function() {
    alert('second run!');
  };
 
  alert('first run!');
}
 
selfUpdate(); // first run!
selfUpdate(); // second run!

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

9.      函数书写规范

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

/*,...*/

AP.reduce || (AP.reduce = function(fn /*, initial*/) {

getPropertyNames(o,/*optional*/a) // /*optional*/表示参数可选

function arraycopy(/*array */ from,/*index*/from_start){};

2)        其它

// bad

function a() {

test();

console.log('doing stuff..');

//..other stuff..

var name = getName();

if (name === 'test') {

return false;

}

return name;

}

// good

function a() {

var name = getName();// 定义变量放在前面

test();

console.log('doing stuff..');

//..other stuff..

if (name === 'test') {

return false;

}

return name;

}

// bad

function a() {

var name = getName();

if (!arguments.length) {

return false;

}

return true;

}

// good

function a() {

if (!arguments.length) {// 参数校验放在前面

return false;

}

var name = getName();

return true;

}

10.              具有记忆功能的函数

/**

*  记忆函数

*/

function memorize(f) {

var cache = {};

return function () {

var key = arguments.length + '' + Array.prototype.join.call(arguments, ',');

if (!(key in cache))

cache[key] = f.apply(null, arguments);

return cache[key];

}

}

JavaScript数组

1.      稀疏数组

var a1 = [,,,];

var a2 = new Array(3);

var a3 = [1,2,3];

console.log( 0 in a1);//false

console.log( 0 in a2);//false

console.log( 0 in a3);//true

delete a3[0];

console.log( 0 in a3);//false

2.      数组元素的增减

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

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

unshift/shift在数组头部操作。

3.      数组遍历

if(!a(i))//null/undefined/不存在的元素

if(a(i)===undefined)

if(!(i in a))//不存在的元素

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

4.      数组的校验和类数组

Array.isArray = Array.isArray || function(o){

return typeof o ==="object" &&

Object.prototype.toString.call(o) === "[object Array]";

}

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

function isArrayLike(o){

if(o &&

typeof o ==='object' &&

o.nodeType != 3 &&

isFinite(o.length) &&

o.length >= 0 &&

o.length === Math.floor(o.length) &&

o.length < 4294967296)

return true;

else

return false;

}

5.      作为数组的字符串

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

s = "JavaScript"

Array.prototype.join.call(s," ")    // => "J a v a S c r i p t"

Array.prototype.filter.call(s,  // 过滤字符串中的字符

function(x){

return x.match(/[^aeiou]/); // 只匹配非元音字母

}).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。

var len = items.length,

itemsCopy = [],

i;

// bad

for (i = 0; i < len; i++) {

itemsCopy[i] = items[i];

}

// good

itemsCopy = items.slice();

8.      ES5中数组支持的方法

forEach()、map()、filter()、every()和some()、reduce()和reduceRigth()、indexOf()和lastIndexOf()。

Ø        forEach()

var data = [1,2,3,4,5];

data.forEach(function(v,i,a){

a[i] = v + 1;

})

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

function foreach(a,f,t){// a为数组,f为函数,t为函数f的执行环境

try{

a.forEach(f,t);

} catch(e) {

if( e === foreach.break)

return;

else

throw e;

}

}

foreach.break = new Error("StopIteration");

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

Array.prototype.forEach || (Array.prototype.forEach = function(fn, context) {

for (var i = 0, len = this.length >>> 0; i < len; i++) {

if (i in this) {

fn.call(context, this[i], i, this);

}

}

});

Ø        map()

a = [1,2,3];

b = a.map(function(x){

return x *x;

});

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

Array.prototype.map = Array.prototype.map || function (callback, thisArg) {

var T, A, k;

if (this == null) {

throw new TypeError(" this is null or not defined");

}

// 1. 将O赋值为调用map方法的数组.

var O = Object(this);

// 2.将len赋值为数组O的长度.

var len = O.length >>> 0;

// 4.如果callback不是函数,则抛出TypeError异常.

if ({}.toString.call(callback) != "[object Function]") {

throw new TypeError(callback + " is not a function");

}

// 5. 如果参数thisArg有值,则将T赋值为thisArg;否则T为undefined.

if (thisArg) {

T = thisArg;

}

// 6. 创建新数组A,长度为原数组O长度len

A = new Array(len);

// 7. 将k赋值为0

k = 0;

// 8. 当 k < len 时,执行循环.

while (k < len) {

var kValue, mappedValue;

//遍历O,k为原数组索引

if (k in O) {

//kValue为索引k对应的值.

kValue = O[ k ];

// 执行callback,this指向T,参数有三个.分别是kValue:值,k:索引,O:原数组.

mappedValue = callback.call(T, kValue, k, O);

// 返回值添加到新书组A中.

A[ k ] = mappedValue;

}

// k自增1

k++;

}

// 9. 返回新数组A

return A;

};

Ø        filter()

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

a = [5,4,3,2,1];

smallvalues = a.filter(function(x){

return x<3;

});// [2,1]

everyother = a.filter(function(x,i){

return i%2 ==0;

});// [5,3,1]

// 跳过稀疏数组中缺少的元素,返回的数组总是稠密的

var dense = sparse.filter(function(){

return true;

});

// 压缩空缺并删除undefined和null元素

a = a.filter(function(x){

return x !==undefined x != null;

})

Ø        every()和some()

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

Ø        reduce()和reduceRight()

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

var a = [1,2,3,4,5];

var sum = a.reduce(function(x,y){

return x + y;

},0);

var product = a.reduce(function(x,y){

return x * y;

},1);

var max = a.reduce(function(x,y){

return x>y?x:y;

});

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

Ø        indexOf()和lastIndexOf()

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

var a= [0,1,2,1,0];

a.indexOf(1); // => 1:a[1]是1

a.lastIndexOf(1) // => 3:a[3]是1

a.indexOf(3) // =>-1: 没有值为3的元素

function findAll(a,x){

var result = [],

len = a.length,

pos = 0;

while(pos<len){

pos = a.indexOf(x,pos);

if(pos === -1){

break;

}

result.push(pos);

pos++;

}

}

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

本文首发:http://www.cnblogs.com/sprying/p/3192578.html

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

  1. [转]JavaScript函数和数组总结

    转自:http://www.uml.org.cn/AJAX/201307264.asp 写的不错,对我有很多帮助,最近准备全面的学习研究一下ES5,先转载一下这篇文章. JavaScript函数 1. ...

  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. [.net 多线程]ThreadPool的安全机制

    ThreadPool类,有两个方法我们没有用到,UnsafeQueueUserWorkItem 和UnsafeRegisterWaitForSingleObject. 为了完全理解这些方法,首先,我们 ...

  2. angular 第二种依赖注入

    import { Injectable } from '@angular/core'; import { ProductServiceService, Product } from './produc ...

  3. angular resolve路由

    import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from "@angular/router&q ...

  4. IEnumerable与IQueryable区别

    最近在使用MongoDB的时候,发现查询很慢,一个根据Id查询的语句竟然用了50秒,debug了一下,没发现什么大问题,但是另一个查询的语句只用了2秒,对比了一下,发现50s的那个语句使用的IEnum ...

  5. 快速了解“云原生”(Cloud Native)和前端开发的技术结合点

    欢迎访问网易云社区,了解更多网易技术产品运营经验. 后端视角,结合点就是通过前端流控缓解后端的压力,提升系统响应能力. 从一般意义理解,Cloud Native 是后端应用的事情,要搞的是系统解耦.横 ...

  6. 多线程《七》信号量,Event,定时器

    一 信号量 信号量也是一把锁,可以指定信号量为5,对比互斥锁同一时间只能有一个任务抢到锁去执行,信号量同一时间可以有5个任务拿到锁去执行,如果说互斥锁是合租房屋的人去抢一个厕所,那么信号量就相当于一群 ...

  7. 【大数据系统架构师】0.2 Linux基础

    1. Linux基本环境 1.1 大数据Hadoop前置大纲讲解 1)Linux系统,基本命令 2)Java语言,JavaSE相关知识 3)MySQL基本的DML和DDL 1.2 常见Linux系统. ...

  8. 【大数据系统架构师】0.3 MySQL数据库

    1. MySQL的基本操作 2. SQL语句 3. 高级查询 1)聚合函数.分组查询 2)联合查询.连接查询 3)子查询 4. 高级应用 1)视图与索引 2)数据可视化管理 5. 使用JDBC操作数据 ...

  9. php代码审计6审计xss漏洞

    跨站脚本攻击(Cross Site Scripting)是指攻击者利用网站程序对用户输入过滤不足,输入可以显示在页面上对其他用户造成影响的html代码,从而盗取用户资料,利用用户身份进行某种动作或者对 ...

  10. 【ARC080F】Prime Flip 差分+二分图匹配

    Description ​ 有无穷个硬币,初始有n个正面向上,其余均正面向下.  你每次可以选择一个奇质数p,并将连续p个硬币都翻转.  问最小操作次数使得所有硬币均正面向下. Input ​ 第一行 ...