• Skip to main content
  • Skip to primary sidebar

プログラミング入門ナビ

プログラミング学習初心者のための情報メディア

You are here: Home / Archives for JavaScript

JavaScript

JavaScriptの「this」は呼び出し方によって値が変わる?違いを徹底解説!

2020-05-29 By プログラミング入門ナビ編集部

はじめに

指し示す指

JavaScriptの「this」は他の言語と比較し挙動に少々癖があります。呼び出し方によってどの値を指すかが変わるためです。

思ったような値が得られない時は、thisの呼び出し方に問題があるかもしれません。

この記事では呼び出し方の違いによるthisの挙動を説明します。

thisの呼び出し方:基礎編

まずはよく使われるオーソドックスな呼び出し方を見ていきましょう。

基礎編クイズ

value = 1;
var obj = {
  value: 2,
  func: function() { console.log(this.value) }
}
function func() { console.log(this.value) }
var test = obj.func;

console.log(this.value);    //①
obj.func();                 //②
test();                     //③
func();                     //④

上記①②③④では何が表示されるでしょうか。少し考えてみてください。

答えは下記のようになります。

> 1       //①
> 2       //②
> 1       //③
> 1       //④

正解できましたか?

①②③④はいずれもthis.valueの呼び出しをしていますが、この通り表示される値が違います。なぜこのようになるのか、順を追って説明していきます。

グローバルコンテキストでの呼び出し

①ではthisをグローバルコンテキスト(関数やオブジェクトの外側)で呼び出しています。この場合、thisにはグローバルオブジェクトが入ります。

グローバルオブジェクトはJavaScriptが実行される環境により変わるのですが、ブラウザの場合はWindowオブジェクトとなります。

下記のようにconsole.logでthisを表示させればグローバルオブジェクトが何なのか確認できます。

console.log(this);    //> [object Window]が表示される

今回は1行目でvalue = 1;としたことで、このグローバルオブジェクトにvalueという値が定義され1が代入されていたため1が表示されました。

このように、グローバルコンテキストでthisを呼び出すと、グローバルオブジェクトが入ります。

オブジェクトのメソッド呼び出し

②は「objオブジェクトのfunc」をメソッド呼び出しています。

このように「〇〇.func();」といった具合で関数呼び出しの前に「〇〇.」がつく場合、関数「func」のスコープ内でのthisが指すのは前置きの〇〇が示すオブジェクトです。

この例ではobjのfunc関数スコープ内でthisが呼び出されているので、このthisが指すのは自分自身であるobjオブジェクトですね。

そしてobjは自身のvalueを持つため、結果的にthis.valueはこれを呼び出して2が入ります。

③は同じくobjの中で定義されたfuncを実行しているのですが、testにobj.funcを代入したあとでtest();と前置きなしで呼び出されていますね。

このように、グローバルコンテキストで前置きなしに関数だけが呼び出されている場合の関数内thisは、次項の「関数呼び出し」のケースにあたりグローバルオブジェクトを指すため1が表示されます。

関数呼び出し

④はグローバルコンテキストで定義された関数funcを呼び出しています。メソッド呼び出しではないので、「〇〇.」のような前置きはありません。

この場合の関数内thisもグローバルオブジェクトを指します。

グローバルオブジェクト(ブラウザで実行の場合はWindowオブジェクト)のvalueは一行目で定義されている通り1なので、1が表示されるわけです。

thisの呼び出し方:応用編

基礎編で見たように、thisの挙動は呼び出し方によって変わります。thisに何を入れたいかを明示的に指定するためのいくつかの方法を紹介します。

アロー関数呼び出し

ES6からはアロー関数が使用できるようになりました。関数としての基本的な挙動は通常の関数(function)と変わらないのですが、関数スコープ内のthisについては挙動が異なります。

アロー関数の中で呼び出されたthisは、関数の呼び出され方に関わらず、その関数が最初に定義された時点で指していた対象を指し続けるのが特徴です。

例を見てみましょう。

value = 5;
function func1() { console.log(this.value) }
var func2 =()=> { console.log(this.value) }
var obj1 = {
  value: 1,
  func1
}
var obj2 = {
  value: 2,
  func2
}

obj1.func1();   //1が表示される
obj2.func2();   //5が表示される

func1は従来の関数、func2はアロー関数です。この時点では両方ともグローバルコンテキストで定義されているため、thisはグローバルオブジェクトを指します。

その後に2種類のオブジェクト:obj1とobj2が定義され、それぞれfunc1とfunc2を保有していますね。

obj1のメソッド呼び出しでは、基礎編で触れたようにthisはobj1を指すので、obj1が持つvalueの値である1が表示されます。

これに対し、obj2のメソッド呼び出しではfunc2がアロー関数なので、thisが指すのはobj2でなく定義された時点で指していたグローバルオブジェクトのままです。

結果として、ojbのvalue(値は2)でなく、グローバルのvalue(値は5)が表示されます。

このように、アロー関数を使うと呼び出され方によらずthisが指す対象を定義当初のまま固定できるのです。

関数のコンストラクタ呼び出し

関数をグローバルコンテキストで前置き無しに呼び出すとその関数内でのthisはグローバルオブジェクトを指すのでした。

しかし、関数をコンストラクタ呼び出しすると、関数自体がインスタンスとなりthisは自身を指すようになります。

function Obj() {  console.log(this) }
Obj();      //> [object Window]が表示される
var obj = new Obj();    //> [object Object]が表示される

1行目の関数を2行目で呼び出した場合はthisはグローバルオブジェクトであるWindowオブジェクトになりますが、3行目のようにコンストラクタ呼び出しをするとObjectオブジェクトとなっていることが分かりますね。

実際に通常の関数呼び出しとコンストラクタ呼び出しの挙動を比較してみましょう。

function MyObject(num){
  this.value = num;
  console.log(this.value);
  this.show = function() { console.log(this.value) };
}
MyObject(5);        //5が表示される
var myObj = new MyObject(3);    //3が表示される
console.log(this.value);    //5が表示される
myObj.show();       //3が表示される

6行目が通常の関数呼び出し、7行目がコンストラクタ呼び出しです。

関数MyObjectではthis.valueに引数の値を代入しますが、通常呼び出しではグローバルオブジェクトのvalueに、コンストラクタ呼び出しでは自身(MyObjectのインスタンス)のvalueに値を入れています。

そのため6行目・8行目ではグローバルvalueが呼ばれるので5が、7行目・9行目ではMyObjectインスタンスのvalueが呼ばれるので3が表示されるわけです。

apply・call関数を使った呼び出し

関数呼び出しにおいてthisに何を入れるか明示的に指定できるのがapply関数とcall関数です。

使い方を見てみましょう。

value = 0;
var obj1 = { value: 1 };
var obj2 = { value: 2 };
function func() { console.log(this.value) }

func();             //0が表示される
func.call(obj1);    //1が表示される
func.apply(obj2);   //2が表示される

4行目の関数funcのthisはグローバルオブジェクトを指すので、6行目のように呼び出すとグローバルのvalueである0が表示されますね。

一方、7行目・8行目のようにcallやapply関数を使って呼び出すと引数に指定したオブジェクトをthisとして指定することができるので、それぞれobj1・obj2のvalueである1と2を表示します。

call・applyでは関数に渡す引数を設定することもでき、その方法によりこれらを使い分けます。詳しくはドキュメント(MDN)を参照してください。

まとめ

考える女性

JavaScriptでのthisについて、呼び出し方による挙動の違いを説明しました。

最初は理解しにくいので、実際にコードを書いて試していくのがおすすめです。

動画で学ぶプログラミング入門

オンラインスクールProglus(プログラス)でプログラミングを学んで、創れる人になろう!

在宅学習応援!今なら複数の基礎コースが無料!!

今すぐ詳細を確認する

Filed Under: プログラミング入門 Tagged With: JavaScript, this, 呼び出し

JavaScriptのfor文で配列要素の足し算をするとNaNが出るのはなぜ?原因と対処法を解説!

2020-05-28 By takayama

はてなマーク

はじめに

はてなマーク

JavaScriptを学習していると、比較的初歩の段階でfor文を学びますね。

繰り返し処理をするための機能で、配列データを順番に取り出して表示したり、別の値を格納していくなどの便利な使い方が可能です。

しかし、使い方に慣れるまではつまずきやすい部分でもあります。

ここでは初心者がうっかりしてしまいがちなfor文での失敗例とその対処方法を紹介します。

for文の失敗例

例えば、主要5教科:国語・算数・英語・理科・社会の合計点を求めるプログラムを書くとしましょう。

配列scoresに各教科の点数が入っていて、これを順番に取り出して合計点totalに加算していくためのコード例は下記です。

total = 0;
var scores = [35, 90, 21, 89, 70];
for(i = 0; i <= scores.length; i++) {
  total += scores[i];
}
console.log(total);

こちらを実行すると、合計点が表示されるのを期待するところですが、実際は下記の結果となってしまいます。

> NaN

NaNとは「Not-A-Number」のことで、「非数」という特別な値です。これは数字が与えられる想定の処理に対し、数字ではない値が与えられた場合に返されます。

NaNになる原因は?

なぜNaNになってしまうのでしょうか?どこで問題が起きているかわからない場合は、各所で値を表示させておかしな値が入っている箇所がないか確認するのが定石で、これをプリントデバッグと呼びます。

下記の通り、for文内にログ出力処理を追加しましょう(4行目)。

total = 0;
var scores = [35, 90, 21, 89, 70];
for(i = 0; i <= scores.length; i++) {
  console.log(scores[i]);
  total += scores[i];
}
console.log(total);

こうすることでscoresの配列から取り出した値をコンソールに表示させて確認できます。実行結果は下記の通りです。

> 35
> 90
> 21
> 89
> 70
> undefined
> NaN

上から順番に、配列内の点数が表示されています(1〜5行目)。一番下のNaNは元から出ていたものですね(7行目)。

ここで、6行目にundefinedが表示されているのにお気付きでしょうか。

for文の中で1〜6行目の値がtotalに足し合わされていきますが、undefinedは数字ではないため、これが足し合わされた後にtotalにはNaNが入ってしまったわけです。

対処方法

なぜ5個しか要素が入っていないはずの配列から6回も値が取り出されているのでしょうか。もう一度for文の繰り返し条件を見てみましょう。

for(i = 0; i <= scores.length; i++)

scoresの要素数は5個なので、scores.lengthには5が入ります。つまり、iは0からスタートし「0、1、2、3、4、5」の合計6回繰り返されるわけです。

そして、配列の要素はsocres[0]が1番目、scores[1]が2番目というふうに対応しています。 n番目の要素を取り出すにはscores[n-1]のように、1つ減らした数字を使って取り出す必要があるのです。

そのため、要素が5個の場合はscores[4]が最後の要素となり、scores[5]は未定義なので取り出そうとするとundefinedが返ります。

実際に取り出してみた例が下記です。最後の列で、数字とundefinedを足そうとしてNaNが返っているのが分かりますね。

var scores = [35, 90, 21, 89, 70];
console.log(scores[0]);                     //35
console.log(scores[5]);                     //undefined
console.log(scores[0] + scores[5]);   //NaN

これに対処するには、繰り返しをi=4で止めるように修正しましょう。for文繰り返し条件を「i がscores.length以下」としていたのを「iがscores.length未満」に変更します(下記3行目)。

total = 0;
var scores = [35, 90, 21, 89, 70];
for(i = 0; i < scores.length; i++) {
  console.log(scores[i]);
  total += scores[i];
}
console.log(total);

実行してみると、無事総合点が表示されました。

> 305

まとめ

ハイタッチする仲間たち

JavaScriptのfor文でNaNが出てしまう原因と対処方法についてご紹介しました。

実はJavaScriptに限らず、他の言語の繰り返し処理でも同様のミスをしてしまいがちです。

起っている現象としては全く同じで、繰り返し条件の間違いにより無いはずの配列要素にアクセスしてしまうことが原因なので、つまずいたら1度チェックする癖をつけましょう。

動画で学ぶプログラミング入門

オンラインスクールProglus(プログラス)でプログラミングを学んで、創れる人になろう!

在宅学習応援!今なら複数の基礎コースが無料!!

今すぐ詳細を確認する

Filed Under: プログラミング入門 Tagged With: for文, JavaScript, NaN

JavaScriptの「net::ERR_FILE_NOT_FOUND」エラーが出る原因と対処方法を紹介!

2020-04-29 By プログラミング入門ナビ編集部

パソコンの前で頭を抱える男性たち

はじめに

JavaScriptのエラー画面

JavaScriptを実行した時、エラーが出てしまうことがありますね。

ブラウザのコンソールで確認すると発生しているエラーのエラーコードを見ることができます。

この記事では、その中でもよくある「net::ERR_FILE_NOT_FOUND」のエラー発生原因とその対処方法を紹介します。

なお、JavaScriptの開発方法については下記講座で詳しく解説していますので、興味のある方はぜひ受講を検討ください。

  • ウェブ開発入門完全攻略コース -プログラミングをはじめて学び創れる人へ!未経験から現場で使える開発スキルを習得!
  • WE09-JavaScript入門

ファイルは呼び出し元から見たパスで検索される

OK画面

例えば上記画面の左側「Project」の様なファイル配置のプロジェクトがあったとしましょう。

「hello.html」の7行目でJavaScriptファイル「hello.js」を呼び出しています。「hello.html」はweb/js_basicの下にありますね。

さらに同じ階層に「js」フォルダがあり、その中に「hello.js」があるので、呼び出す時のファイルパスは

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

となります。

「hello.html」のファイルがある場所(web/js_basic/)から見ると、自分と同じ場所に「js」フォルダがあるのでこのようなパスとなるわけです。

JavaScriptの「net::ERR_FILE_NOT_FOUND」エラーが出る原因は?

これは簡単にいいますと指示されたパスにJavaScriptのファイルが見つからないために発生するエラーです。

ファイルパスの指定が間違っている、もしくは、ファイルパスは合っているが呼び出し元のファイルを想定した場所に置けていないことが原因となります。

例えば、先ほどの例で誤って「hello.html」を下記のように web > js_basic > js の下に置いてしまったとしましょう。

NG画面

この場合は、「hello.html」から見ると同じ階層に「js」フォルダが見えないので「js/hello.js」とファイルパスを指定されても見つけられずエラーとなってしまいます。

エラーへの対処方法

このような場合はまず呼び出すファイルパスが正しいかどうか?を確認し、場合に応じて下記の方法でエラーを解消しましょう。

方法1:ファイルを正しい場所に配置し直す

ファイルパスが正しい場合、ファイル呼び出し元のファイル(先ほどの例では「hello.html」)を想定通りの正しい場所に配置し直しましょう。

先に出した例で「hello.html」の7行目に書いたファイルパス:

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

に合わせて「hello.html」の場所を見直してください。jsフォルダが見えるよう、web/js_basic/jsの下ではなく、web/js_basicの下に置かなければなりません。

なお、「はじめに」で紹介した講座では上記のファイルパスを正としていますので、こちらのパターンとなります。

方法2:ファイルパスを正しく修正する

ファイルパスが正しくない場合は、ファイルパスを修正します。

例えば先ほどの例で「hello.html」はweb/js_basic/jsの下になければならない、という場合はファイルパスを下記のように直さなければなりません。

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

呼び出し元の「hello.html」と「hello.js」が同じ階層にあるため、フォルダ名が無しとなるわけです。

まとめ

パソコンの前でショックを受ける女性

JavaScriptの「net::ERR_FILE_NOT_FOUND」エラーが出る主な原因と対処方法について紹介しました。

紹介した方法で解決しない場合でも、ファイルパスとファイルの場所が合っていないことが主な原因ですので、今一度ファイルの場所やパスに間違いがないか確認してみてください。

動画で学ぶプログラミング入門

オンラインスクールProglus(プログラス)でプログラミングを学んで、創れる人になろう!

在宅学習応援!今なら複数の基礎コースが無料!!

今すぐ詳細を確認する

Filed Under: プログラミング入門 Tagged With: error, HTML, JavaScript

  • Go to page 1
  • Go to page 2
  • Go to page 3
  • Interim pages omitted …
  • Go to page 11
  • Go to Next Page »

Primary Sidebar

Twitter

Follow @programmingnavi Tweets by programmingnavi

Facebookページ

プログラミング入門ナビ

メルマガに今すぐ登録!

ブログの更新情報やお得なクーポン情報などをお知らせします。

登録はこちらから。

人気の記事

まだデータがありません。

最近の投稿

  • 【7/9更新】Udemyプログラミング入門講座等の割引クーポン配布
  • JavaScriptの「this」は呼び出し方によって値が変わる?違いを徹底解説!
  • JavaScriptのfor文で配列要素の足し算をするとNaNが出るのはなぜ?原因と対処法を解説!
  • プログラミング学習を成功させるポイントを3つお送りいたします
  • 初心者がスマホアプリを開発するには?iOSとAndroidの両方について必要なスキルを確認しよう

カテゴリー

  • エンジニアのしごと
  • エンジニアへの道
  • ツールの使い方
  • ニュース
  • プログラミング入門

タグクラウド

AI AWS AWS Cloud9 Bootstrap Cloud9 CodeWing CSS Git GitHub Heroku HTML JavaScript Linux macOS MySQL MySQL Workbench node.js Nuxt.js Proglus Python Ruby Ruby on Rails SQL Udemy Vue.js Web開発 Windows Windows10 エラー エンジニア オンライン学習 サーバ サーバー スクリーンショット セキュリティ セール データベース プログラミング プログラミング入門 プログラミング学習 ユーデミー 初心者 未経験 機械学習 開発環境構築

アーカイブ

  • 2020年7月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年11月
  • 2019年9月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年11月
  • 2018年10月
  • 2018年9月
  • 2018年8月
  • 2018年7月
  • 2018年6月
  • 2018年5月
  • 2018年4月
  • 2018年3月

検索

Copyright © 2025 · programmingnavi.com ・About・プライバシーポリシー