JavaScript 基礎函數_深入剖析變數和範圍,javascript深入剖析

來源:互聯網
上載者:User

JavaScript 基礎函數_深入剖析變數和範圍,javascript深入剖析

函數定義和調用

定義函數,在JavaScript中,定義函數的方式如下:

function abs(x){ if(x >=0){ return x;}else{ return -x;}}

上述abs() 函數的定義如下:

function 指出這是一個函數定義;

abs 是函數的名稱;

(x) 括弧內列出函數的參數,多個參數以,分隔;

{...}之間的代碼是函數體,可以包含若干語句,甚至可以沒有任何語句。

注意:函數體內部的語句在執行時,一旦執行到return 時,函數就執行完畢,並將結果返回。因此內部通過條件判斷和迴圈可以在實現非常複雜的。

如果沒有return語句,函數執行完畢後也會返回結果,只是結果為undefined。

由於JavaScript的函數也是一個對象,上述定義的abs()函數實際上是一個函數對象,而函數名abs可以視為指向該函數的變數。

var abs = function(x){ if(x >= 0){ return x;} else { return -x;}}

在這種方式下,function (x) { ... }是一個匿名函數,它沒有函數名。但是,這個匿名函數賦值給了變數abs,所以,通過變數abs就可以調用該函數。

兩種定義完全等價,注意第二種方式按照完整文法需要在函數體末尾加一個;,表示指派陳述式結束。

調用函數時,按順序傳入參數即可:

abs(10); // 返回10
abs(-9); // 返回9

由於JavaScript 允許傳入任意個參數而不受影響調用,因此傳入的參數比定義的參數多也沒有問題,雖然函數內部並不需要這些參數。

abs(10,'blablabla'); //返回10
abs(-9,'haha','hehe',null) // 返回9

傳入的參數比定義的少也沒有問題

abs(); 返回NaN

此時abs(x)函數的參數x 將收到undefined,計算結果為NaN

function abs(x){ if(typeof x !=='number'){ throw 'Not a number':} if(x >=0){ return x;}else{ return -x;}}

arguments

JavaScript 還有一個免費贈送的關鍵字 arguments,它只在函數內部起作用,並且永遠指向當前函數的調用者傳入的所有參數。

function foo(x){ alert(x); // 10for(var i=0; i < arguments.length;++){ alert(arguments[i]); // 10,20,30}}foo(10.20,30)

利用arguments,你可以獲得調用者傳入的所有參數。也就是說,即使函數不定義任何參數,還是可以拿到參數的值:

function abs(){ if(arguments.length ===0){ return 0;}var x = arguments[0]return x >=0 ? x : -x;}abs(); //0abs(10); // 10abs(-9) //9

實際上arguments最常用於判斷傳入參數的個數。你可能會看到這樣的寫法:

// foo(a[,b],c)

//接受2~3 個參數,b 是選擇性參數,如果只要出入兩個參數,b預設為null

function foo(a,b,c){ if(arguments.length ===2){ // 實際拿到的參數是a 和b c 為undefinedc = b;b = null; // b 變為預設值

要把中間的參數b變為“可選”參數,就只能通過arguments判斷,然後重新調整參數並賦值。

rest 參數

由於JavaScript 函數允許接收任意個參數,遇事我們就不得不用arguments 來擷取所有的參數:

function foo(a,b){ var i, rest = [];if(arguments.length > 2){ for(i = 2; i < arguments.length; i++){ rest.push(arguments[i]);}}console.log('a =' + a);console.log('b = ' + b);console.log(rest);}

為了擷取除了已定義參數a、b之外的參數,我們不得不用arguments,並且迴圈要從索引2開始以便排除前兩個參數,這種寫法很彆扭,只是為了獲得額外的rest參數,有沒      有更好的方法?

ES6標準引入了rest參數,上面的函數可以改寫為:

function foo(a,b,...rest){ console.log('a = ' + a);console.log('b = ' + b);console.log(rest);}foo(1,2,3,4,5);//結果// a = 1// b = 2// Array[3,4,5]foo(1)// 結果// a = 1// b = undefined// Array []

rest 參數只能寫在最後,前面用... 標示,從運行結果可知,傳入的參數先綁定 a , b, 多餘的參數以數組形式交給變數 rest,所以,

不在需要 arguments 我們就擷取了全部參數。

如果傳入的參數連正常定義的參數都沒填滿,也不要緊,rest參數會接收一個空數組(注意不是undefined)。

return 語句

前面我們講到了JavaScript引擎有一個在行末自動添加分號的機制,這可能讓你栽到return語句的一個大坑:、

function foo(){ return {name:'foo'};}foo(); // {name:'foo'}

要注意:

function foo(){ return: //自動添加了分號,相當於return undefined{name:'foo'}; // 這行語句已經沒法執行到了。}

所以正確的多行寫法是

function foo(){ return { // 這裡不會自動加分號,因為表示語句尚未結束。name:'foo'}}

變數範圍

在JavaScript 中,用var 聲明的實際上是有範圍的。

如果一個變數在函數體內部申明,則該變數的範圍為整個函數體,在函數體外不該引用該變數。

‘use strict':function foo(){ var x = 1;x = x +1;}x = x +2; // RefrenceError 無法在函數體外引用該該變數x

如果兩個不同的函數各自申明了同一個變數,那麼該變數只在各自的函數體內起作用。換句話說,不同函數內部的同名變數互相獨立,互不影響:

'use struct':function foo(){ var x = 1;x = x +1;}function bar (){ var x= 'A';x = x + 'B';}

由於JavaScript的函數可以嵌套,此時,內建函式可以訪問外部函數定義的變數,反過來則不行:

'use strict';function foo(){ var x =1;function bar(){ var x = 1;function bar(){ var y= x +1; //bar 可以訪問foo 的變數x}var z = y + 1; //RefernceError! foo 不可以訪問bar 的變數y!}}

如果內建函式和外部函數的變數名重名怎麼辦?

'use strict':function foo(){ var x = 1;function bar (){ var x = 'A';alert('x in bar() =' + x); // 'A'}alert('x in foo()=' +x) //1bar();}

變數提升

JavaScript的函數定義有個特點,它會先掃描整個函數體的語句,把所有申明的變數“提升”到函數頂部:

'use strict';function foo(){ var x='Hello,'+y;alert(x);var y = 'Bob';}foo();

對於上述foo()函數,JavaScript引擎看到的代碼相當於:

function foo(){ var y; // 提升變數y的var x = 'Hello' + y;alert(x);y = 'Bob';}

由於JavaScript的這一怪異的“特性”,我們在函數內部定義變數時,請嚴格遵守“在函數內部首先申明所有變數”這一規則。最常見的做法是用一個var申明函數內部用到的所有變數:

function foo(){ var x =1, // x 初始化為1y = x +1, // y 初始化為2z,i; // z和i 為undefined// 其他語句for(i =0; i<100; i++){ ...}}

全域範圍

不在任何函數內定義的變數就具有全域範圍,實際上,JavaScript 預設有一個全域範圍的變數實際上唄綁定到window 的一個屬性。

‘use strict';var sourse = 'Learn JavaScript';alert(course); // 'Learn JavaScript';alert(window.course); // 'Learn JavaScript'

名字空間

全域變數會綁定到window 上,不同的JavaScript 檔案如果使用相同的全域變數,或者定義了相同名字的頂層函數,都會造成

命名衝突,並且很難被發現,

減少衝突的一個方法是把自己的所有的變數和函數全部綁定到一個全域變數中。

// 唯一的曲劇變數MYAPPvar MYAPP = {};//其他變數:MYAPP.name = 'myapp';MYAPP.version = 1.0;// 其他函數MYAPP.foo = function (){ return 'foo';};

把自己的代碼全部放入唯一的名字空間MYAPP中,會大大減少全域變數衝突的可能。

局部範圍

由於JavaScript 的變數範圍實際上是函數內部,我們在for 迴圈等語句塊中是無法定義具有無法定義具有局部範圍的變數的。

function foo(){ for(var i = 0; i<100; i++){ //}i+=100; // 仍然可以引用變數;}

為瞭解決塊級範圍,ES6引入了新的關鍵字let,用let替代var可以申明一個塊級範圍的變數:

function foo(){ var sum = 0;for(let i=0; i<100;i++){ sum +=i;}i +=1;}

常量

由於var 和let 聲明的變數,如果要聲明一個常量,在ES6 之前是不行的,我們通常用全部大寫的變數倆表示這是一個常量

不要修改他的值。

var PI = 3.14;
ES6標準引入了新的關鍵字const 來定義常量,const 與 let都具有塊級範圍;
const PI = 3.14;
PI = 3; // 某些瀏覽器不報錯,但是無效果。
PI; // 3.14

以上這篇JavaScript 基礎函數_深入剖析變數和範圍就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援幫客之家。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.