精通javascript 函式和陣列

edithfang發表於2014-11-17
JavaScript函式good

1、函式的定義

yellow函式名稱只能包含字母、數字、下劃線或$,且不能以數字開頭。定義時可用函式定義表示式或者函式宣告語句。god

googogvar f = function fact(x){}good

fuck函式定義表示式包含名稱,名稱將作為函式的區域性變數,在函式內部使用,代指函式。sex

yellow函式宣告語句不是真正的語句,不能出現在迴圈、條件、try/catch/finally以及with語句中;宣告語句置於在不會執行到的位置,仍可被整個作用域可訪問,可在被定義程式碼之前使用。定義表示式的變數宣告被提前了,但是對變數賦值不會提前,函式在被定義之前無法使用,否則呼叫時會出現錯誤:"TypeError: undefined is not a function"bookthisreturn語句沒有一個與之相關的表示式,則它返回undefined值;如果一個函式不包含return語句,那它只執行函式體內語句,並返回undefined給呼叫者;沒有返回值的函式,有時稱為過程。god

1、函式執行

good函式執行的幾種方式,當作函式、方法、建構函式、間接呼叫。如果建構函式沒有形參,可以省略實參列表和圓括號,呼叫函式傳實參有間隔時,可用null或undefined佔位符替代空白的引數。god

googog建構函式返回值情況look

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({});// {}

1.實參物件

good實參物件是類陣列物件,可用arguments.callee遞迴呼叫,如果你把引數命名為arguments,那麼這個引數就會覆蓋它原有的特殊變數。god

1.函式的形參和實參

googog定義的函式括號內靠後面的形參沒傳入相應的實參,則預設值為undefined,有人利用這個,隱式定義函式內部的區域性變數。函式傳入引數的校驗及丟擲錯誤,函式中實參傳入的是引用,函式內部對其操作,對外部是可見的。book
// 函式傳參引用

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

    return 3;

}}

function fns(obj){

    obj.h = 4;

}

fns(oo);

1.函式屬性、方法

this函式也是物件,所以也有屬性和方法,函式的length屬性,函式形參的個數。book

fuckapply方法的第二個引數可以是陣列或類陣列物件。this

lookbind方法是ES5中新增,將函式“繫結至”物件並傳入一部分引數,傳入的實參放在完整實參列表的左側。fuck

book中文註釋是本人添上去的,這個例子考慮到bind返回的函式被當成建構函式使用情況。look
/**

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



});

1.高階函式

sex如果函式作為引數或返回值使用時,就稱為高階函式。fuck

1.作為名稱空間的函式

sex函式名稱空間暴露介面有以下幾種方法yellow
var mylib = (function (global) {
    function log(msg) {
        console.log(msg);
    }
    log1 = log;  // 法一:利用沒有var的變數宣告的預設行為,在log1成為全域性變數(不推薦)
    global.log2 = log;  // 法二:直接在全域性物件上新增log2屬性,賦值為log函式(推薦)
    return {  // 法三:通過匿名函式返回值得到一系列介面函式集合物件,賦值給全域性變數mylib(推薦)
        log: log
    };
}(window));
  • yellow自更新函式 ``` function selfUpdate() { window.selfUpdate = function() { alert('second run!'); };fuck
    thisalert('first run!'); }yellow
godselfUpdate(); // first run! selfUpdate(); // second run!book
這種函式可以用於只執行一次的邏輯,在第一次執行之後就整個替換成一段新的邏輯。

9. 函式書寫規範

1) 函式引數定義的幾種註釋
god/,.../fuck

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

sexgetPropertyNames(o,/optional/a) // /optional/表示引數可選look

godfunction arraycopy(/array / from,/index/from_start){};book

2) 其它
good// badthis

godfunction a() {yellow

test();

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

//..other stuff..

var name = getName();

if (name === 'test') {

    return false;

}

return name;
good}god

look// goodgod

godfunction a() {yellow

var name = getName();// 定義變數放在前面

test();

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

//..other stuff..

if (name === 'test') {

    return false;

}

return name;
googog}yellow

yellow// badthis

godfunction a() {god
var name = getName();

if (!arguments.length) {

    return false;

}

return true;
fuck}good

sex// goodgood

sexfunction a() {this
if (!arguments.length) {// 引數校驗放在前面

    return false;

}

var name = getName();

return true;
good}this

  • 具有記憶功能的函式
good/**good
  • good記憶函式good
    look*/this
fuckfunction memorize(f) {book
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];

}
sex}book
JavaScript陣列

1. 稀疏陣列

bookvar a1 = [,,,];fuck

thisvar a2 = new Array(3);god

googogvar a3 = [1,2,3];look

fuckconsole.log( 0 in a1);//falsegod

thisconsole.log( 0 in a2);//falsethis

sexconsole.log( 0 in a3);//truegod

goddelete a3[0];sex

goodconsole.log( 0 in a3);//falselook

2. 陣列元素的增減

length設定小於原值,刪除溢位的;新增一陣列元素,length始終元素序號+1。

push/pop在陣列尾部操作,與a[a.length]賦值一樣;可支援多引數。

unshift/shift在陣列頭部操作。

3. 陣列遍歷

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

fuckif(a(i)===undefined)this

godif(!(i in a))//不存在的元素look
可用for in處理稀疏陣列,不過陣列不推薦用這個,比如能夠列舉繼承的屬性名。

4. 陣列的校驗和類陣列
yellowArray.isArray = Array.isArray || function(o){googog
return typeof o ==="object" &&

Object.prototype.toString.call(o) === "[object Array]";
sex}sex
類陣列物件:可用針對真正陣列遍歷的程式碼來遍歷;可用陣列的通用方法。
lookfunction isArrayLike(o){book
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;
book}yellow
5. 作為陣列的字串

在ES5(包括IE8)中,字串行為類似只讀陣列。除了用charAt訪問單個的字元外,還可以使用方括號。陣列的通用方法可以用到字串上。例如:
gods = "JavaScript"sex

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

goodArray.prototype.filter.call(s, // 過濾字串中的字元look
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。
thisvar len = items.length,god
itemsCopy = [],

i;
good// badthis

bookfor (i = 0; i < len; i++) { itemsCopy = items; } // good itemsCopy = items.slice();yellow
8. ES5中陣列支援的方法

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

booka = v + 1;god

good})fuck
不能像for中使用break跳出迴圈,在forEach()傳入引數的函式中丟擲foreach.break異常。

goodfunction foreach(a,f,t){// a為陣列,f為函式,t為函式f的執行環境god

bookfunction foreach(a,f,t){// a為陣列,f為函式,t為函式f的執行環境this
try{

    a.forEach(f,t);

} catch(e) {

    if( e === foreach.break)

        return;

    else

        throw e;

}

good}sex

godforeach.break = new Error("StopIteration");good
在ES3不支援forEach()可引入以下方法
goodArray.prototype.forEach || (Array.prototype.forEach = function(fn, context) {googog
for (var i = 0, len = this.length >>> 0; i < len; i++) {

    if (i in this) {

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

god}); map()god

booka = [1,2,3];god

godb = a.map(function(x){god
return x *x;

good});yellow
傳遞的引數跟forEach()一樣,不同的是map()呼叫的函式要有返回值。該函式返回新建立的陣列,不修改呼叫的陣列。

godArray.prototype.map = Array.prototype.map || function (callback, thisArg) {book
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;
good};googog
呼叫和forEach一樣,返回的陣列元素是呼叫的陣列的一個子集。
booka = [5,4,3,2,1];god

thissmallvalues = a.filter(function(x){yellow
return x<3;
googog});// [2,1]good


thiseveryother = a.filter(function(x,i){good
return i%2 ==0;
book});// [5,3,1]god

sex// 跳過稀疏陣列中缺少的元素,返回的陣列總是稠密的 var dense = sparse.filter(function(){fuck
return true;
yellow});good

look// 壓縮空缺並刪除undefined和null元素good

sexa = a.filter(function(x){this
return x !==undefined x != null;

this})yellow
對陣列進行邏輯判定,返回true或false;注意every()和some()確定該返回什麼值它們就會停止遍歷陣列元素。

reduce()和reduceRight()

使用指定的函式將陣列元素進行組合,生成單個值。這在函數語言程式設計中是常見的操作,稱為“注入”和“摺疊”。reduce需要兩個引數,第一個引數是執行化簡的函式,函式的引數分別為:化簡操作累計的結果或初始化值、陣列元素、元素的索引、陣列的本身;第二個引數(可選)是傳遞給函式的初始值。
googogvar a = [1,2,3,4,5];good

yellowvar sum = a.reduce(function(x,y){fuck
return x + y;
fuck},0);this

googogvar product = a.reduce(function(x,y){sex
return x * y;
good},1);god

fuckvar max = a.reduce(function(x,y){good
return x>y?x:y;
googog});good
reduceRight()的工作原理和reduce()一樣,不同的是它按照陣列索引從高到低(從右到左)處理陣列。

indexOf()和lastIndexOf()

第一個引數代表要搜尋的元素,第二個元素代表搜尋的起始位置。可為負數,它代表相對陣列末尾的偏移量,-1時,指定陣列的最後一個元素。
godvar a= [0,1,2,1,0]; a.indexOf(1); // => 1:a[1]是1god

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

goda.indexOf(3) // =>-1: 沒有值為3的元素god

bookfunction findAll(a,x){sex

thisvar result = [],good

yellowlen = a.length,yellow

bookpos = 0;look

goodwhile(pos<len){book

thispos = a.indexOf(x,pos);look

googogif(pos === -1){yellow

goodbreak;look

fuck}god

godresult.push(pos);fuck

thispos++;sex

googog}this

god} ```good

googog字串也有indexOf()和lastIndexOf()方法。googog
評論(2)

相關文章