JavaScript裡的函式

Yjjtt發表於2019-02-26

函式

函式, function, 是一個關鍵字, 表示宣告一個函式, 是一個變數的特例.

每一個函式,都必須有一個return, 如果不寫return, 預設會新增return undefined.

函式本質

函式就是將做一件相同事情的程式碼整合到一起,作為程式碼塊, 可以被反覆呼叫,可以執行程式碼的物件就是函式.

函式的五種宣告方式

  1. 具名函式
function x(input1, input2){ return }
複製程式碼
  1. 匿名函式
var x = function(input1, input2){ return }
// 匿名函式必須給一個變數
複製程式碼
  1. 具名函式賦值
var x = function y(input1, input2){ return }
複製程式碼
  1. Window.function
var x = new Function('x', 'y', 'return x + y')
複製程式碼
  1. 箭頭函式
var x = (x, y) => { return x + y}
var x = (x, y) => { let n = x * 3; let m = y * 4; return n + m;}
複製程式碼

具名函式和具名函式賦值兩種宣告的區別:

不一致性, 作用域不同, 垃圾特性.

分別宣告具名函式和具名函式賦值, 並console.log(函式):

JavaScript裡的函式

JavaScript裡的函式

console.log()原理

console.log = function(a){
    alert(a)
    return undefined
}
// 由此可見, console.log 永遠返回undefined, 返回什麼和列印什麼 一點關係沒有
複製程式碼

函式的name屬性

var f2 = function(){}
f2.name = "f2";

var f3 = function f4(){}
f3.name = "f4"

var f5 = new Function('x','y','return x + y')
f5.name = "anonymous" // 匿名的意思
複製程式碼

如何呼叫函式

function f(x,y){ return x + y }

f(1,2) // 3

// 骨灰級寫法, 真正的函式呼叫
f.call(undefined, 1, 2)

複製程式碼

call()原理:

var f = new Function('x','y','console.log(1)')
f.call() // 1
// Function建構函式, 除了最後一個引數是函式體, 其他的都是引數
// 分解如下
var f = {};
f.parmas = ['x','y'];
f.functionBody = 'console.log(1)';
f.call = function(){
    window.eval(f.functionBody)
}
f.call() // 1
複製程式碼

由上可得出: 為什麼說函式是物件, 因為呼叫的過程就是執行eval函式體的過程, 可以執行程式碼的物件就是函式

f和f.call()的區別:

f 是物件, f.call 是執行物件的函式體

this 和 arguments

call()的第一個引數可以用this得到.後面的引數可以用arguments得到.

  • this

上述程式碼中f.call(undefined, 1, 2), undefined就是this, 當時要求JS必須長的像java, 所有強行加了this

  • arguments

上述程式碼中f.call(undefined, 1, 2), [1,2]就是arguments.

JavaScript裡的函式

  • arguments也是一個偽陣列, 因為長的像陣列, 原型鏈中沒有Array.prototype, 或者是____proto____沒有指向Array.prototype.
function f(){
    console.log(this)
}
f.call(1) // Number 物件 1


function f(){
    'use strict' // 嚴格模式
    console.log(this)
}
f.call(1) // 1
複製程式碼

作用域

作用域(scope)指的是變數存在的範圍。在 ES5 的規範中,Javascript 只有兩種作用域:一種是全域性作用域,變數在整個程式中一直存在,所有地方都可以讀取;另一種是函式作用域,變數只在函式內部存在.只要有函式就有作用域

作用域對應的資料結構是樹:

var a = 1;
function f(){
    console.log(a)
    var a = 2;
   
    function f2(){
        console.log(a)
    }
}
function f1(){
    var a = 3;
    console.log(a)
}

console.log(a)
f()

// 程式碼作用域如下圖:
複製程式碼

JavaScript裡的函式

  • 函式外部宣告的變數就是全域性變數(global variable),它可以在函式內部讀取。

  • 在函式內部定義的變數,外部無法讀取,稱為“區域性變數”(local variable)。

函式內部的變數提升

與全域性作用域一樣,函式作用域內部也會產生“變數提升”現象。var命令宣告的變數,不管在什麼位置,變數宣告都會被提升到函式體的頭部。

function f(){
    console.log(a);
    var a = 1;
}

// 等同於
function f(){
    var a;
    console.log(a);
    var a = 1;
}

// a 列印出undefined
複製程式碼

函式本身的作用域

函式本身也是一個值,也有自己的作用域。它的作用域與變數一樣,就是其宣告時所在的作用域,與其執行時所在的作用域無關。

var a = 1;
function x(){
    console.log(a);
}

function f(){
    var a = 2;
    x();
}
f(); // 1

// 等同於
var a;
a = 1;
function x(){
    console.log(a); // 1
}

function f(){
    var a;
    a = 2;
    x();
}
f();
複製程式碼

上面程式碼中,函式x是在函式f的外部宣告的,所以它的作用域繫結外層,內部變數a不會到函式f體內取值,所以輸出1,而不是2

總之,函式執行時所在的作用域,是定義時的作用域,而不是呼叫時所在的作用域.

閉包

如果一個函式, 使用了它範圍外的值, 那麼(這個函式+這個變數)就叫做閉包.

JavaScript裡的函式

相關文章