We're looking for a user researcher to understand the needs of developers and designers. Is this you or someone you know? Check out the post: https://mzl.la/2IGzdXS

この記事は翻訳作業中です。

コーディングにおいて、不可欠なコンセプトが関数です。関数を使用することで、特定のタスクをこなすコードを定義し、保持しておいて、いつでも簡単なコマンドで呼び出すことを可能にしてくれます。同じコードを何度も打たなければならないよりとっても簡単です。この記事では関数の書き方や、関数を実行する方法、定義の仕方、スコープ、引数といった関数に関する基礎を学びます。

前提知識: 基本的なコンピュータの知識、 HTML と CSS への理解、JavaScript の第一歩
目的: JavaScript の関数についての基礎を理解する。

関数はどこにありますか?

JavaScript の中で、関数はあらゆるところに見つかるでしょう。実際、これまでのところすべての場面で関数を使用してきました。これについてはあまり触れてきませんでした。しかし、今こそ明確に関数について話し始め、本当に構文を探索する時期です。

Pretty much anytime you make use of a JavaScript structure that features a pair of parentheses — () — and you're not using a common built-in language structure like a for loop, while or do...while loop, or if...else statement, you are making use of a function.

ブラウザー組込み関数

このコースではブラウザーに組込まれた関数をたくさん使ってきました。毎回テキスト文字列を操作したときには、こんな風に:

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

あるいは毎回配列を操作したときには:

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

また毎回乱数を作成したときには:

var myNumber = Math.random();
// the random() function generates a random
// number between 0 and 1, and returns that
// number

...関数を使っていたのです!

メモ: これらの機能に慣れるために、必要なときにはこういった行をあなたのブラウザのJavaScriptコンソールにいつでも入力してみて下さい。

JavaScript言語にはたくさんの組込み関数があるので、いろいろなあなたのやりたい事を、全部をあなた自身で全部書かなくてもすみます。実は、あなたが呼び出して起動(走らせたり実行する事の別の言い方)するコードのいくつかは、JavaScriptでは書けない、ブラウザー組込み関数です — こういった関数の多くは背後のブラウザのコードを呼び出していて、これらはJavaScriptのようなWeb言語ではなく、大半がC++のような低レベルのシステム言語で書かれています。

ブラウザ関数のいくつかはJavaScript言語の核に含まれない事を心に留めておいて下さい — いくつかはブラウザAPIの一部として定義されていて、もっと多くの機能を提供すべくデフォルトの言語の上で構築されています(詳しくは私たちのコースのこの以前のセクションを見て下さい)。ブラウザAPIのもっと詳しい使い方については、後の方のモジュールで見ていく事になるでしょう。

関数とメソッド

この先に進む前に片付けておくべき事柄が一つあります — 技術的に言えば、ブラウザ組込み関数は関数ではありません — それらはメソッドです。ちょっと怖ろしげで意味不明な言葉かもしれませんが、心配しなくて大丈夫 — 関数とメソッドという言葉はおおよそ同じような意味で使えます。少くとも我々の目的、今の学習段階では。

区別としては、メソッドはオブジェクトの中で定義された関数になります。ブラウザ組込み関数(メソッド)と変数(プロパティと呼ばれます)は構成されたオブジェクトの中にあって、コードをより効率的で扱いやすいようにしています。

構成されたJavaScriptオブジェクト内部の働きについては、まだ知る必要はありません — この後のモジュールで、オブジェクト内部の働きや自分でオブジェクトを作る方法について教える段階になってから覚えれば大丈夫です。今のところは、Webのあちこちにある関連したリソースを見ていると、メソッドと関数が混在している事があるとわかってもらいたいだけです。

カスタム関数

このコースのここまででもたくさんのカスタム関数を見てきました — ブラウザの内部でではなくあなたのコードの中で定義された関数です。独自の名前の直後にカッコがついてるものを見かけたら、それはカスタム関数を使っているという事です。 繰返しの記事で出てきたrandom-canvas-circles.html の例(ソースコードはこちら)では、 独自に作った 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();
  }
}

この関数は、<canvas> エレメントの内にランダムな円を100描きます。同じ事をやりたい時には、いつでもこんな具合に関数を起動するだけです

draw();

繰り返しをする毎に何度も同じコードを書き上げるのではなく。関数にはあなたが書きたいどんなコードでも含められます — 関数の中から他の関数を呼ぶことだってできます。例に挙げた上の関数では、random()関数を3回呼んでいて、random関数は以下のコードで定義されています:

function random(number) {
  return Math.floor(Math.random()*number);
}

ブラウザ組込みの Math.random() は0から1までの間の10進数の乱数を作成するだけなので、私たちにはこの関数が必要でした。私たちは0から指定した数にわたる乱数が欲しかったのです。

関数の呼び出し

もうよくご存知でしょう、でも念のため … 定義した後で実際に関数を使うには、関数を走らせ — あるいは起動し — なければなりません。これはコードのどこかに関数の名前、直後にカッコの組を書けばできます。

function myFunction() {
  alert('hello');
}

myFunction()
// calls the function once

匿名関数

 

ちょっと違う形式で定義されて起動される関数を見かける事があるでしょう。ここまでは関数をこのように作ってきました:

 

function myFunction() {
  alert('hello');
}

でも名前のない関数を作る事もできます::

function() {
  alert('hello');
}

これは匿名関数と呼ばれます — 名前がないんです! It also won't do anything on its own. 無名関数はよくイベントハンドラで使われていて、例えば以下では関連づけられたボタンがクリックされるたび、関数の中のコードが走ります:

var myButton = document.querySelector('button');

myButton.onclick = function() {
  alert('hello');
}

上の例では、ページの中に選択してクリックするための<button>エレメントが存在しなければならないでしょう。あなたはこのような例をここまでのコースで見てきましたし、ここから先の記事でもっと学習し、使い方を見ていく事になります。

匿名関数を変数の値として代入する事もできます:

var myGreeting = function() {
  alert('hello');
}

この関数は次のように起動できます:

myGreeting();

関数に名前をつけたような効果があります。また関数を複数の変数の値として代入する事もできます:

var anotherGreeting = function() {
  alert('hello');
}

結果、この関数はどちらの方法でも起動できます

myGreeting();
anotherGreeting();

ですがこれは混乱するだけなので、やらないように! 関数を作成するときはこの形式でやった方が良いです:

function myGreeting() {
  alert('hello');
}

匿名関数は主にイベント発火 — ボタンがクリックされたとか — のレスポンスとして、一連のコードを走らせるだけのような場合に、イベントハンドラとして使われます。くりかえしですが、こんな具合です:

myButton.onclick = function() {
  alert('hello');
  // I can put as much code
  // inside here as I want
}

関数の引数

関数には実行する時に引数が必要なものがあります — 関数のカッコとカッコの間に書かなければならない値で、関数が正しい仕事をするのに必要とされます。

メモ: 引数は、パラメータ、プロパティ、アトリビュート(属性)などと呼ばれる場合もあります。

例えばブラウザ組込み関数 Math.random() は引数を必要としません。 呼ばれるといつも0から1までの乱数を返します:

var myNumber = Math.random();

ですがブラウザ組込みの文字列関数 replace() は二つの引数が必要です — 主文字列から探すべき部分文字列と、部分文字列を置換する文字列です:

var myText = 'I am a string';
var newString = myText.replace('string', 'sausage');

メモ: 複数の引数を指定するときは、カンマで区切って書きます

引数には省略可能 — 書かなくても良い — なものもある事に触れておくべきでしょう。省略された場合、関数はだいたいデフォルトに規定された動作を行ないます。例えば、配列の join() 関数のパラメータは省略可能です:

var myArray = ['I', 'love', 'chocolate', 'frogs'];
var madeAString = myArray.join(' ');
// returns 'I love chocolate frogs'
var madeAString = myArray.join();
// returns 'I,love,chocolate,frogs'

もし結合/区切り文字を指定する引数が省略された場合、デフォルトとしてカンマが使われます。

関数のスコープと競合

 

スコープという言葉について説明しておきましょう — 関数を扱う際にはとても大切な概念です。関数を作成するとき、関数の中で定義されている変数や関数は、内部でそれぞれ独自のスコープというものを持ちます。これはそれぞれが独自の小部屋に閉じ込められていて、別の関数の内部から、あるいはこの関数の外部のコードから触れられくなる事を意味しています。

 

あなたの全ての関数の外側、一番の外側を、グローバルスコープと呼びます。グローバルスコープで定義された値は全て、コードのどこからでもアクセスできます。

 

JavaScriptがこう作られているのにはいくつも理由があります — が、主な理由はセキュリティと組織化のためです。時には変数にコードのどこからでもアクセスされないようにしたい場合もあるでしょう — どこかから呼び込んだ外部スクリプトが、あなたのコードをおかしくして問題を起す場合があるかもしれません。別の場所でたまたま同じ名前の変数を使っていて、衝突していたために。これは悪意をもってわざとやっている場合や、単なる偶然の場合もあります。

そうですね、例えばあるHTMLファイルが二つの外部 JavaScript ファイルを呼び出しているとして、そのどちらも同じ名前の変数と関数を定義しているとします:

<!-- 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 + '.');
}

あなたが呼び出したいのはどっちも greeting()関数ですが、あなたには second.js ファイルの greeting() 関数しかアクセスできません — HTMLソースの後の方で呼ばれているので、ここで定義した変数や関数が first.js のものを上書きしてしまいます。

: この例を GitHubでライブ実行 できます(ソースコードはこちら).

あなたのコードの部品を関数の中に隔離するとこのような問題を避けられるので、これが一番良いやりかたと考えられています。

これは動物園みたいなものです。ライオン、シマウマ、トラ、ペンギンはそれぞれの檻の中にいて、それぞれの檻の中のものにしか触れられません — 関数のスコープと同じ事です。もし彼等が他の檻の中に侵入できたら問題が起きることでしょう。良くて、知らない住人に囲まれて気まずい思いをする — 寒くて水だらけのペンギンの檻に入ったライオンやトラは酷い気分になるでしょう。最悪の場合、ライオンやトラはペンギンを食べてみようとするかも!

動物園の管理人はグローバルスコープみたいなものです — 管理人は全ての檻の鍵を持っていて、エサを補充し、動物にうんざりし、などなど。

Active learning: Playing with scope

Let's look at a real example to demonstrate scoping.

  1. First, make a local copy of our function-scope.html example. This contains two functions called 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.
  2. Open the example up in a browser and in your text editor.
  3. Open the JavaScript console in your browser developer tools. In the JavaScript console, enter the following command:
    output(x);
    You should see the value of variable x output to the screen.
  4. Now try entering the following in your console
    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.
  5. However, what about when it's called from inside another function? Try editing 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.
  6. Now try updating your code like this:
    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.
  7. Finally, try updating your code like this:
    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.

: The same scoping rules do not apply to loop (e.g. for() { ... }) and conditional blocks (e.g. if() { ... }) — they look very similar, but they are not the same thing! Take care not to get these confused.

: The ReferenceError: "x" is not defined error is one of the most common you'll encounter. If you get this error and you are sure that you have defined the variable in question, check what scope it is in.

関数の中の関数

Keep in mind that you can call a function from anywhere, even inside another function.  This is often used as a way to keep code tidy — if you have a big complex function, it is easier to understand if you break it down into several sub-functions:

function myBigFunction() {
  var myValue;

  subFunction1();
  subFunction2();
  subFunction3();
}

function subFunction1() {
  console.log(myValue);
}

function subFunction2() {
  console.log(myValue);
}

function subFunction3() {
  console.log(myValue);
}

Just make sure that the values being used inside the function are properly in scope. The example above would throw an error ReferenceError: myValue is not defined, because although the myValue variable is defined in the same scope as the function calls, it is not defined inside the function definitions — the actual code that is run when the functions are called. To make this work, you'd have to pass the value into the function as a parameter, like this:

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);
}

まとめ

This article has explored the fundamental concepts behind functions, paving the way for the next one in which we get practical and take you through the steps to building up your own custom function.

関連情報

 

このモジュール内の文書

 

ドキュメントのタグと貢献者

このページの貢献者: i12o, mfuji09, chameleonhead
最終更新者: i12o,