先決條件: | 基本的計(jì)算機(jī)素養(yǎng),對(duì)HTML和CSS的基本了解, JavaScript第一步。 |
---|---|
目的: | 了解JavaScript函數(shù)背后的基本概念。 |
在JavaScript中,你會(huì)發(fā)現(xiàn)函數(shù)無處不在。 事實(shí)上,到目前為止,我們一直使用函數(shù)直到整個(gè)過程; 我們只是沒有在說他們非常。 現(xiàn)在是時(shí)候,我們開始明確地談?wù)摵瘮?shù),并真正地探索他們的語法。
幾乎任何時(shí)候,你使用一個(gè)JavaScript結(jié)構(gòu),它具有一對(duì)括號(hào) - ()
- 并且不使用一個(gè)常見的內(nèi)置語言結(jié)構(gòu), a href ="/ en-US / Learn / JavaScript / Building_blocks / Looping_code#The_standard_for_loop"> for循環(huán), "> while或do ... while循環(huán),或 if ... else語句 >,你正在使用一個(gè)函數(shù)。
我們?cè)诒菊n程中使用了很多內(nèi)置到瀏覽器中的功能。 每次我們處理一個(gè)文本字符串,例如:
var myText = 'I am a string'; var newString = myText.replace('string', 'sausage'); console.log(newString); // the replace() string function takes a string, // replaces one substring with another, and returns // a new string with the replacement made
或者每次我們操縱數(shù)組:
var myArray = ['I', 'love', 'chocolate', 'frogs']; var madeAString = myArray.join(' '); console.log(madeAString); // the join() function takes an array, joins // all the array items together into a single // string, and returns this new string
或者每次我們生成一個(gè)隨機(jī)數(shù):
var myNumber = Math.random() // the random() function generates a random // number between 0 and 1, and returns that // number
...我們正在使用一個(gè)函數(shù)!
注意:您可以隨意在瀏覽器的JavaScript控制臺(tái)中輸入這些行,以便在需要時(shí)重新熟悉自己的功能。
JavaScript語言有許多內(nèi)置函數(shù),允許你做有用的事情,而不必自己編寫所有的代碼。 實(shí)際上,當(dāng)您調(diào)用(用于運(yùn)行或執(zhí)行)的內(nèi)置瀏覽器函數(shù)時(shí),您調(diào)用的某些代碼無法用JavaScript編寫 - 其中許多函數(shù)都是調(diào)用零件 的后臺(tái)瀏覽器代碼,這是寫在很大程度上低級(jí)系統(tǒng)語言,如C ++,而不是像JavaScript這樣的Web語言。
請(qǐng)記住,一些內(nèi)置的瀏覽器函數(shù)不是核心JavaScript語言的一部分 - 一些被定義為瀏覽器API的一部分,它建立在默認(rèn)語言之上以提供更多的功能(參考 en-US / Learn / JavaScript / First_steps / What_is_JavaScript#So_what_can_it_really_do">我們課程的這個(gè)早期部分了解更多說明)。 我們將在后面的模塊中更詳細(xì)地討論使用瀏覽器API。
在我們繼續(xù)之前我們需要清除一件事 - 技術(shù)上來說,內(nèi)置的瀏覽器函數(shù)不是函數(shù) - 它們是方法。 這聽起來有點(diǎn)可怕和混亂,但不要擔(dān)心 - 字的功能和方法在很大程度上是可互換的,至少對(duì)于我們的目的,在這個(gè)階段在你的學(xué)習(xí)。
區(qū)別在于方法是在對(duì)象內(nèi)定義的函數(shù)。 內(nèi)置瀏覽器函數(shù)(方法)和變量(稱為屬性)存儲(chǔ)在結(jié)構(gòu)化對(duì)象中,以使代碼更高效,更易于處理。
你不需要了解結(jié)構(gòu)化JavaScript對(duì)象的內(nèi)部工作 - 你可以等到我們后面的模塊教會(huì)你所有關(guān)于對(duì)象的內(nèi)部工作,以及如何創(chuàng)建自己的。 現(xiàn)在,我們只是想清除方法與功能的任何可能的混淆 - 當(dāng)您查看Web上可用的相關(guān)資源時(shí),您可能會(huì)遇到這兩個(gè)術(shù)語。
在過去的課程中,您還看到了很多自定義函數(shù) - 在代碼中定義的函數(shù),而不是瀏覽器中的函數(shù)。 任何時(shí)候,你看到一個(gè)自定義名稱后面帶括號(hào),你正在使用一個(gè)自定義函數(shù)。 在我們的 random-canvas-circles.html 示例(另請(qǐng)參閱完整的 ="external">源代碼),我們?cè)?a href="/webstart/Building_blocks/Looping_code">循環(huán)文章中添加了一個(gè)自定義 draw()
看起來像這樣:
function draw() { ctx.clearRect(0,0,WIDTH,HEIGHT); for (var i = 0; i < 100; i++) { ctx.beginPath(); ctx.fillStyle = 'rgba(255,0,0,0.5)'; ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); ctx.fill(); } }
此函數(shù)在 繪制圖形和動(dòng)畫。"> < canvas>
元素。 每次我們想要這樣做,我們可以調(diào)用這個(gè)函數(shù)
draw();
而不是每次我們想重復(fù)它時(shí)再次寫出所有的代碼。 函數(shù)可以包含任何你喜歡的代碼 - 你甚至可以從函數(shù)內(nèi)部調(diào)用其他函數(shù)。 上述函數(shù)例如調(diào)用 random()
函數(shù)三次,它由以下代碼定義:
function random(number) { return Math.floor(Math.random()*number); }
我們需要此功能,因?yàn)闉g覽器的內(nèi)置 Math.random() / a>函數(shù)只生成0和1之間的隨機(jī)十進(jìn)制數(shù)。我們想要一個(gè)介于0和指定數(shù)之間的隨機(jī)整數(shù)。
你現(xiàn)在可能清楚這一點(diǎn),但是為了防止...在定義后真正使用一個(gè)函數(shù),你必須運(yùn)行或調(diào)用它。 這是通過在代碼中包含函數(shù)的名稱,后跟括號(hào)來完成的。
function myFunction() { alert('hello'); } myFunction() // calls the function once
您可能會(huì)看到以稍微不同的方式定義和調(diào)用的函數(shù)。 到目前為止,我們剛剛創(chuàng)建了一個(gè)像這樣的函數(shù):
function myFunction() { alert('hello'); }
但是你也可以創(chuàng)建一個(gè)沒有名字的函數(shù):
function() { alert('hello'); }
這稱為匿名函數(shù) - 它沒有名稱! 它也不會(huì)自己做任何事情。 你通常使用一個(gè)匿名函數(shù)和一個(gè)事件處理程序,例如下面的代碼將在函數(shù)中運(yùn)行相關(guān)按鈕被點(diǎn)擊時(shí):
var myButton = document.querySelector('button'); myButton.onclick = function() { alert('hello'); }
上面的例子要求有一個(gè) "> < button>
元素,以選擇并點(diǎn)擊。 您已經(jīng)在整個(gè)課程中看過這種結(jié)構(gòu)幾次,您將在下一篇文章中了解更多并了解它的使用。
您還可以將匿名函數(shù)指定為變量的值,例如:
var myGreeting = function() { alert('hello'); }
此函數(shù)現(xiàn)在可以使用:
myGreeting();
這有效地給變量名稱; 您還可以將函數(shù)分配為多個(gè)變量的值,例如:
var anotherGreeting = function() { alert('hello'); }
此函數(shù)現(xiàn)在可以使用
myGreeting(); anotherGreeting();
但這只是混亂,所以不要這樣做! 當(dāng)創(chuàng)建函數(shù)時(shí),最好堅(jiān)持這種形式:
function myGreeting() { alert('hello'); }
您將主要使用匿名函數(shù)來運(yùn)行一個(gè)代碼負(fù)載,以響應(yīng)事件觸發(fā)(如點(diǎn)擊按鈕)使用事件處理程序。 同樣,這看起來像這樣:
myButton.onclick = function() { alert('hello'); // I can put as much code // inside here as I want }
某些函數(shù)在調(diào)用它們時(shí)需要指定參數(shù) - 這些是需要包含在函數(shù)括號(hào)內(nèi)的值,它需要正確完成其工作。
注意:參數(shù)有時(shí)稱為參數(shù),屬性,甚至屬性。
例如,瀏覽器的內(nèi)置 Math.random() a>函數(shù)不需要任何參數(shù)。 當(dāng)調(diào)用時(shí),它總是返回一個(gè)0和1之間的隨機(jī)數(shù):
var myNumber = Math.random();
然而,瀏覽器的內(nèi)置字符串 replace()函數(shù)需要 兩個(gè)參數(shù) - 要在主字符串中查找的子字符串,以及用以下代替該字符串的子字符串:
var myText = 'I am a string'; var newString = myText.replace('string', 'sausage');
注意:當(dāng)您需要指定多個(gè)參數(shù)時(shí),它們之間用逗號(hào)分隔。
還應(yīng)該注意,有時(shí)參數(shù)是可選的 - 您不必指定它們。 如果你不這樣做,函數(shù)通常會(huì)采用某種默認(rèn)行為。 例如,數(shù)組 join()函數(shù)的參數(shù)為 可選的:
var myArray = ['I', 'love', 'chocolate', 'frogs']; var madeAString = myArray.join(' '); // returns 'I love chocolate frogs' var madeAString = myArray.join(); // returns 'I,love,chocolate,frogs'
如果不包括用于指定加入/定界字符的參數(shù),則默認(rèn)使用逗號(hào)。
讓我們來談?wù)?a rel="external nofollow" target="_blank" target="_blank"> 值和表達(dá)式是"可見"或可以引用的上下文。 如果變量或其他表達(dá)式不是"在當(dāng)前作用域中",則它不可用。 范圍也可以在層次結(jié)構(gòu)中分層,以便子范圍可以訪問父范圍,反之亦然。\'scope - 處理函數(shù)時(shí)非常重要的概念。 當(dāng)創(chuàng)建一個(gè)函數(shù)時(shí),函數(shù)內(nèi)部定義的變量和其他東西都在它們自己的范圍內(nèi),這意味著它們被鎖定在它們自己的獨(dú)立區(qū)域中,從其他函數(shù)內(nèi)部無法訪問, 功能。
所有函數(shù)外的頂層稱為全局范圍。 在全局范圍中定義的值可以從代碼中的任何地方訪問。
JavaScript是這樣設(shè)置的各種原因 - 但主要是因?yàn)榘踩徒M織。 有時(shí)你不希望變量可以從代碼中的任何地方訪問 - 外部腳本,你從其他地方調(diào)用可能開始混亂你的代碼,并導(dǎo)致問題,因?yàn)樗麄兣銮墒褂孟嗤淖兞棵Q與代碼的其他部分 ,引起沖突。 這可能是惡意地,或只是偶然。
JavaScript是這樣設(shè)置的各種原因 - 但主要是因?yàn)榘踩徒M織。 有時(shí)你不希望變量可以從代碼中的任何地方訪問 - 外部腳本,你從其他地方調(diào)用可能開始混亂你的代碼,并導(dǎo)致問題,因?yàn)樗麄兣銮墒褂孟嗤淖兞棵Q與代碼的其他部分 ,引起沖突。 這可能是惡意地,或只是偶然。...
<!-- Excerpt from my HTML --> <script src="first.js"></script> <script src="second.js"></script> <script> greeting(); </script>
// first.js var name = 'Chris'; function greeting() { alert('Hello ' + name + ': welcome to our company.'); }
// second.js var name = 'Zaptec'; function greeting() { alert('Our company is called ' + name + '.'); }
你想調(diào)用的兩個(gè)函數(shù)都叫 greeting()
,但你只能訪問 second.js
文件的 greeting
在源代碼中應(yīng)用于HTML,因此其變量和函數(shù)覆蓋了 first.js
中的變量和函數(shù)。
注意:您可以看到此示例 >在GitHub上運(yùn)行(另見 源代碼)。
在函數(shù)中保留代碼的一部分可以避免這樣的問題,并且被認(rèn)為是最佳實(shí)踐。
它有點(diǎn)像一個(gè)動(dòng)物園。 獅子,斑馬,老虎和企鵝被保存在自己的外殼中,并且只能訪問其外殼內(nèi)的東西 - 與功能范圍相同。 如果他們能夠進(jìn)入其他機(jī)箱,會(huì)出現(xiàn)問題。 最好的情況是,不同的動(dòng)物在不熟悉的棲息地感覺真的不舒服 - 獅子或老虎會(huì)在企鵝的水和冰冷的領(lǐng)域感到可怕。 在最壞的情況下,獅子和老虎可能會(huì)嘗試吃企鵝!
動(dòng)物園管理員就像全球范圍 - 他或她有鑰匙進(jìn)入每個(gè)外殼,補(bǔ)充食物,往往生病的動(dòng)物等。
讓我們看一個(gè)真實(shí)的例子來展示范圍。
a()
and b()
, and three variables — x
, y
, and z
— two of which are defined inside the functions, and one in the global scope. It also contains a third function called output()
, which takes a single parameter and outputs it in a paragraph on the page.output(x);You should see the value of variable
x
output to the screen.output(y); output(z);Both of these should return an error along the lines of "ReferenceError: y is not defined". Why is that? Because of function scope —
y
and z
are locked inside the a()
and b()
functions, so output()
can't access them when called from the global scope.a()
and b()
so they look like this: function a() { var y = 2; output(y); } function b() { var z = 3; output(z); }Save the code and reload it in your browser, then try calling the
a()
and b()
functions from the JavaScript console: a(); b();You should see the
y
and z
values output in the page. This works fine, as the output()
function is being called inside the other functions — in the same scope as the variables it is printing are defined in, in each case. output()
itself is available from anywhere, as it is defined in the global scope.function a() { var y = 2; output(x); } function b() { var z = 3; output(x); }Save and reload again, and try this again in your JavaScript console:
a(); b();Both the
a()
and b()
call should output the value of x — 1. These work fine because even though the output()
calls are not in the same scope as x
is defined in, x
is a global variable so is available inside all code, everywhere.function a() { var y = 2; output(z); } function b() { var z = 3; output(y); }Save and reload again, and try this again in your JavaScript console:
a(); b();This time the
a()
and b()
calls will both return that annoying "ReferenceError: z is not defined" error — this is because the output()
calls and the variables they are trying to print are not defined inside the same function scopes — the variables are effectively invisible to those function calls.注意:相同的范圍規(guī)則不適用于循環(huán)(例如 for(){...}
)和條件塊(例如 if
。} ) - 他們看起來很相似,但是他們不一樣的東西! 小心不要讓這些困惑。
注意:參考錯(cuò)誤:"x"未定義 錯(cuò)誤是您最常遇到的錯(cuò)誤之一。 如果你得到這個(gè)錯(cuò)誤,并且你確定你有一個(gè)定義的變量,檢查它在什么范圍。
請(qǐng)記住,你可以從任何地方,甚至在另一個(gè)函數(shù)中調(diào)用一個(gè)函數(shù)。 這通常用來保持代碼整潔 - 如果你有一個(gè)大的復(fù)雜的函數(shù),它是更容易理解,如果你把它分解成幾個(gè)子函數(shù):
function myBigFunction() { var myValue; subFunction1(); subFunction2(); subFunction3(); } function subFunction1() { console.log(myValue); } function subFunction2() { console.log(myValue); } function subFunction3() { console.log(myValue); }
只需確保在函數(shù)內(nèi)部使用的值正確的范圍。 上面的例子會(huì)拋出一個(gè)錯(cuò)誤 ReferenceError:MyValue未定義
,因?yàn)殡m然 myValue
變量在與函數(shù)調(diào)用相同的作用域中定義, 函數(shù)定義 - 調(diào)用函數(shù)時(shí)運(yùn)行的實(shí)際代碼。 要使這個(gè)工作,你必須傳遞的值作為參數(shù)的函數(shù),像這樣:
function myBigFunction() { var myValue = 1; subFunction1(myValue); subFunction2(myValue); subFunction3(myValue); } function subFunction1(value) { console.log(value); } function subFunction2(value) { console.log(value); } function subFunction3(value) { console.log(value); }
本文探討了函數(shù)背后的基本概念,為下一個(gè)函數(shù)鋪平了道路,讓我們實(shí)際操作,并介紹了構(gòu)建自己的自定義函數(shù)的步驟。
更多建議: