3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Javascript】即時関数とFunctionコンストラクタ、関数宣言、関数式について

Last updated at Posted at 2019-06-16

本日、ドットインストールの簡単なJavascriptの問題を解いていて、不明な点があったため、まとめることにしました。

といってもほぼ公式ドキュメントの写しのような形になっておりますが、今回自分用にまとめたいと思います。

解いた問題はこちら→JavaScriptで文字数チェッカーを作ろう

最終的にこのような文字を入力すると残りの文字数をリアルタイムでチェックすることができます。

スクリーンショット (451).png

コードは以下のとおりです。(無料のレッスンなので転記します)

index.html
<!DOCKTYPE html>
<html lang = 'ja'>
    <head>
        <meta charset = 'utf-8'>
        <title>Comment Form</title>
        <link rel='stylesheet' href='css/styles.css'>
    </head>

    <body>
        <div class='container'>
            <textarea id='comment' placeholder = 'your comment here'></textarea>
            <div class='btn'>Submit</div>
            <p><span id='label'>30</span>characters left</p>
            
        </div>

        <script src= "js/main.js"></script>

    </body>
    </html>

styles.css
@charset 'UTF-8';

body{
    font-family:Verdana,sans-serif;
    font-size:16px;
    background:#e0e0e0;
}

.container{
    width:400px;
    margin:30px auto;
}

textarea{
    width:400px;
    box-sizing: border-box;
    height:200px;
    padding:14px;
    font-size:16px;
    border-radius:5px;
    margin-bottom: 10px;
    line-height:30px;
}

textarea:focus{
    outline:none;
}

p{
    color:#333;
    font-size:14px;
    margin:0;
    padding-top:6px;

}

#label{
    font-weight:bold;
}

.btn{
    display:inline-block;
    width:150px;
    background-color:blue;
    padding:5px;
    color:#fff;
    border-radius: 5px;
    text-align:center;
    cursor:pointer;
    box-shadow:0 4px 0 #0088cc;
    float:right;
    
}

.warning{
    color:red;
    

}
main.js
(function(){ //即時関数
    'use strict';

    var comment = document.getElementById('comment');
    var label = document.getElementById('label');

    var LIMIT = 30;
    var WARNING = 10;


    label.innerHTML = LIMIT;

    comment.addEventListener('keyup',function(){

        var remaining = LIMIT - this.value.length;
        label.innerHTML = remaining;
        if(remaining<WARNING){
            label.className = 'warning';
        } else{
            label.className = '';
        }
    })

})();

#即時関数について

今回のコードでは、即時関数を使っていると言っていました。
そもそも即時関数とはなんなのでしょうか。

参考:Javascriptドキュメント「関数」

私が今参考にしている上記のドキュメントを見てみると、即時関数なるものがあり、これを今回使っているようです。

##即時関数とは

関数を一度だけ使うときの一般的なパターンがIIFE(Immediately Invokable Function Expression)であり、以下のように記述する。

(function(){
  statements
})(); //関数を即時に実行している。

何度も使わないから特に関数としては定義文function hugahuga = ~を書かず、その場かぎりで実行するという意味だろうか?(´・ω・)

そもそもjavascriptの関数の種類はどんなものがあるのでしょうか。

参考:Javascriptドキュメント「関数」

まず第一前提として、

JavaScript において、関数は第一級オブジェクトです。すなわち、関数はオブジェクトであり、他のあらゆるオブジェクトと同じように操作したり渡したりする事ができます。具体的には、関数は Function オブジェクトです。

Javascriptにおいて、関数はオブジェクトであるということがわかりました。

もう少し深くfunctionについて学んでいきます。

##Functionコンストラクタ
Functionコンストラクタにより新規のFunctionオブジェクトを作成する方法が以下のとおり。
※しかし、Functionコンストラクターによる関数の生成は推奨されません。これは、文字列として関数本体が必要で、JS エンジンによる最適化を妨げたり、他の問題を引き起こしたりする場合があるためです。


new Function ([arg1[, arg2[, ...argN]],] functionBody)

arg1, arg2, ... argN
仮引数の名前として関数で用いるための名前例えば"x""theValue" "a,b"

functionBody
関数定義を形成する JavaScript の文を含む文字列
説明


var sum = new Function('a', 'b', 'return a + b');

console.log(sum(2, 6));
// expected output: 8

##Functionコンストラクタと関数宣言(Function文)の違い
また、Functionコンストラクタによる関数の生成は、常にグローバルスコープで作成する。

var x = 10;

//Functionコンストラクタの場合
function createFunction1() {
    var x = 20;
    return new Function('return x;'); // this |x| refers global |x|
}

//関数宣言の場合
function createFunction2() {
    var x = 20;
    function f() {
        return x; // this |x| refers local |x| above
    }
    return f;
}

var f1 = createFunction1();
console.log(f1());          // 10
var f2 = createFunction2();
console.log(f2());          // 20

##関数宣言(Function文)
ちなみに上記の関数宣言(Function文)は、関数を宣言するための特殊な構文である。

function name([param[, param[, ... param]]]) {
   statements
}
name
関数名
param
関数に渡される引数の名前
statements
関数の本体を構成する文

JavaScript の関数宣言は、関数の定義を巻き上げる。関数を宣言する前に使用することができる。


hoisted(); // logs "foo"

function hoisted() {
  console.log('foo');
}

##さらに関数式(Function演算子)
functionから開始せずに関数を含んでいる式のことを関数式という。
関数式は、関数宣言と似ており、同じ構文を持っている。関数式と関数宣言の主な違いは関数名を省略できるかできないかという点。
関数式では、匿名関数を生成するために、関数名を省略できる。

var myFunction = function [name]([param1[, param2[, ..., paramN]]]) {
   statements
};

name
関数名省略可省略した場合関数は無名関数として認識されますname は関数内でローカル
paramN
関数に渡される引数の名前
statements
関数の本体を構成するステートメント



これは無名関数
var getRectArea = function(width, height) {
    return width * height;
}

console.log(getRectArea(3,4));
// expected output: 12

また、関数式は関数宣言と違って巻き上げはできない。
※関数を宣言したあとでないと実行できない。

notHoisted(); // TypeError: notHoisted is not a function

var notHoisted = function() {
   console.log('bar');
};

#コンストラクタか関数宣言か関数式か

以下の4つのパターンが上記で学習したfunctionの表現の仕方4つである。

1 Function コンストラクタによって定義され変数 multiply に代入された関数:

var multiply = new Function('x', 'y', 'return x * y');

2 multiply と命名された関数の 関数宣言:

function multiply(x, y) {
   return x * y;
} // there is no semicolon here

3 変数 multiply に代入された無名関数の関数式:

var multiply = function(x, y) {
   return x * y;
};

4 変数 multiply に代入されたfunc_name と命名された関数式:

var multiply = function func_name(x, y) {
   return x * y;
};

上記4つはおおよそ同じ働きをするが、いくつか微妙に異なる点がある。

1 Functionコンストラクタを使用した場合
・new Functionで定義された関数は関数名を持たない。
・Functionコンストラクタで定義された関数はグローバルスコープ以外はどんなスコープも継承しない。(関数式で定義された関数は現在のスコープを継承する)
・Functionコンストラクタで定義された関数は、評価されるたびに解析される。一度しか解析されない関数式や関数宣言より速度が遅いため、できる限り避けるべきである。

2 関数宣言と 3、4 関数式の違い
関数宣言で定義された関数のみ、関数自体が宣言される前に使用することができる。(巻き上げがあると表現される)

foo(); // FOO! とアラートされる
function foo() {
   alert('FOO!');
}

Functionコンストラクタのことを考えると、一般的には、関数式を使用するのがよさそうである。
ちなみに、関数宣言は、

  • 式の一部になった時
  • 関数またはスクリプト自体の「ソース要素 (source element)」でなくなった時。「ソース要素」はスクリプトや関数本体の中で入れ子にされていない文の事です。

に関数宣言ではなくなり、関数式に変化する。(ここは少し細かすぎる気がするが一応記載)

// 関数宣言
function foo() {}

// 関数式
(function bar() {})

// 関数式
x = function hello() {}


if (x) {
   // 関数式
   function world() {}
}


// 関数宣言
function a() {
   // 関数宣言
   function b() {}
   if (0) {
      // 関数式
      function c() {}
   }
}

#即時関数の疑問に戻る

即時関数は、関数式である。さらに、「JavaScriptで即時関数を使う理由」という記事に詳しく記載がありました。

一時変数を使用する場合、スコープの外側へ影響を与えてしまうのを防ぐため、なるべく変数の有効範囲をせばめる。そのため、処理が再利用されないのであれば、即時関数を使うべき。

少し難しいですが、参考になるQiita記事をペタっと張り付けておきます。
[関数宣言 vs 関数式 | ES2015+](https://qiita.com/raccy/items/aac3b8e3981564bbd1fa)

まだまだわからないことばかりですが、頑張ります。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?