JS call、apply、bind、遞歸、閉包


call、apply、bind方法用來處理函數內部的this指向問題

在(https://www.cnblogs.com/qimuz/p/12740831.html)中介紹了用構造函數來創建對象,其中里面的this指的是誰調用this,它就指向誰。

function animal() {}
animal.prototype = {
    color: "grey",
    look: function() {
        console.log("It's color is " + this.color);
    }
};
var dog = new animal();
dog.look(); // It's color is grey
var cat = new animal();
cat.look(); // It's color is grey

上圖所示,打印出來的都是“It's color is grey”,但是如果我們想改變cat的顏色,就要重新定義一個look方法,如果改變的多了,就會很麻煩。

call()

call() 方法調用一個函數, 它具有一個指定的 this 值和分別地提供的參數

fun.call(thisArg, arg1, arg2, ...)
  • thisArg指的是在 fun 函數中指定的 this的值,是一個可選項

  • arg1, arg2, …指定的參數列表,也是可選項

  • 使用調用者提供的 this 值和參數調用該函數的返回值。若該方法沒有返回值,則返回 undefined。

  • call()允許為不同的對象分配和調用屬於一個對象的函數/方法

  • call()提供新的 this 值給當前調用的函數/方法。可以使用 call() 來實現繼承:寫一個方法,然后讓另外一個新的對象來繼承它,而不是在新對象中再寫一次這個方法

    比如前面的例子可以改為:

    //使用 call() 方法調用函數並且指定上下文的 this
    function animal() {}
    animal.prototype = {
    color: "grey",
    look: function() {
    console.log("It's color is " + this.color);
    	}
    };
    
    var dog = new animal();
    cat = {
    color:"white"
    };
    dog.look.call(cat); 
    

    這樣就更改了cat的顏色,輸出為"It's color is white"

    除此之外,還可以通過調用父構造函數的call()方法來實現繼承

    apply()

    這個方法與call方法類似,區別就是call方法里面接受的是參數,而apply方法接受的是數組

    fun.apply(thisArg, [argsArray]);
    

    1、將數組添加到另一個數組

    var arr = ["a", "b", "c"];
    var nums = [1, 2, 3];
    arr.push.apply(arr, nums);
    console.log(arr);  //返回["a", "b", "c", 1, 2, 3]
    

    結果為["a", "b", "c", 1, 2, 3]

    concat()、push()、apply()的區別:

    concat() 方法連接數組,不會改變原數組,而是創建一個新數組

    push() 是接受可變數量的參數的方式來添加元素

    apply() 則可以連接兩個數組

    2、apply() 方法及內置函數

    var numbers = [3, 4, 6, 1, 9];
    var max = Math.max.apply(null, numbers);
    console.log(max);  //返回9
    

    bind()

    bind()方法創建一個新的函數(稱為綁定函數),在調用時設置 this 關鍵字為提供的值。並在調用新函數時,將給定參數列表作為原函數的參數序列的前若干項。

    fun.bind(thisArg[, arg1[, arg2[, ...]]])
    

    thisArg指的是當綁定函數被調用時,該參數會作為原函數運行時的 this 指向。當使用 new 操作符調用綁定函數時,該參數無效。參數:arg1,arg2,…表示當目標函數被調用時,預先添加到綁定函數的參數列表中的參數。

    this.num = 6;
    var test = {
      num: 66,
      getNum: function() {
        return this.num;
      }
    };
    test.getNum(); // 返回 66
    var newTest = test.getNum;
    newTest(); // 返回 6
    // 創建一個新函數,將"this"綁定到 test 對象
    var bindgetNum = newTest.bind(test);
    bindgetNum(); // 返回 66
    

    遞歸

    在一個函數里,自己調用自己,就稱為遞歸調用

    function fun(){
    			fun();
    			console.log('Hello World');
    			}//一定要寫臨界條件,不然程序無法結束並且會報錯
    			fun();
    

    1、函數+變量

    例:求 1 到 100之間的整數相加的和

    function sum(n){
    		if(n==0){
    			return 0;
    		}else{
    			return n+sum(n-1);
    			}
    		}
    		var i = sum(100);
    		console.log(i);
    

    例:求10的階乘

    function fun(n){
    		if(n==1){
    			return 1;
    		}else{
    			return n*fun(n-1);
    			}
    		}
    		var i = fun(10);
    		console.log(i);
    

    2、函數+函數

斐波拉契題
--從出生后第3個月起每個月都生一對兔子,小兔子長到第三個月后每個月又生一對兔子,假如兔子都不死,每個月的兔子對數為多少?

產量分析:1, 1, 2, 3, 5, 8, 13, 21 .......

第n個月的兔子總數 = 第n-1個月的兔子總數 + 第n-2個月的兔子總數

問題: 求任意月兔子的總數

function func( n )
{
    if (n == 0 || n == 1){
        return 1;
    }else{
        return func(n-1) + func(n-2);
    }
}

var i = func(11);
console.log(i);

閉包

指的是函數可以使用函數定義之外的變量,每當函數被創建,就會在函數生成時生成閉包

先來了解一下作用域這個概念:

作用域

作用域的值就是作用范圍,也就是說一個變量或函數在什么地方可以使用,在什么地方不能使用

函數作用域

​ 指的是在函數內部聲明的變量在這個函數體內是可見的

function test() {
  var num = 123;
  console.log(num); //123
  if (2 == 3) {
    var k = 5;
    for (var i = 0; i < 10; i++) {}
    console.log(i);
  }
  console.log(k); // 不會報錯,顯示 undefined
}
test();

全局作用域

指的就是在什么地方都能夠訪問到它

  • 內層作用域可以訪問外層作用域,反之不行。
  • 整個代碼結構中只有函數可以限定作用域。
  • 如果當前作用規則中有名字了,就不考慮外面的同名變量。
  • 作用域規則首先使用提升規則分析。

再來看閉包~

簡單的閉包:全局變量

復雜的閉包:

function f1() {
		 var num=10;
		function f2() {
		console.log(num);
			}
		 //函數調用
		 f2();
			}
		f1(); //10

閉包可用來緩存數據~


免責聲明!

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



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