Function型別
Function型別是JS的引用型別之一 通過Function型別建立Function物件
在JS中 函式也以物件的形式存在
每個函式都是一個Function物件
console.log(Function instanceof Function) //true
console.log(Function instanceof Object) //true
console.log(Object instanceof Function) //true
建構函式
函式除了用函式定義語句和字面量表示式兩種方式定義之外 還可以通過Funcion型別進行定義
函式的引數和函式體都是以字串形式傳遞給Function的
var fun = new Function ('num','console.log(num)');
fun(100); //100
通過Function型別定義函式的效率遠不如函式定義語句和字面量表示式的定義
定義函式的三種方式之間存在一定差別
- 函式定義語句:執行時函式名被提前宣告 不存在效率問題
- 字面量表示式:函式體固定 無法動態執行 不存在效率問題
- Function型別定義 函式體是字串 可以動態執行 效率較低
Function的apply()方法
apply方法可以劫持另外一個物件的方法,繼承另外一個物件的屬性.
Function.apply(obj,arguments)方法能接收兩個引數(可選):
obj:這個物件將代替Function類裡this物件
arguments:這個引數是陣列,它將作為引數傳給Function
如果沒有obj引數 那麼Global物件被用作obj
//定義一個人類
function Person(name,age) {
this.name=name;
this.age=age;
}
//定義一個男人
function Man(name,age,hobby) {
Person.apply(this,arguments); //this代表的是man arguments是一個陣列 也就是['Sicong',30,'撕逼']
this.hobby=hobby;
}
var man=new Man('Sicong',30,'撕逼');
console.log("name:"+man.name +"\n"+ "age:"+man.age +"\n"+"hobby:"+man.hobby); //name:SicongWang age:30 hobby:撕逼
//用Man去執行Person這個類裡面的內容,在Person這個類裡面存在this.name等語句,這樣就將屬性建立到了student物件裡面
Function的call()方法
call方法與apply類似 只是第二個引數不是陣列
//定義一個人類
function Person(name,age) {
this.name=name;
this.age=age;
}
//定義一個woman
function Woman(name,age,hobby) {
Person.call(this,name,age); //this代表的是woman
this.hobby=hobby;
}
var woman=new Woman('TimoFeng',18,'唱歌');
console.log("name:"+woman.name +"\n"+ "age:"+woman.age +"\n"+"hobby:"+woman.hobby); //name:TimoFeng age:18 hobby:唱歌
Function的bind()方法
bind方法與call和apply類似 第一個引數都是this要指向的物件 利用後續引數傳引數
不同的是bind是返回對應的函式 可以稍後呼叫;call和apply是立即呼叫
var fn=function () {
console.log(this.x)
};
var foo={
x:3
};
fn(); //undefined
console.log(fn.bind(foo)); //ƒ () {
// console.log(this.x) }
// 此時this已經指向了foo,但是用bind()方法並不會立即執行,而是建立一個函
// 數 如果要直接呼叫的話 可以 bar.bind(foo)()
var result=fn.bind(foo);
result(); //3
遞迴
在函式內部,可以呼叫其他函式。如果一個函式在內部呼叫自身本身,這個函式就是遞迴函式
遞迴函式的優點是定義簡單,邏輯清晰 所有的遞迴函式都可以寫成迴圈的方式,但迴圈的邏輯不如遞迴清晰
遞迴呼叫的次數過多,會導致棧溢位 使用過深會造成死迴圈
var num=function(x){
if(x == 1){
return 1;
} else{
return x*num(x-1);
}
}
console.log(num(5)) //120
/* 計算過程為:
---> num(5)
---> 5 * num(4)
---> 5 * (4 * num(3))
---> 5 * (4 * (3 * num(2)))
---> 5 * (4 * (3 * (2 * num(1))))
---> 5 * (4 * (3 * (2 * 1))) 只有n=1時才特殊處理
---> 5 * (4 * (3 * 2))
---> 5 * (4 * 6)
---> 5 * 24
---> 120
*/
回撥函式
一個函式作為引數傳給另一個函式 我們把另一個函式稱為回撥函式
通俗的說回撥函式有3個特點: 1).你定義的 2).你沒有呼叫 3).但最後執行了
回撥函式的優點:
- 可以在未命名的情況下傳遞函式 節省全域性變數
- 將另一個函式呼叫操作委託給另一個函式
- 有助於提升效能
$('btn').click(function(){ //click方法就是一個回撥函式
alert('我是一個按鈕')
})
自呼叫函式
自呼叫函式 宣告完了,馬上進行呼叫,只能使用一次
(function(num1,num2){
console.log(num1+num2)
})(10,20) //30
作用域和作用域鏈
作用域: 一塊程式碼區域, 在編寫時就確定, 不會再變化
作用域鏈: 多個巢狀的作用域形成的由內向外的結構, 用於查詢變數
分為全域性作用域和函式(區域性)作用域
作用:
作用域: 隔離變數, 可以在不同作用域定義同名的變數不衝突
作用域鏈: 查詢變數
var num1=10; //全域性變數
function fn1(){
var num2=20; //fn1作用域的區域性變數
function fn2(){
var num3=30; //fn2作用域的區域性變數
function fn3(){
var num4=40; //fn3作用域的區域性變數
console.log(num1); //10
console.log(num2); //20
console.log(num3); //30
console.log(num4); //40
}
fn3();
console.log(num1); //10
console.log(num2); //20
console.log(num3); //30
console.log(num4); //num4 is not defined
}
fn2();
console.log(num1); //10
console.log(num2); //20
console.log(num3); //num3 is not defined
console.log(num4); //num4 is not defined
}
fn1()
閉包函式
當巢狀的內部函式引用了外部函式的變數時就產生了閉包
閉包本質是內部函式中的一個物件, 這個物件中包含引用的變數屬性
作用:
延長區域性變數的生命週期
讓函式外部能操作內部的區域性變數
避免汙染全域性名稱空間
缺點:
變數佔用記憶體的時間可能會過長
可能導致記憶體洩露(佔用的記憶體沒有及時釋放
記憶體洩露積累多了就容易導致記憶體溢位)
function fn1() {
var a = 2;
function fn2() {
a++;
console.log(a); //3 4
}
return fn2;
}
var f = fn1();
f();
f();