什么是函數呢?
對於JS來說,我們可以把函數理解為任意一段代碼放在一個盒子里,在我們想要讓這段代碼執行的時候,直接執行這個盒子里的代碼就行。專業一點來講:js函數就是由事件驅動的可執行課重復只用的代碼塊。
函數定義
聲明式
function fn() {
}
//這個function就聲明了一個名為fn的函數
匿名函數(分為兩種情況)
// 賦值式的原理和我們使用var關鍵字是一個道理
// 首先我們用一個var定義一個變量,把一個函數當做值直接賦值就行了
var fn = function(){
}
// var定義一個fn的變量 然后函數function()賦值給fn
//匿名函數自執行:聲明后不需要調用就直接執行
;(function(){
console.log("自執行函數執行");
})();
構造函數式
var object = new Object();
//這里是js語言自帶的構造函數
函數在調用上區別
- 雖然兩種定義方式的調用都是一樣的,但是還是有一些區別的
- 聲明式函數: 調用可以在 定義之前或者定義之后
// 可以調用
fn()
// 聲明式函數
function fn() {
console.log('我是 fn 函數')
}
// 可以調用 fn函數
fn()
// 會報錯
fn()
// 賦值式函數
var fn = function() {
console.log('我是 fn 函數')
}
// 可以調用
fn()
;(function(){
console.log("自執行函數")
})();

函數的參數
在定義函數的時候我們都需要使用到(),而這個()就是存放參數的地方,參數分為形參和實參
// 聲明式
function fn(形參){
// 一段代碼
}
fn(實參);
// 賦值式
var fn = function(形參){
// 一段代碼
}
fn(實參)
形參與實參的作用
- 形參
- 形參實際上就是函數內部使用的變量,在函數外部不能使用
- 在定義函數()中每寫一個單詞,就相當於在函數內部定義一個可以使用的變量,多個單詞之前使用
,
隔開
// 書寫一個參數
function fn(num) {
// 在函數內部就可以使用 num 這個變量
}
var fn1 = function(num) {
// 在函數內部就可以使用 num 這個變量
}
// 書寫兩個參數
function fun(num1, num2) {
// 在函數內部就可以使用 num1 和 num2 這兩個變量
}
var fun1 = function(num1, num2) {
// 在函數內部就可以使用 num1 和 num2 這兩個變量
}
- 如果只有形參,沒有賦值,那么在函數內部使用的時候會出現
undefined
- 形參的值由函數調用時實參決定的
- 實參
- 在函數調用時為形參賦值使用
- 多個參數的時候需要一一對應
function fn(num1, num2){
//這里可以使用num1和num2
}
//這樣在fn函數中調用num1和num2時,他們的值就是num1=100,num2=200;
// 如果參數沒有一一對應那么函數調用的時候就會出現undefined
fn(100,200);


函數不定參數(可變參)-關鍵字arguments
- 但實參傳入的值是不確定的參數個數的時候,在形參我們也不知道怎么去接收,這個時候我們就需要使用arguments來接收參數
function fn(){
console.log(arguments);
console.log(arguments[0]);
console.log(arguments[1]);
console.log(arguments[2]);
console.log(arguments[3]);
console.log(arguments[4]);
console.log(arguments[5]);
console.log(arguments[6]);
}
fn(1,2,3,4,5,6,7)

函數的return
的用法
- return是返回的意思,作用就是給函數一個返回值和中斷函數
返回值
- 每一個函數自身就是一個表達式,使用
return
關鍵字可以是返回一個結果出去
function fn(num1, num2){
return num1 + num2;
}
var res = fn(100, 200);
console.log(res);//結果為300

- 如果沒有
return
返回一個結果 那么去打印函數的結果就是undefined
function fn(){
}
console.log(fn());// undefined

- 在函數里使用
return
關鍵字我們可以任何數據類型當做這個函數運行后的結果
函數的特點
- 函數就是對一段代碼的封裝,在我們想調用的時候調用
- 函數的幾個優點
- 封裝代碼,使代碼更加簡潔
- 復用,在重復功能的時候直接調用就好
- 代碼執行時機,隨時可以在我們想要執行的時候執行
JS預解析機制
JS是一個解釋語言,在所有代碼執行前都會進行一個預解析
函數提升(整體提升)
- 在內存中先聲明有一個變量名是函數名,並且這個名字代表的內容是一個函數
// 在代碼執行前這個函數整體已經被提升到代碼的最前面
fn();
function fn(){
console.log("hello world");
}
變量提升(局部提升)
console.log(num);//undefined
var num = 10;
// 在代碼執行之前,這個變量被提升到代碼最前面,但是並未被賦值,所以打印的時候是undefined
作用域
- 什么是作用域?就是一個變量可以生效的范圍
- 變量不能再任何地方使用的,而可以使用該變量的就是變量的作用域
- 作用域分為全局作用域和局部作用域
全局作用域
- 全局作用域是最大的作用域
- 在全局作用域中定義的變量可以在任何地方使用
- 頁面打開的時候,瀏覽器會自動給我們生成一個全局作用域
windows
- 全局作用域會一直存在,直到頁面關閉才銷毀
// 在頁面任何一個地方都可以使用
var num1 = 100;
var num2 = 200;
局部作用域
- 在js中只有函數里才能出現局部作用域
- 局部作用域中定義的變量只能在局部作用域中使用
- 每一個函數都是一個局部作用域
function fn(){
var num = 10;
console.log(num);
}
// 局部作用域的作用范圍只能在函數中使用,所以這里打印is no defined
console.log(num);

變量使用規則
- 有了作用域之后,變量就有了使用范圍和使用規則
- 變量使用規則分為兩種: 范圍規則和賦值規則
訪問規則
- 當我想獲取一個變量的時候,我們稱這個行為叫做訪問
- 獲取變量的規則
- 首先,在自己作用域內部查找,如果有,就直接拿來使用
- 如果沒有,就去上一級作用域查找,如果有,直接拿來使用
- 如果沒有,就繼續向上一級作用域查找,依次類推
- 如果一直查找到全局作用域都沒有這個變量,那么就會直接報錯 is no defined
var a = 1;
function poo(){
var num1 = 100;
function foo(){
var num2 = 200;
console.log(num1);//自己作用域沒有向上一層查找
console.log(num2);//自己作用域有直接拿來用
console.log(a);//一直查找到全局作用域
console.log(num3);//全局作用域沒有,就直接報錯 is no defined
}
foo();
}
poo();
- 作用訪問規則,又叫作用域查找機制
- 作用域查找機制,只能由內向外,不能由外向內
function fn(){
var num = 100;
}
console.log(num);//無法找到num
賦值規則
- 當你想要給一個變量賦值的時候,我們需要先找到這個變量在給它賦值
- 變量賦值規則
- 先在自己的作用查找變量,查找到之后直接賦值
- 沒有的話就向上一級作用域查找,有就直接賦值
- 直到找到全局作用域,如果還沒有找到的話,js會將這個變量變為偽全局變量
function fn(){
num = 100;
}
console.log(num);//這里的num變成了偽全局變量,可以訪問到
總結
每當一個函數創建時,作用域鏈也被創建出來了,作用域鏈查找過程:在JS中我們調用一條數據時,會先在當前作用域進行查找,如果找不到,就從向上找父作用域的數據,還找不到就接着向上,一直找到全局作用域(window對象),window都找不到就報錯。
