JavaScript 函數

函數

由于JavaScript的函數也是一個對象,所以類似function abs(v){}函數實際上是一個函數對象,而函數名abs可以視為指向該函數的變量。

因此,第二種定義函數的方式如下:

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

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

此方式按照完整語法需要在函數體末尾加一個;表示賦值語句結束。

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

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

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

abs(); // 返回NaN

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

要避免收到undefined,可以對參數進行檢查:

if (typeof x !== 'number') {throw 'Not a number';
}

arguments

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

function foo(x) {alert(x); // 10for (var i=0; i<arguments.length; i++) {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(); // 0 
abs(10); // 10 
abs(-9); // 9

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

// foo(a[, b], c)// 接收2~3個參數,b是可選參數,如果只傳2個參數,b默認為null:
function foo(a, b, c) {if (arguments.length === 2) {        // 實際拿到的參數是a和b,c為undefinedc = b; // 把b賦給cb = null; // b變為默認值
    }
}

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

rest參數

function foo(a, b, ...rest) {console.log('a = ' + a);console.log('b = ' + b);console.log(rest);
}

rest參數只能寫在最后,前面用...標識,從運行結果可知,傳入的參數先綁定ab,多余的參數以數組形式交給變量rest,所以,不再需要arguments我們就獲取了全部參數。

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

小心你的return語句

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

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

如果把return語句拆成兩行:

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

要小心了,由于JavaScript引擎在行末自動添加分號的機制,上面的代碼實際上變成了:

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

所以正確的多行寫法是:

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

全局作用域

不在任何函數內定義的變量就具有全局作用域。實際上,JavaScript默認有一個全局對象window,全局作用域的變量實際上被綁定到window的一個屬性:

var course = 'Learn JavaScript';
alert(course); // 'Learn JavaScript'
alert(window.course); // 'Learn JavaScript'

因此,直接訪問全局變量course和訪問window.course是完全一樣的。

你可能猜到了,由于函數定義有兩種方式,以變量方式var foo = function () {}定義的函數實際上也是一個全局變量,因此,頂層函數的定義也被視為一個全局變量,并綁定到window對象:

'use strict';function foo() {alert('foo');
}
foo(); // 直接調用foo()
window.foo(); // 通過window.foo()調用

進一步大膽地猜測,我們每次直接調用的alert()函數其實也是window的一個變量:

window.alert('調用window.alert()');
// 把alert保存到另一個變量:
var old_alert = window.alert;
// 給alert賦一個新函數:
window.alert = function () {}
// 恢復alert:
window.alert = old_alert;
alert('又可以用alert()了!');

這說明JavaScript實際上只有一個全局作用域。任何變量(函數也視為變量),如果沒有在當前函數作用域中找到,就會繼續往上查找,最后如果在全局作用域中也沒有找到,則報ReferenceError錯誤。?

變量作用域


在JavaScript中,用var申明的變量實際上是有作用域的。

如果一個變量在函數體內部申明,則該變量的作用域為整個函數體,在函數體外不可引用該變量:

'use strict';function foo() {var x = 1;x = x + 1;
}x = x + 2; // ReferenceError! 無法在函數體外引用變量x

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

'use strict';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 y = x + 1; // bar可以訪問foo的變量x!}
var z = y + 1; // ReferenceError! 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); // 1
    bar();
}

這說明JavaScript的函數在查找變量時從自身函數定義開始,從“內”向“外”查找。如果內部函數定義了與外部函數重名的變量,則內部函數的變量將“屏蔽”外部函數的變量。

變量提升

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

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

雖然是strict模式,但語句var x = 'Hello, ' + y;并不報錯,原因是變量y在稍后申明了。但是alert顯示Hello, undefined,說明變量y的值為undefined。這正是因為JavaScript引擎自動提升了變量y的聲明,但不會提升變量y的賦值。

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

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

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

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

全局作用域

不在任何函數內定義的變量就具有全局作用域。實際上,JavaScript默認有一個全局對象window,全局作用域的變量實際上被綁定到window的一個屬性:

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

因此,直接訪問全局變量course和訪問window.course是完全一樣的。

你可能猜到了,由于函數定義有兩種方式,以變量方式var foo = function () {}定義的函數實際上也是一個全局變量,因此,頂層函數的定義也被視為一個全局變量,并綁定到window對象:

function foo() {alert('foo');
}
foo(); // 直接調用foo()
window.foo(); // 通過window.foo()調用

進一步大膽地猜測,我們每次直接調用的alert()函數其實也是window的一個變量:

window.alert('調用window.alert()');
// 把alert保存到另一個變量:
var old_alert = window.alert;
// 給alert賦一個新函數:
window.alert = function () {}
// 恢復alert:
window.alert = old_alert;
alert('又可以用alert()了!');
這說明JavaScript實際上只有一個全局作用域。任何變量(函數也視為變量),如果沒有在當前函數作用域中找到,就會繼續往上查找,最后如果在全局作用域中也沒有找到,則報ReferenceError錯誤。

名字空間

全局變量會綁定到window上,不同的JavaScript文件如果使用了相同的全局變量,或者定義了相同名字的頂層函數,都會造成命名沖突,并且很難被發現。

減少沖突的一個方法是把自己的所有變量和函數全部綁定到一個全局變量中。例如:

// 唯一的全局變量MYAPP:
var MYAPP = {};
// 其他變量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;// 其他函數:
MYAPP.foo = function () {return 'foo';
};

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

許多著名的JavaScript庫都是這么干的:jQuery,YUI,underscore等等。

局部作用域

由于JavaScript的變量作用域實際上是函數內部,我們在for循環等語句塊中是無法定義具有局部作用域的變量的:

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

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

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

常量

由于varlet申明的是變量,如果要申明一個常量,

const PI = 3.14;

方法

var xiaoming = {name: '小明',birth: 1990,age: function () {var y = new Date().getFullYear();return y - this.birth;}
};
xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年調用是25,明年調用就變成26了

綁定到對象上的函數稱為方法,和普通函數也沒啥區別,但是它在內部使用了一個this關鍵字,這個東東是什么? 在一個方法內部,this是一個特殊變量,它始終指向當前對象,也就是xiaoming這個變量。所以,this.birth可以拿到xiaomingbirth屬性。

More:http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/0014345005399057070809cfaa347dfb7207900cfd116fb000

?

?

?

轉載于:https://www.cnblogs.com/284628487a/p/5548431.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/372901.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372901.shtml
英文地址,請注明出處:http://en.pswp.cn/news/372901.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Http Invoker的Spring Remoting支持

Spring HTTP Invoker是Java到Java遠程處理的重要解決方案。 該技術使用標準的Java序列化機制通過HTTP公開服務&#xff0c;并且可以被視為替代解決方案&#xff0c;而不是Hessian和Burlap中的自定義序列化。 而且&#xff0c;它僅由Spring提供&#xff0c;因此客戶端和服務器應…

mysql 日期列表_MySQL 生成日期表

1、創建一個num表&#xff0c;用來存儲數字0~9CREATE TABLE num (i int);2、在num表中生成0~9INSERT INTO num (i) VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);3、生成一個存儲日期的表&#xff0c;datalist是字段名CREATE TABLE if not exists calendar(dateli…

學習后綴自動機想法

小序&#xff1a;學習后綴自動機是要有耐心的&#xff0c;clj的論文自己看真心酸爽&#xff01;&#xff08;還是自己太弱&#xff0c;ls&#xff0c;oyzx好勁啊&#xff0c;狂膜不止&#xff09; 剛剛在寫博客之前又看了篇論文&#xff0c;終于看懂了&#xff0c;好開心 正文&…

【BZOJ】3575: [Hnoi2014]道路堵塞

題目鏈接&#xff1a;http://www.lydsy.com/JudgeOnline/problem.php?id3575 大概的做法是&#xff0c;按照順序枚舉每一條要刪去的邊&#xff0c;(假設當前點為$u$&#xff0c;在最短路徑上的下一個點是$v$)然后強制不走${u->v}$這條邊&#xff0c;將$u$入隊&#xff0c;做…

結合使用slf4j和Logback教程

在當前文章中&#xff0c;我將向您展示如何配置您的應用程序以使用slf4j和logback作為記錄器解決方案。 Java簡單日志記錄外觀&#xff08;slf4j&#xff09;是各種日志記錄框架的簡單外觀&#xff0c;例如JDK日志記錄&#xff08;java.util.logging&#xff09;&#xff0c;lo…

mysql 分組top_MySQL:如何查詢出每個分組中的 top n 條記錄?

問題描述需求&#xff1a;查詢出每月 order_amount(訂單金額) 排行前3的記錄。例如對于2019-02&#xff0c;查詢結果中就應該是這3條&#xff1a;解決方法MySQL 5.7 和 MySQL 8.0 有不同的處理方法。1. MySQL 5.7我們先寫一個查詢語句。根據 order_date 中的年、月&#xff0c;…

ACM第四站————最小生成樹(普里姆算法)

對于一個帶權的無向連通圖&#xff0c;其每個生成樹所有邊上的權值之和可能不同&#xff0c;我們把所有邊上權值之和最小的生成樹稱為圖的最小生成樹。 普里姆算法是以其中某一頂點為起點&#xff0c;逐步尋找各個頂點上最小權值的邊來構建最小生成樹。 其中運用到了回溯&#…

利用jenkins的api來完成相關工作流程的自動化

[本文出自天外歸云的博客園] 背景 1. 實際工作中涉及到安卓客戶端方面的測試&#xff0c;外推或運營部門經常會有很多的渠道&#xff0c;而每個渠道都對應著一個app的下載包&#xff0c;這些渠道都記錄在安卓項目下的一個渠道列表文件中。外推或運營部門經常會有新的渠道產生&a…

擁有成本分析:Oracle WebLogic Server與JBoss

Crimson Consulting Group 撰寫的非常有趣的白皮書 &#xff0c;比較了Weblogic和JBoss之間的擁有成本 。 盡管JBoss是免費的&#xff0c;但該白皮書卻嚴肅地宣稱&#xff0c;從長遠來看&#xff0c;Weblogic更便宜。 盡管此研究是由Oracle贊助的&#xff0c;但它看起來非常嚴肅…

mysql limit 分頁 0_Mysql分頁之limit用法與limit優化

Mysql limit分頁語句用法與Oracle和MS SqlServer相比&#xff0c;mysql的分頁方法簡單的讓人想哭。--語法&#xff1a;SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset--舉例&#xff1a;select * from table limit 5; --返回前5行select * from table limit 0…

與硒的集成測試

總覽 我已經使用了一段時間&#xff0c;遇到了一些似乎可以使生活更輕松的事情。 我以為可以將其作為教程分享&#xff0c;所以我將向您介紹這些部分&#xff1a; 使用Maven設置Web項目&#xff0c;配置Selenium以在CI上作為集成測試運行 尋找使用“頁面對象”為網站中的頁面…

linux每天一小步---sed命令詳解

1 命令功能 sed是一個相當強大的文件處理編輯工具&#xff0c;sed用來替換&#xff0c;刪除&#xff0c;更新文件中的內容。sed以文本行為單位進行處理&#xff0c;一次處理一行內容。首先sed吧當前處理的行存儲在臨時的緩沖區中&#xff08;稱為模式空間pattern space&#xf…

mysql trace工具_100% 展示 MySQL 語句執行的神器-Optimizer Trace

在上一篇文章《用Explain 命令分析 MySQL 的 SQL 執行》中&#xff0c;我們講解了 Explain 命令的詳細使用。但是它只能展示 SQL 語句的執行計劃&#xff0c;無法展示為什么一些其他的執行計劃未被選擇&#xff0c;比如說明明有索引&#xff0c;但是為什么查詢時未使用索引等。…

MOXy作為您的JAX-RS JSON提供程序–服務器端

在以前的系列文章中&#xff0c;我介紹了如何利用EclipseLink JAXB&#xff08;MOXy&#xff09;創建RESTful數據訪問服務。 在本文中&#xff0c;我將介紹在服務器端利用MOXy的新JSON綁定添加對基于JAXB映射的JSON消息的支持有多么容易。 MOXy作為您的JAX-RS JSON提供程序–服…

006_過濾器

過濾器 過濾器&#xff08;Filter&#xff09;把附加邏輯注入到MVC框的請求處理&#xff0c;實現了交叉關注。所謂交叉關注&#xff08;Cross-Cutting Concerns&#xff09;&#xff0c;是指可以用于整個應用程序&#xff0c;而又不適合放置在某個局部位置的功能&#xff0c;否…

Android_項目文件結構目錄分析

android項目文件結構目錄分析 在此我們新建了一個helloworld的項目&#xff0c;先看一些目錄結構&#xff1a; 這么多的文件夾和文件中&#xff0c;我們重點關注是res目錄、src目錄、AndroidManifest.xml文件&#xff1a; 一、res目錄主要是用來存放android項目的各種資源文件&…

實體 聯系 模型mysql_數據庫系統概念讀書筆記――實體-聯系模型_MySQL

bitsCN.com數據庫系統概念讀書筆記——實體-聯系模型前言為了重新回顧我寫的消息系統架構&#xff0c;我需要重新讀一下數據庫系統概念的前三章&#xff0c;這里簡單的做一個筆記&#xff0c;方便自己回顧基本概念實體-聯系(E-R)數據模型基于對現實世界的這樣一種認識&#xff…

使用Twitter Bootstrap,WebSocket,Akka和OpenLayers玩(2.0)

原始帖子可以在ekito網站上找到。 對于我們的一位客戶&#xff0c;我們需要顯示一張具有實時更新的車輛位置的地圖。 因此&#xff0c;我開始使用Play制作原型&#xff01; 框架及其最新發布的版本2.0&#xff0c;使用Java API。 我從Play的網絡聊天室開始&#xff01; 2.0個樣…

同步時間

同步時間 [rootlocalhost 03]# ntpdate 0.centos.pool.ntp.org 轉載于:https://www.cnblogs.com/cglWorkBook/p/5556920.html