JavaScript函數和數組總結


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.

    // 通過callapply調用時,校驗傳入的上下文

    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.      數組slicesplice方法

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;否則Tundefined.

    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;

});

// 壓縮空缺並刪除undefinednull元素

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
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM