重新鞏固JS(四)——JavaScript函數

重新鞏固JS系列,都是比較基礎的東西,可以進行查漏補缺,很快看完,這是第四篇。
其他JS重新鞏固系列

1. 函數概述

在編程領域中,子程序是一個大型程序中的某部分代碼,由一個或多個語句塊組成。它負責完成某項特定任務,而且相較於其他代碼,具備相對的獨立性。一般會有輸入參數並有返回值,提供對過程的封裝和細節的隱藏。不同語言中,子程序的叫法:
子程序叫法
在JS中,子程序成爲函數(function)。如果函數掛載在一個對象上,就稱它爲對象的方法。例子:

// 兩數求和函數
function sum(numA, numB) {
	return numA + numB;
}

// 對象的方法
const person = {
	//person對象的方法
	getName: function() {
		return this.name;
	}
}

JS中,函數也是對象,程序可以隨意操控它們,比如賦值給變量、作爲參數傳遞給其他函數、可以給它們設置屬性和方法。

2. 函數定義

使用關鍵字 function定義,通常有2種方式: 函數聲明語句和函數表達式。

// 函數聲明語句: sum爲函數名,numA、num爲形參。
function sum(numA, numB) {
	return numA + numB;
}

// 函數表達式
const sum = function(numA, numB) {
	return numA + numB;
}

函數返回值使用return關鍵字, 沒有return語句則默認返回undefined
第三種定義的方式是使用Function構造函數。最後一個參數是函數體,之前的都是函數的形參。

const sum = new Function('numA', 'numB', 'return numA + numB');

備註:一般不使用Function構造函數的形式(使用的場景:比如將一段字符串轉化爲可執行的代碼時)。

3. 函數調用

函數名稱加一對括號就可以調用函數。括號中可以傳入實參,和形參一一對應。

function sum(sumA, sumB) {
	return numA + numB;
}
const result = sum(1, 2);
console.log(result); // 3

4. 函數參數

定義函數時,形參不需要指定類型,調用函數時也不會檢查實參的類型和個數。

function sum() {
	return '?';
}
const result = sum(1, 2);
console.log(result); // 正常執行,輸出:?

4.1 默認值

函數參數可以指定默認值,如果調用時沒有傳入對應的值,則會使用默認值。

function sum(numA, numB = 2) {
	return numA + numB;
}
console.log(sum(1)); // 3

4.2 剩餘參數

ES6新增:如果函數的最後一個命名參數以...爲前綴,則它是包含剩餘參數的數組

function sum(numA, ...nums) {
	if (nums) {
		for(let i = 0; i < nums.length; i++) {
			numA += nums[i]
		}
	}
	return numA;
}
console.log(sum(1)); // 1
console.log(sum(1, 2, 3)); // 6

5. 函數內部屬性

在函數內部,有2個特殊對象: argumentsthis

5.1 arguments對象

在函數體內,arguments表示實參列表對象,它是一個類數組對象(類數組中的“類”字表示像的意思,就是說arguments對象像數組),可以通過下標訪問對應的實參值,也有length屬性,但是沒有數組的一些方法。

function sum() {
	return arguments[0] + arguments[1];
}
console.log(sum(1, 2)); // 3

5.2 this對象

在函數體內,this是指函數執行的環境對象(也叫context,即函數上下文)。一般來說,this指向調用函數的對象,如果沒有,就是全局對象,在瀏覽器中即爲Window對象(Node環境中爲Global對象)。

const sum = function () {
	console.log(this);
}
// 嚴格模式下是 undefined, 非嚴格模式下是 Window(Node環境爲Global)
sum();


const obj = {
	sum: function () {
		console.log(this);
	}
};
// this 爲 obj 對象
obj.sum();

6. 函數是特殊對象

函數是特殊的對象,意味着它也是一種值。所以函數可以: 當作參數傳遞、賦值給變量、作爲數組的元素中等。

function callSomeFunction (func, arg) {
	return func(arg);
}
function sum(sum) {
	return 1 + sum;
}

console.log(callSomeFunction(sum, 2)); // 3

函數具有的屬性:lengthname。 方法: callapplybind

6.1 函數的屬性:length 和 name

6.1.1 length屬性

函數的length是該函數期望參數的個數(第一個有默認參數前的參數),不包括有默認值參數和剩餘參數。

function sum(numA, numB = 1, ...nums) { }
console.log(sum.length); // 1

function sum(numA, numB = 1, numC, ...nums) { }
console.log(sum.length); // 1

6.1.2 name屬性

函數的name屬性是該函數的名稱。

const sum1 = function () {}
const obj = {
	sum2: function () {}
}
const sum3 = new Function();

console.log(sum1.name); // sum1
console.log(obj.sum2.name); // sum2
console.log(sum3.name); // anonymous

6.2 函數的方法: call、apply、bind

6.2.1 call方法

調用函數,可以指定函數中this和傳入參數列表

const obj = {
	name: 'cc',
	say: function (content) {
		const speak = function () {
			console.log(`${this.name} say ${content}`)
		};
		speak();
	}
};

obj.say('welcome'); //  say welcome

以上示例中,在say方法中調用speak,由於speak方法是直接單獨調用的,所以函數體內的this指向的是全局變量window,而全局變量window的name屬性值爲空(''),所以輸出'' say welcome

提問:①函數speak中的this.name如何取到cc這個值? ②函數speak如何接收更多參數?
解決方法
① speak() -----> speak.call(this) ,即可。
② speak() -----> speak.call(this, ‘one’, ‘two’) ,在call函數第一個參數後面依次添加參數即可。

6.2.2 apply方法

調用函數,可以指定函數中的 this 和傳入 參數數組 ,作用其實和call方法一樣,只是後面的參數是以數組的形式傳入。助記方法: apply----->首字母a,數組array的首字母也是a------->apply方法傳參是以數組的形式。

6.2.3 bind方法

生成一個新的函數,可以指定函數調用時的this對象和傳入參數列表
6.2.1中同樣的兩個問題的解法:
① 因爲bind方法是生成一個新的方法,我們需要再調用這個新方法才能得到執行結果:

const obj = {
	name: 'cc',
	say: function (content) {
		const speak = function () {
			console.log(`${this.name} say ${content}`)
		};
		const speak1 = speak.bind(this);
		speak1()
	}
};

obj.say('welcome'); // cc say welcome

② 傳參的話,直接在bind函數中的第一個參數後面以參數列表的形式傳入即可。

const  speak1 = speak.bind(this, 'one', 'two')

7. 變量作用域簡介

JS引擎查找變量的過程,從局部作用域向外層查找,一直到全局作用域爲止。
JS引擎查找變量的過程
變量作用域
局部變量的名字可以和全局變量相同,但兩者互不影響。

const name = 'cc1';
function outerFunc() {
	const name = 'cc2';
	function innerFunc() {
		const name = 'cc3';
		console.log(name); // 'cc3'
	}
	innerFunc()
	console.log(name); // 'cc2'
}
outerFunc();
console.log(name); // 'cc1'

ES6塊級作用域:ES6引入了letconst,它們聲明的是塊級作用域變量,塊由{...}構成。

let x = 10;
var y = 10;
{
	let x = 5;
	var y = 5;
	{
		let x = 2;
		var y = 2;
		console.log(x, y) // 2 2
	}
	console.log(x, y) // 5 2
}
console.log(x, y) // 10 2

原型相關感興趣的可以看看這篇文章:幫你徹底搞懂JS中的prototype、__proto__與constructor(圖解)

8. 箭頭函數(arrow function)

箭頭函數表達式的語法比函數表達式更短,並且不綁定自己的this、arguments、super或new.target。這些函數表達式最適合用於非方法函數,並且它們不能用作構造函數。

const materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium'];
materials.map(function (material) {
	return material.length;
});  // [8, 6, 7, 9]

materials.map((material) => {
	return material.length;
});  // [8, 6, 7, 9]

materials.map(material => material.length );  // [8, 6, 7, 9]

若對你有幫助,可以支持一下作者創作更多好文章哦~
讚賞碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章