- 函數的定義與調用
方式1 函數聲明方式 function 關鍵字 (命名函數)
function fn(){}
方式2 函數表達式(匿名函數)
var fn = function(){}
方式3 new Function()
var f = new Function('a', 'b', 'console.log(a + b)');
f(1, 2);
var fn = new Function('參數1','參數2'..., '函數體')
注意
/*Function 裏面參數都必須是字符串格式
第三種方式執行效率低,也不方便書寫,因此較少使用
所有函數都是 Function 的實例(對象)
函數也屬於對象
*/
/* 1. 普通函數 */
function fn() {
console.log('人生的巔峯');
}
fn();
/* 2. 對象的方法 */
var o = {
sayHi: function() {
console.log('人生的巔峯');
}
}
o.sayHi();
/* 3. 構造函數*/
function Star() {};
new Star();
/* 4. 綁定事件函數*/
btn.onclick = function() {}; // 點擊了按鈕就可以調用這個函數
/* 5. 定時器函數*/
setInterval(function() {}, 1000); 這個函數是定時器自動1秒鐘調用一次
/* 6. 立即執行函數(自調用函數)*/
(function() {
console.log('人生的巔峯');
})();
- 函數內部的this指向
this執行只有在調用函數的時候才確定、一般指向調用者
- 改變函數內部 this 指向的方法
call()方法、呼叫的意思、主要用於實現繼承、
作用、1、調用方法、2、改變this指向
apply()方法、應用、運用的意思、
作用、1、調用方法、2、改變this指向
不同的是參數必須是數組(僞)
bind()方法、捆綁、綁定的意思、
作用、1、不會調用函數、2、改變this指向
拷貝原來的函數改變this、返回一個新的函數
用於:不想立即執行函數、又想改變這個函數內部的this執行時用bind()
例如定時器、我想觸發時才調用
- call、apply、bind三者的異同
共同點 : 都可以改變this指向
不同點:
call 和 apply 會調用函數, 並且改變函數內部this指向.
call 和 apply傳遞的參數不一樣,call傳遞參數使用逗號隔開,apply使用數組傳遞
bind 不會調用函數, 可以改變函數內部this指向.
應用場景
1. call 經常做繼承.
2. apply經常跟數組有關係. 比如藉助於數學對象實現數組最大值最小值
3. bind 不調用函數,但是還想改變this指向. 比如改變定時器內部的this指向.
-
嚴格模式
通過嚴格模式去解決一些不合理、不規範的地方 -
開啓嚴格模式
–爲腳本開啓嚴格模式:讓use strict模式作用與全局作用域
(function (){
//在當前的這個自調用函數中有開啓嚴格模式,當前函數之外還是普通模式
"use strict";
var num = 10;
function fn() {}
})();
//或者
<script>
"use strict"; //當前script標籤開啓了嚴格模式
</script>
– 爲函數開啓嚴格模式 :讓use strict模式作用於局部作用域
要給某個函數開啓嚴格模式,需要把“use strict”; (或 ‘use strict’; ) 聲明放在函數
體所有語句之前。
function fn(){
"use strict";
return "123";
}
//當前fn函數開啓了嚴格模式
- 嚴格模式中的變化
'use strict'
num = 10
console.log(num)//嚴格模式後使用未聲明的變量
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
‐‐‐‐‐‐‐
var num2 = 1;
delete num2;//嚴格模式不允許刪除變量
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
‐‐‐‐‐‐‐
function fn() {
console.log(this); // 嚴格模式下全局作用域中函數中的 this 是 undefined
}
fn();
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
‐‐‐‐‐‐‐‐
function Star() {
this.sex = '男';
}
// Star();嚴格模式下,如果 構造函數不加new調用, this 指向的是undefined 如果給
他賦值則 會報錯.
var ldh = new Star();
console.log(ldh.sex);
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
‐‐‐‐‐‐‐‐‐
setTimeout(function() {
console.log(this); //嚴格模式下,定時器 this 還是指向 window
}, 2000);
- 高階函數
傳遞的是函數或者返回的是函數就是高階函數
- 閉包
–變量的作用域
變量根據作用域的不同分爲兩種:全局變量和局部變量。
- 函數內部可以使用全局變量。
- 函數外部不可以使用局部變量。
- 當函數執行完畢,本作用域內的局部變量會銷燬。
- 什麼是閉包
閉包指一個函數訪問另一個函數中的局部變量
<script>
// 閉包(closure)指有權訪問另一個函數作用域中變量的函數。
// 閉包: 我們fun 這個函數作用域 訪問了另外一個函數 fn 裏面的局部變量 num
function fn() {
var num = 10;
function fun() {
console.log(num);
}
fun();
}
fn();
</script>
閉包的作用
延伸了變量的作用範圍、 延長了變量的生命週期、
function fn() {
var num = 10;
function fun() {
console.log(num);
}
return fun;
}
var f = fn();
f();
- 利用閉包的方式得到當前li 的索引號
for (var i = 0; i < lis.length; i++) {
// 利用for循環創建了4個立即執行函數
// 立即執行函數也成爲小閉包因爲立即執行函數裏面的任何一個函數都可以使用它的i這變
量
(function(i) {
lis[i].onclick = function() {
console.log(i);
}
})(i);
}
- 閉包應用-3秒鐘之後,打印所有li元素的內容
for (var i = 0; i < lis.length; i++) {
(function(i) {
setTimeout(function() {
console.log(lis[i].innerHTML);
}, 3000)
})(i);
}
- 閉包應用-計算打車價格
/*需求分析
打車起步價13(3公里內), 之後每多一公里增加 5塊錢. 用戶輸入公里數就可以計算打車
價格
如果有擁堵情況,總價格多收取10塊錢擁堵費*/
var car = (function() {
var start = 13; // 起步價 局部變量
var total = 0; // 總價 局部變量
return {
// 正常的總價
price: function(n) {
if (n <= 3) {
total = start;
} else {
total = start + (n ‐ 3) * 5
}
return total;
},
// 擁堵之後的費用
yd: function(flag) {
return flag ? total + 10 : total;
}
}
})();
console.log(car.price(5)); // 23
console.log(car.yd(true)); // 33
思考題
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function() {
return function() {
return this.name;
};
}
};
console.log(object.getNameFunc()())
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
‐‐‐‐‐‐‐‐‐‐
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function() {
var that = this;
return function() {
return that.name;
};
}
};
console.log(object.getNameFunc()())
- 遞歸
– 什麼是遞歸
簡單理解:函數內部自己調用自己, 這個函數就是遞歸函數
作用:重複執行某段代碼
注意:遞歸函數的作用和循環效果一樣,由於遞歸很容易發生“棧溢出”錯誤(stack overflow),所以必須要加退出條件return。
//利用遞歸函數求1~n的階乘 1 * 2 * 3 * 4 * ..n
function fn(n) {
if (n == 1) { //結束條件
return 1;
}
return n * fn(n ‐ 1);
}
console.log(fn(3));