函數的四種調用方式


 函數的四種調用方式

函數有下列調用模式

  1. 函數調用模式
  2. 方法調用模式
  3. 構造器模式
  4. 上下文模式

1. 函數調用 模式

要調用,就肯定要先定義,函數的定義方式:

  1. 聲明式: function fuc() {}
  2. 表達式式: var func = function() {};
  3. Function: new Function( ‘參數’,…,’函數體’ );

單獨獨立調用的,就是函數調用模式,即 函數名( 參數 ),不能加任何其他的東西, 對象 o.fuc() 就不是了。

在函數調用模式中, this 表示全局對象 window

任何自調用函數都是函數模式。


2. 方法調用 模式 method

所謂方法調用,就是用對象的方法調用。方法是什么,方法本身就是函數,但是,方法不是單獨獨立的,而是要通過一個對象引導來調用。

就是說方法對象一定要有宿主對象。

即 對象.方法(參數)

this表示引導方法的對象,就是指宿主對象

對比-函數調用模式:

  1. 方法調用模式是不是獨立的,需要宿主,而函數調用模式是獨立的
  2. 方法調用模式方式:obj.fuc(); 函數調用模式方式: fuc();
  3. 方法調用模式中,this指宿主。而函數調用模式中 this 指 全局對象window

美團的一道面試題

  1.  
    var length = 10;
  2.  
    function fn() {
  3.  
    console.log( this.length ); // 10
  4.  
    }
  5.  
    var obj = {
  6.  
    length: 5,
  7.  
    method: function ( fn ) {
  8.  
    fn(); // 10 前面沒有引導對象,是函數調用模式
  9.  
    arguments[ 0 ](); // 2
  10.  
    // arguments是一個偽數組對象, 這里調用相當於通過數組的索引來調用.
  11.  
    // 這里 this 就是 指的這個偽數組, 所以 this.length 為 2
  12.  
    }
  13.  
    };
  14.  
    obj.method( fn, 1 ); // 打印 10 和 2
  15.  
    //obj.method( fn, 1, 2, 3 ); // 打印 10 和 4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

解析:

  1. fn() 前面沒有引導對象,是函數調用模式, this是全局對象,輸出 10

  2. arguments[ 0 ](),arguments是一個偽數組對象, 這里調用相當於通過數組的索引來調用.

    這里引導對象即宿主就是 arguments對象。

    所以,執行時,this 就是指 arguments,由於傳了兩個參數,所以 輸出為 arguments.length 就是 2


3. 構造器模式(構造函數模式, 構造方法模式)

constructor

  1. 特點: 使用 new 關鍵字引導

  2. 執行步驟:var p = new Person();

    new 是一個運算符, 專門用來申請創建對象, 創建出來的對象傳遞給構造函數的 this。然后利用構造函數對其初始化。

    1.  
      function Person () {
    2.  
      // new了 進入構造函數時, p 對象的原型 就指向了 構造函數 Person,
    3.  
      // p.__proto__.constructor = function Person() {};
    4.  
      // 而 this 指的的是 p 對象
    5.  
      this.name = 'jim',
    6.  
      this.age = 19;
    7.  
      this.gender = 'male';
    8.  
      }
    9.  
      var p = new Person();
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    執行完 new 進入構造函數時, p 對象的原型 就指向了 構造函數 Person

    而 構造時,this 指的的是 p 對象,是通過對象動態添加屬性來構造的

    小貼士:如果調用構造函數的時候, 構造函數沒有參數, 圓括號是可以省略的。

    1.  
      function Person() {
    2.  
      this.name = 'jim';
    3.  
      }
    4.  
      var p = new Person; // 不傳參,可以簡寫,不影響構造
    5.  
      console.log( p ); // p 含有 name屬性
    • 1
    • 2
    • 3
    • 4
    • 5

    ↑ 不傳參,可以簡寫,不影響構造

  3. 返回值

    1. 不寫 return 語句, 那么 構造函數 默認返回 this

    2. 在構造函數 return 基本類型( return num, return 1223 ). 則忽略返回類型.

    3. 在構造函數 return 引用類型, 那么構造函數返回該引用類型數據, 而忽略 this

    1.  
      function Person () {
    2.  
      this.name = 'Jepson';
    3.  
      return 123;
    4.  
      }
    5.  
      var p1 = new Person();
    6.  
      console.log( p1 );
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    ↑ 忽略了 123,返回 this 對象, 指向構建的實例

    1.  
      function Person () {
    2.  
      this.name = 'Jepson';
    3.  
      return { 'peter': 'nihao' };
    4.  
      }
    5.  
      var p1 = new Person();
    6.  
      console.log( p1 );
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    ↑ 忽略了 this,返回 { ‘peter’: ‘nihao’ } 對象

構造函數結合性

  1. 如果構造函數沒有參數, 可以省略 圓括號

    var p = new Person;

  2. 如果希望創建對象並直接調用其方法

    ( new Person () ).sayHello()

    -> 可以省略調整結核性的圓括號 new Person().sayHello()

    -> 如果想要省略構造函數的圓括號, 就必須添加結核性的圓括號 (new Person).sayHello()

面試題

一道面試題,大家可以自己嘗試先做一下,再看下面的答案和解析

請問順序執行下面代碼,會怎樣 alert

  1.  
    function Foo(){
  2.  
    getName = function(){ alert(1); };
  3.  
    return this;
  4.  
    }
  5.  
    Foo.getName = function(){ alert(2); };
  6.  
    Foo.prototype.getName = function(){ alert(3); };
  7.  
    var getName = function(){ alert(4); };
  8.  
    function getName(){ alert(5); }
  9.  
     
  10.  
    Foo.getName(); // alert ??
  11.  
    getName(); // alert ??
  12.  
    Foo().getName(); // alert ??
  13.  
    getName(); // alert ??
  14.  
    new Foo.getName(); // alert ??
  15.  
    new Foo().getName(); // alert ??
  16.  
    new new Foo().getName(); // alert ??
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

預解析,簡化后的代碼,以及答案

  1.  
    /* function getName(){ alert(5); } 執行到下面被覆蓋了,直接刪除 */
  2.  
    function Foo() {
  3.  
    getName = function () { alert(1); };
  4.  
    return this;
  5.  
    }
  6.  
    Foo.getName = function () { alert(2); };
  7.  
    Foo.prototype.getName = function () { alert(3); };
  8.  
    var getName = function () { alert(4); };
  9.  
     
  10.  
    Foo.getName(); // ------- 輸出 2 -------
  11.  
    getName(); // ------- 輸出 4 -------
  12.  
    Foo().getName(); // ------- 輸出 1 -------
  13.  
    getName(); // ------- 輸出 1 -------
  14.  
    new Foo.getName(); // ------- 輸出 2 -------
  15.  
    new Foo().getName(); // ------- 輸出 3 -------
  16.  
    var p = new new Foo().getName(); // ------- 輸出 3 -------
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

全部解析過程 ↓

  1.  
    function Foo() {
  2.  
    getName = function () { alert(1); };
  3.  
    return this;
  4.  
    }
  5.  
    Foo.getName = function () { alert(2); };
  6.  
    Foo.prototype.getName = function () { alert(3); };
  7.  
    var getName = function () { alert(4); };
  8.  
     
  9.  
    Foo.getName(); // ------- 輸出 2 -------
  10.  
    // 調用 Foo函數 作為 對象 動態添加的屬性方法 getName
  11.  
    // Foo.getName = function () { alert(2); };
  12.  
     
  13.  
    getName(); // ------- 輸出 4 -------
  14.  
    // 這里 Foo函數 還沒有執行,getName還沒有被覆蓋
  15.  
    // 所以 這里還是 最上面的 getName = function () { alert(4); };
  16.  
     
  17.  
    Foo().getName(); // ------- 輸出 1 -------
  18.  
    // Foo()執行,先覆蓋全局的 getName 再返回 this,
  19.  
    // this 是 window, Foo().getName() 就是調用 window.getName
  20.  
    // 此時 全局的 getName已被覆蓋成 function () { alert(1); };
  21.  
    // 所以 輸出 1
  22.  
    /* 從這里開始 window.getName 已被覆蓋 alert 1 */
  23.  
     
  24.  
    getName(); // -------- 輸出 1 --------
  25.  
    // window.getName alert(1);
  26.  
     
  27.  
    new Foo.getName(); // ------- 輸出 2 -------
  28.  
    // new 就是 找 構造函數(),由構造函數結合性,這里即使 Foo無參,也不能省略 (),所以不是 Foo().getName()
  29.  
    // 所以 Foo.getName 為一個整體,等價於 new (Foo.getName)();
  30.  
    // 而 Foo.getName 其實就是函數 function () { alert(2); } 的引用
  31.  
    // 那 new ( Foo.getName )(), 就是在以 Foo.getName 為構造函數 實例化對象。
  32.  
    // 就 類似於 new Person(); Person 是一個構造函數
  33.  
     
  34.  
    // 總結來看 new ( Foo.getName )(); 就是在以 function () { alert(2); } 為構造函數來構造對象
  35.  
    // 構造過程中 alert( 2 ),輸出 2
  36.  
     
  37.  
    new Foo().getName(); // ------- 輸出 3 -------
  38.  
    // new 就是 找 構造函數(),等價於 ( new Foo() ).getName();
  39.  
    // 執行 new Foo() => 以 Foo 為構造函數,實例化一個對象
  40.  
    // ( new Foo() ).getName; 訪問這個實例化對象的 getName 屬性
  41.  
    // 實例對象自己並沒有 getName 屬性,構造的時候也沒有 添加,找不到,就到原型中找
  42.  
    // 發現 Foo.prototype.getName = function () { alert(3); };
  43.  
    // 原型中有,找到了,所以 ( new Foo() ).getName(); 執行,alert(3)
  44.  
     
  45.  
    var p = new new Foo().getName(); // ------- 輸出 3 -------
  46.  
    // new 就是 找 構造函數(),等價於 new ( ( new Foo() ).getName )() 輸出 3
  47.  
     
  48.  
    // 先看里面的 ( new Foo() ).getName
  49.  
    // new Foo() 以Foo為構造函數,實例化對象
  50.  
    // new Foo().getName 找 實例對象的 getName屬性,自己沒有,去原型中找,
  51.  
    // 發現 Foo.prototype.getName = function () { alert(3); }; 找到了
  52.  
     
  53.  
    // 所以里層 ( new Foo() ).getName 就是 以Foo為構造函數實例出的對象的 一個原型屬性
  54.  
    // 屬性值為一個函數 function () { alert(3); } 的引用
  55.  
     
  56.  
    // 所以外層 new ( (new Foo()).getName )()在以該函數 function () { alert(3); } 為構造函數,構造實例
  57.  
    // 構造過程中 執行了 alert(3), 輸出 3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

4. 上下文調用模式

就是 環境調用模式 => 在不同環境下的不同調用模式

簡單說就是統一一種格式, 可以實現 函數模式與方法模式

-> 語法(區分)

  1. call 形式, 函數名.call( … )
  2. apply 形式, 函數名.apply( … )

這兩種形式功能完全一樣, 唯一不同的是參數的形式. 先學習 apply, 再來看 call 形式

apply方法的調用形式

存在上下文調用的目的就是為了實現方法借用,且不會污染對象。

  • 如果需要讓函數以函數的形式調用, 可以使用

    foo.apply( null ); // 上下文為 window

  • 如果希望他是方法調用模式, 注意需要提供一個宿主對象

    foo.apply( obj ); // 上下文 為 傳的 obj 對象

  1.  
    function foo () {
  2.  
    console.log( this );
  3.  
    }
  4.  
    var o = { name: 'jim' };
  5.  
     
  6.  
    // 如果需要讓函數以函數的形式調用, 可以使用
  7.  
    foo.apply( null ); // this => window // 或 foo.apply()
  8.  
     
  9.  
    // 如果希望他是方法調用模式, 注意需要提供一個宿主對象
  10.  
    foo.apply( o ) // this => o 對象
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

帶有參數的函數如何實現上下文調用?

  1.  
    function foo ( num1, num2 ) {
  2.  
    console.log( this );
  3.  
    return num1 + num2;
  4.  
    }
  5.  
     
  6.  
    // 函數調用模式
  7.  
    var res1 = foo( 123, 567 );
  8.  
     
  9.  
    // 方法調用
  10.  
    var o = { name: 'jim' };
  11.  
    o.func = foo;
  12.  
    var res2 = o.func( 123, 567 );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

使用 apply 進行調用, 如果函數是帶有參數的. apply 的第一個參數要么是 null 要么是對象

  1. 如果是 null 就是函數調用

  2. 如果是 對象就是 方法調用, 該對象就是宿主對象, 后面緊跟一個數組參數, 將函數所有的參數依次放在數組中.

  1.  
    例如: 函數模式 foo( 123, 567 );
  2.  
    apply foo.apply( null, [ 123, 567 ] ) 以 window 為上下文執行 apply
  3.  
     
  4.  
    如果有一個函數調用: func( '張三', 19, '男' ),
  5.  
    將其修改成 apply 模式: func.apply( null, [ '張三', 19, '男'] )
  6.  
     
  7.  
    方法模式: o.func( 123, 567 )
  8.  
    apply var o = { name: 'jim' };
  9.  
    foo.apply( o, [ 123, 567 ] ); 以 o 為上下文執行 apply
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

方法借用的案例

需求, 獲得 div 與 p 標簽, 並添加邊框 border: 1px solid red

一般做法:

  1.  
    var p_list = document.getElementsByTagName('p');
  2.  
    var div_list = document.getElementsByTagName('div');
  3.  
     
  4.  
    var i = 0;
  5.  
    for( ; i < p_list.length; i++ ) {
  6.  
    p_list[ i ].style.border = "1px solid red";
  7.  
    }
  8.  
    for( i = 0; i < div_list.length; i++ ) {
  9.  
    div_list[ i ].style.border = "1px solid red";
  10.  
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  1. 利用方法借用優化,元素獲取
  1.  
    var t = document.getElementsByTagName;
  2.  
    var p_list = t.apply( document, [ 'p' ] ); // 方法借用
  3.  
    var div_list = t.apply( document, [ 'div' ] ); // 方法借用
  • 1
  • 2
  • 3
  1. 接下來考慮下面的優化,兩個for循環,只要將數組合並了,就可以只用一個 for 循環

    數組合並

    1.  
      var arr1 = [ 1, 2, 3 ];
    2.  
      var arr2 = [ 5, 6 ];
    3.  
      arr1.push.apply( arr1, arr2 ); // 方法調用,第一個給上對象
    4.  
      // 等價於 Array.prototype.push.apply( arr1, arr2 );
    • 1
    • 2
    • 3
    • 4

    所以同理,利用 apply 方法借用,將兩個偽數組合並成同一個數組

    1.  
      var arr = []; // 偽數組沒有 push 方法,所以這里要 聲明一個 數組
    2.  
      arr.push.apply( arr, p_list ); // 將 p_list里的內容,一個個當成參數放了進來,相當於不用遍歷了
    3.  
      arr.push.apply( arr, div_list ); // 同上,方法借用
    4.  
      console.log( arr );
    • 1
    • 2
    • 3
    • 4

將兩者綜合, 使用forEach,最終 6 行就解決了

  1.  
    var t = document.getElementsByTagName, arr = [];
  2.  
    arr.push.apply( arr, t.apply( document, [ 'p' ] ) );
  3.  
    arr.push.apply( arr, t.apply( document, [ 'div'] ) );
  4.  
    arr.forEach( function( val, index, arr ) {
  5.  
    val.style.border = '1px solid red';
  6.  
    });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

call 調用

在使用 apply 調用的時候, 函數參數, 必須以數組的形式存在. 但是有些時候數組封裝比較復雜

所以引入 call 調用, call 調用與 apply 完全相同, 唯一不同是 參數不需要使用數組

  1.  
    foo( 123, 567 );
  2.  
     
  3.  
    foo.apply( null, [ 123, 567 ] );
  4.  
     
  5.  
    foo.call( null, 123, 567 );
  • 1
  • 2
  • 3
  • 4
  • 5
  1. 函數調用: 函數名.call( null, 參數1,參數2,參數3… );

  2. 方法調用: 函數名.call( obj, 參數1,參數2, 參數3… );

不傳參時,apply 和 call 完全一樣

借用構造方法實現繼承

  1.  
    function Person ( name, age, gender ) {
  2.  
    this.name = name;
  3.  
    this.age = age;
  4.  
    this.gender = gender;
  5.  
    }
  6.  
     
  7.  
    function Student ( name, age, gender, course ) {
  8.  
    // 原型鏈結構不會變化,同時實現了繼承的效果
  9.  
    Person.call( this, name, age, gender );// 借用Person構造方法
  10.  
    this.course = course;
  11.  
    }
  12.  
     
  13.  
    var p = new Student ( 'jim', 19, 'male', '前端' );
  14.  
    console.log( p );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

補充知識 1. 函數的 bind 方法 ( ES5 )

bind 就是 綁定

還是上面那個案例 獲得 div 與 p 標簽, 並添加邊框 border: 1px solid red

  1.  
    var t = document.getElementsByTagName, arr = [];
  2.  
    arr.push.apply( arr, t.call( document, 'p' ) );
  3.  
    arr.push.apply( arr, t.call( document, 'div' ) );
  4.  
    arr.forEach( function( val, index, arr ) {
  5.  
    val.style.border = '1px solid red';
  6.  
    });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

我們 讓 t 包含函數體(上面的方式),同時包含 對象,就可以更精簡

  1.  
    var t = document.getElementsByTagName.bind( document ), arr = [];
  2.  
    arr.push.apply( arr, t( 'p') );
  3.  
    arr.push.apply( arr, t( 'div') );
  4.  
    arr.forEach( function( val, index, arr ) {
  5.  
    val.style.border = '1px solid red';
  6.  
    });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

bind : 就是讓函數綁定對象的一種用法

函數本身就是可以調用, 但是其如果想要作為方法調用, 就必須傳入宿主對象, 並且使用 call 或 apply 形式

但是 bind 使得我的函數可以與某一個對象綁定起來, 那么在調用函數的時候, 就好像是該對象在調用方法,就可以直接傳參,而不需要傳宿主對象。

語法: 函數.bind( 對象 )

返回一個函數 foo,那么調用 返回的函數 foo, 就好像 綁定的對象在調用 該方法一樣

  1.  
    t.call( document, 'p' );
  2.  
     
  3.  
    t( 'p' ); 綁定后,就不用傳宿主對象了,這里調用時上下文已經變成了 document
  4.  
     
  5.  
    bind 是 ES 5 給出的函數調用方法
  • 1
  • 2
  • 3
  • 4
  • 5

補充知識 2. Object.prototype 的成員

Object.prototype 的成員

  1. constructor
  2. hasOwnProperty 判斷該屬性是否為自己提供
  3. propertyIsEnumerable 判斷屬性是否可以枚舉
  4. isPrototypeOf 判斷是否為原型對象
  5. toString, toLocaleString, valueOf
  1.  
    function Person() {
  2.  
    this.name = 'jim';
  3.  
    }
  4.  
    Person.prototype.age = 19;
  5.  
    var p = new Person();
  6.  
    console.log( p.hasOwnProperty( 'name' ) ); // true; p 是否含有 name 屬性,原型上不管
  7.  
    console.log( p.hasOwnProperty( 'age' ) ); // false; p 是否含有 age 屬性
  8.  
     
  9.  
    /* Person.prototype 是 p 的原型 */
  10.  
    console.log( p.isPrototypeOf( Person.prototype ) ); // false
  11.  
    console.log( Person.prototype.isPrototypeOf( p ) ); // true;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

用途:一般把一個對象拷貝到另一個對象時,可以進行判斷,更加嚴謹,以防把原型中的屬性也拷貝過去了…


補充知識 3. 包裝類型

字符串 string 是基本類型, 理論上講不應該包含方法

那么 charAt, substr, slice, …等等方法,理論上都不應該有,但確是有的

所以引入包裝對象的概念,在 js 中為了更好的使用數據, 為三個基本類型提供了對應的對象類型

  1. Number
  2. String
  3. Boolean

在 開發中常常會使用基本數據類型, 但是基本數據類型沒有方法, 因此 js 引擎會在需要的時候自動的將基本類型轉換成對象類型, 就是包裝對象

  • “abc”.charAt( 1 )

  • “abc” -> s = new String( “abc” )

  • s.charAt( 1 ) 返回結果以后 s 就被銷毀

當基本類型.方法 的時候. 解釋器首先將基本類型轉換成對應的對象類型, 然后調用方法.

方法執行結束后, 這個對象就被立刻回收

在 apply 和 call 調用的時候, 也會有轉換發生. 上下文調用的第一個參數必須是對象. 如果傳遞的是數字就會自動轉換成對應的包裝類型


補充知識 4. getter 和 setter 的語法糖 ( ES5 )

語法糖: 為了方便開發而給出的語法結構

本身實現:

  1.  
    var o = (function () {
  2.  
    var num = 123;
  3.  
    return {
  4.  
    get_num: function () {
  5.  
    return num;
  6.  
    },
  7.  
    set_num: function ( v ) {
  8.  
    num = v;
  9.  
    }
  10.  
    };
  11.  
    })();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  1.  
    希望獲得數據 以對象的形式
  2.  
    o.get_num(); => o.num 形式
  3.  
     
  4.  
    希望設置數據 以對象的形式
  5.  
    o.set_num( 456 ); => o.num = 456 形式
  • 1
  • 2
  • 3
  • 4
  • 5

所以 getter 和 setter 誕生 了

  1.  
    var o = (function () {
  2.  
    var num = 123;
  3.  
    return {
  4.  
    // get 名字 () { 邏輯體 }
  5.  
    get num () {
  6.  
    console.log( '執行 getter 讀寫器了' );
  7.  
    return num;
  8.  
    },
  9.  
     
  10.  
    // set 名字 ( v ) { 邏輯體 }
  11.  
    set num ( v ) {
  12.  
    console.log( '執行 setter 讀寫器了' );
  13.  
    num = v;
  14.  
    }
  15.  
    };
  16.  
    })();
  17.  
     
  18.  
    console.log( o.num ); // 執行 getter 讀寫器了 123
  19.  
    o.num = 33; // 執行 setter 讀寫器了
  20.  
    console.log( o.num ); // 執行 getter 讀寫器了 33
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

為什么不直接用 對象呢 var o = { num : 123 } ,也可以讀寫呀?

因為語法糖還可以 限制其賦值的范圍,使用起來特別爽

  1.  
    var o = (function () {
  2.  
    var num = 13;
  3.  
    return {
  4.  
     
  5.  
    // get 名字 () { 邏輯體 }
  6.  
    get num () {
  7.  
    console.log( '執行 getter 讀寫器了' );
  8.  
    return num;
  9.  
    },
  10.  
     
  11.  
    // set 名字 ( v ) { 邏輯體 }
  12.  
    set num ( v ) {
  13.  
    console.log( '執行 setter 讀寫器了' );
  14.  
     
  15.  
    if ( v < 0 || v > 150 ) {
  16.  
    console.log( '賦值超出范圍, 不成功 ' );
  17.  
    return;
  18.  
    }
  19.  
    num = v;
  20.  
    }
  21.  
    };
  22.  
    })();
  23.  
    o.num = -1; // 執行 setter 讀寫器了
  24.  
    // 讀寫器賦值超出范圍, 不成功
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

補充知識 5. ES5 中引入的部分數組方法

  1. forEach
  2. map
  3. filter
  4. some
  5. every
  6. indexOf
  7. lastIndexOf

  1. forEach, 數組遍歷調用,遍歷arr,參數三個 1某項, 2索引, 3整個數組

    1.  
      var arr = [ 'hello', ' js', { }, function () {} ];
    2.  
      // 遍歷 數組
    3.  
      arr.forEach( function ( v, i, ary ) {
    4.  
      console.log( i + '=====' + v );
    5.  
      console.log( ary );
    6.  
      });
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  2. map 映射

    語法: 數組.map( fn )

    返回一個數組, 數組的每一個元素就是 map 函數中的 fn 的返回值

    就是對每一項都進行操作,並返回

    1.  
      var arr = [ 1, 2, 3, 4 ];
    2.  
      // 數學中: x -> x * x
    3.  
      var a = arr.map(function ( v, i ) {
    4.  
      return v * v;
    5.  
      });
    6.  
      // a [1, 4, 9, 16]
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  3. filter 就是篩選, 函數執行結果是 false 就棄掉, true 就收着

    語法: 數組.filter( function ( v, i ) { return true/false })

    1.  
      var arr = [ 1, 2, 3, 4, 5, 6 ];
    2.  
      // 篩選奇數
    3.  
      var a = arr.filter( function ( v ) { return v % 2 === 1; });
    4.  
      // a [ 1, 3, 5 ]
    • 1
    • 2
    • 3
    • 4
  4. some 判斷數組中至少有一個數據復合要求 就返回 true, 否則返回 false

    1.  
      var arr = [ '123', {}, function () {}, 123 ];
    2.  
      // 判斷數組中至少有一個數字
    3.  
      var isTrue = arr.some( function ( v ) { return typeof v === 'number'; } ); // true;
    • 1
    • 2
    • 3
  5. every 必須滿足所有元素都復合要求才會返回 true

    1.  
      var arr = [ 1, 2, 3, 4, 5, '6' ];
    2.  
      // 判斷數組中每一個都是數字
    3.  
      var isTrue = arr.every( function ( v ) { return typeof v === 'number'; } ); } ); // false;
    • 1
    • 2
    • 3
  6. indexOf 在數組中查找元素, 如果含有該元素, 返回元素的需要( 索引 ), 否則返回 -1

    1.  
      var arr = [ 1, 2, 3, 4, 5 ];
    2.  
      var res = arr.indexOf( 4 ); // 要找 4
    3.  
      console.log( res ); // 3 找 4 在 索引為 3 找到
    4.  
       
    5.  
      var arr = [ 1, 2, 3, 4, 5, 4, 5, 6 ];
    6.  
      var res = arr.indexOf( 4, 4 ); // 要找 4, 從索引 4開始找
    7.  
      console.log( res ); // 找到了 索引為 5
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  7. lastIndexOf 從右往左找

    1.  
      var arr = [ 1, 2, 3, 4, 5, 4, 5, 6 ];
    2.  
      var res = arr.lastIndexOf( 4 );
    3.  
      console.log( res ); // 索引為 5, 從最后一項開始找,即從 length-1 項開始找
    4.  


免責聲明!

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



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