1. 程式人生 > 其它 >JS call、apply、bind、遞迴、閉包

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

閉包可用來快取資料~