[转]JavaScript函数和数组总结
转自: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占位符替代空白的参数。
构造函数返回值情况
- 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中数组支持的方法
1)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);
- }
- }
- });
2)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;
- };
3)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;
- })
4)every()和some()
对数组进行逻辑判定,返回true或false;注意every()和some()确定该返回什么值它们就会停止遍历数组元素。
5)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()一样,不同的是它按照数组索引从高到低(从右到左)处理数组。
6)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++;
- }
- return result;
- }
字符串也有indexOf()和lastIndexOf()方法。
[转]JavaScript函数和数组总结的更多相关文章
- JavaScript函数和数组总结
JavaScript函数 1. 函数的定义 函数名称只能包含字母.数字.下划线或$,且不能以数字开头.定义时可用函数定义表达式或者函数声明语句. var f = function fact( ...
- JavaScript 函数 伪数组 arguments
一.函数 函数:函数就是将一些语言进行封装,然后通过调用的形式,执行这些语句. 函数的作用: 1.将大量重复的语句写在函数里,以后需要这些语句的时候,可以直接调用函数,避免重复劳动 2.简化编程,让变 ...
- javascript函数一共可分为五类: ·常规函数 ·数组函数 ·日期函数 ·数学函数 ·字符串函数
javascript函数一共可分为五类: ·常规函数 ·数组函数 ·日期函数 ·数学函数 ·字符串函数 1.常规函数 javascript常规函数包括以下9个 ...
- 思维导图(自己整理,希望对大家有用):JavaScript函数+canvas绘图+Array数组
1.javascript函数: 2.Array数组: 3.canvas绘图:
- JavaScript回调函数及数组方法测试
JavaScript回调函数及数组方法测试 具体代码如下: <!DOCTYPE html> <html lang="en"> <head> &l ...
- javascript之Array()数组函数讲解
Array()是一个用来构建数组的内建构造器函数.数组主要由如下三种创建方式: array = new Array() array = new Array([size]) array = new Ar ...
- JavaScript函数、对象和数组
一.JavaScript函数 1.定义函数:函数的通用语法如下 function function_name([parameter [, ...]]) { statements; } 由关键字func ...
- JavaScript权威设计--JavaScript函数(简要学习笔记十一)
1.函数调用的四种方式 第三种:构造函数调用 如果构造函数调用在圆括号内包含一组实参列表,先计算这些实参表达式,然后传入函数内.这和函数调用和方法调用是一致的.但如果构造函数没有形参,JavaScri ...
- 前端开发:Javascript中的数组,常用方法解析
前端开发:Javascript中的数组,常用方法解析 前言 Array是Javascript构成的一个重要的部分,它可以用来存储字符串.对象.函数.Number,它是非常强大的.因此深入了解Array ...
随机推荐
- A - Til the Cows Come Home
裸的最短路,试一下刚看的spfa,虽然没有看代码,不过明白了大致的思想,先写一下试试吧,而且是个稀疏图,应该会很快吧. SPFA 算法采用图的存储结构是邻接表,方法是动态优化逼近法.算法中设立了一个先 ...
- hdoj 1711 Number Sequence【求字串在母串中第一次出现的位置】
Number Sequence Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- 什么是method swizzling
其实跟字面的意思很相近.方法的调和.可以去修改oc中两个方法的调用. 这张图看起来会比较形象 20130718230430859.png 就是把两个实现调换具体的做法,首先,用Categroy建立自己 ...
- java随机数与数组的使用。
java随机数与数组的使用. 一:题目 二 代码: public class Students { int number; // 学号 int State ; // 年级 ...
- pull解析和sax解析的差别
假设在一个XML文档中我们仅仅须要前面一部分数据.可是使用SAX方式或DOM方式会对整个文档进行解析,虽然XML文档中后面的大部分数据我们事实上都不须要解析.因此这样实际上就浪费了处理资源. 使用PU ...
- [置顶] 数据持久层(DAO)常用功能–通用API的实现
在Web开发中,一般都分3层. Controller/Action 控制层, Service/Business 服务层/业务逻辑层, Dao 数据访问层/数据持久层. 在学习和工作的实践过程中,我发现 ...
- linux常用命令 http://mirrors.163.com/ubuntu-releases/12.04/
由于记忆力有限,把平时常用的Linux命令整理出来,以便随时查阅: linux 基本命令 ls (list 显示当前目录下文件和目录 ls -l 详细显示 =ll ) [root@linux ...
- 重新启动linux上的tomcat
1.进入tomcat安装文件夹 2.cd bin 3../shutdown.sh 4../startup.sh
- Qt知识点、疑难杂症的治疗
Q: QVariant 保存指针数据 A1: 1,使用QVariant::fromValue((void*)target)保存数据 2,使用(ShortcutItem*)(v.value<v ...
- DTD简单使用
DTD:Document Type Definition DTD是一种简单的XML约束模式语言 DTD文档必须以utf-8或unicode编码 注释方式与HTML.XML文档相同 DTD文档的引用:紧 ...