• js函数和数组总结


    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返回的函数被当成构造函数使用情况。

    /**
    
     * 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中数组支持的方法

    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的执行环境

    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;
    
    };
    

    调用和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;
    
    })
    

    对数组进行逻辑判定,返回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()方法。

  • 相关阅读:
    线性表---顺序表&链表
    C++——虚函数表——typedef指向函数的指针
    C++——继承与多态
    C++——动态内存分配new--delete
    C++——模板---函数模板---类模板
    C++——指针---指向数组的指针---指向字符串的指针--指向函数的指针--指针的指针--指针的引用
    C++——this指针
    C++——运算符的重载---以成员函数方式重载---以友元函数方式重载
    C++——友元函数--友元类——friend关键字
    Ubuntu环境下实现WireShark抓取HTTPS
  • 原文地址:https://www.cnblogs.com/lxd564965917/p/6941761.html
Copyright © 2020-2023  润新知