Function型別

RoOK1E發表於2018-08-15

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型別定義函式的效率遠不如函式定義語句和字面量表示式的定義
定義函式的三種方式之間存在一定差別

  1. 函式定義語句:執行時函式名被提前宣告 不存在效率問題
  2. 字面量表示式:函式體固定 無法動態執行 不存在效率問題
  3. 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();

相關文章