質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

1721閲覧

JS : promise().then(console.log) が成功する理由がわからない

dwayne_johnson

総合スコア86

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

2グッド

2クリップ

投稿2018/10/25 23:31

掲題の通りです。

JavaScript

1promise() 2 .then((response) => console.log(response));

上記が成功するのはわかります。

JavaScript

1promise() 2 .then(console.log);

これだと、結果受け取っていないように思われるため、どうして成功するのかわかりません。

これがどのような省略記法なのか、教えていただきたいです。
よろしくお願いします。

fa11enprince, BlueMoon👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

promise().then(fn)は、Promiseインスタンスのthenメソッドの実行という意味です。
thenメソッドを実行する時は、引数に関数を指定して下さいねと言っています。
つまり、引数を要求する関数を渡せば何でもいいんですよ。


まず、JSでは関数を第一級オブジェクトとして取り扱っている為、以下の特性があります。

  • 変数に代入できる
  • 関数の引数として設定できる
  • 関数の戻り値として設定できる

console.logはConsoleというインスタンスで、プロトタイプメソッドとしてlogがぶら下がっています。
このメソッドはthisがconsoleインスタンスに束縛されているだけの関数です。

関数やメソッドはお尻に()をつける事で実行されます。
console.logのようにカッコを付けずにアクセスすることで、
関数の実体にアクセスすることが可能です。

関数としてアクセスしたメソッドは、代入演算子で変数に格納したり、
別の関数やメソッドの引数として利用することが可能です。

例としてArray.prototype.forEachにconsole.logを千切って渡してみましょう。

JavaScript

1[1, 2, 3].forEach(console.log); 2// 1 0 (3) [1, 2, 3] 3// 2 1 (3) [1, 2, 3] 4// 3 2 (3) [1, 2, 3]

forEachはコールバック関数に対して「要素の値、インデックス値、配列そのもの」を引数として渡すので、可変引数のconsole.logを渡すと出力結果が大騒ぎになりますが、普通に動作している事が分かります。


console.logは別にthisに強く依存する作りではないので、
メソッドを千切ってコールバック引数として指定するだけでも動作します。

ただし、インスタンスのメソッドは基本的にthis、つまりプロパティに依存するものが多いはず。
プロパティに依存しないなら最初から静的メソッドや普通の関数で作るケースが多いですからね。

ちょっと変数にメソッドを千切って保存することで、
thisの束縛が切れてしまうことを確認してみましょう。

JavaScript

1class Cat { 2 constructor (name) { 3 this.name = name; 4 } 5 say () { 6 return `${(this || {}).name}: meow`; 7 } 8} 9 10const tama = new Cat('tama'); 11console.log(tama.say()); // tama: meow 12 13const say = tama.say; 14console.log(say()); // Undefined: meow

鳴き声sayのプロトタイプメソッドだけ保存しておこうと別の変数に保存すると、
見事に捨て猫になってしまいました。
無名関数に包むのが楽ですが、bindを使ったり、引数に束縛したりと色々と対応策はあります。

JavaScript

1// 対応策色々 2const say2 = tama.say.bind(tama); 3const say3 = () => tama.say(); 4const say4 = (cat => () => cat.say())(tama); 5 6console.log(say2()); // tama: meow 7console.log(say3()); // tama: meow 8console.log(say4()); // tama: meow

ここの部分は難解で質問文時点では蛇足気味ですが、
JSで高度な処理を組む時にシンプルに書けるようになってくるので必要に応じて勉強してみてください。

投稿2018/10/26 09:09

miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dwayne_johnson

2018/10/26 12:20 編集

なるほど。。 わかった気にはなりました。 これまで、ここのthisは何を指すだとか、bind()の意味などを深く考えずに書いていましたが、今一度、しっかりと学びたいと思います。 2点だけ、自分の認識が間違っていないか確認したいので、お手すきの際にご回答いただければ幸いです。 説明文中の ``` const say = tama.say; ``` は ``` const say = function say() { return `${(this || {}).name}: meow`; } } ``` と同義であり、その関数単体ではthisもくそもないので、捨て猫になってしまうという認識で合っていますでしょうか? `tama.say`はCatクラス内のsay()関数の実体であるという認識です。 また、この`say`そのものを使い、どうにかしてthisを設定して猫に名前を付けることは、不可能ということであっていますでしょうか? よろしくお願いします。
miyabi-sun

2018/10/29 01:00

そうですね。 ただし、微妙に動きが違うケースがあり、 試しに回答文のsayメソッドの中身を`return `${this.name}: meow`;`にするとthis=undefinedなのでundefinedには何のプロパティもありませんよエラーになるはずです。 コメントにあったsay変数に直接関数を宣言した場合はthisはfunction関数によってthisが生成され、this.nameが空文字列を返すはずです。 > この`say`そのものを使い、どうにかしてthisを設定して猫に名前を付けることは、不可能ということであっていますでしょうか? 可能です。 全ての関数はbindというthisや引数を束縛した関数を生成するメソッドを有しており、this.nameを使いたいならそれを何かしらで補ってやれば動作します。 say.bind({name: 'tama'})() // "tama: meow" say.bind({name: 'kuro'})() // "kuro: meow"
dwayne_johnson

2018/10/29 08:25

ご解答ありがとうございました。 > 全ての関数はbindというthisや引数を束縛した関数を生成するメソッドを有しており bindについてはもう少しきちんと学ぶ必要がありそうですが、何となく理解はできました。ありがとうございました。
guest

0

ベストアンサー

then()は、関数を受け取り、その関数にresponseをセットして呼び出すからだと思います。

〜.then(hoge)という呼び出しに対して、
Promiseの内部では、

hoge(response);

が呼び出されるということです。

一つ目の例を、

const func = (response) => {console.log(response)); promise.then(func);

と置きかえると、

func(response); //console.log(response);の呼び出し

が呼び出されることになり、

結果としては、質問の二つのソースは同じ意味になりますね。

投稿2018/10/25 23:52

Meganezaru

総合スコア715

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dwayne_johnson

2018/10/26 00:20

なるほど。Promiseのthen内部では、明示しなくてもレスポンスが引数に代入されるため、console.logの引数にレスポンスが勝手に代入されるということですね。 非常に明快なご説明、ありがとうございました。
Meganezaru

2018/10/26 01:46

明示しなくても、という感じより、then()の仕様として、「引数には、関数をセットしてね。resolveした時に引数に結果をセットして、その関数を呼び出すから。」というイメージだと思います。 今回の例でいえば、セットした関数が、console.logか自作した関数か、という違いですね。
Meganezaru

2018/10/26 03:55

yambejpさんの回答のコメント欄にあるやりとりから考えると、オブジェクトに所属する関数を、直接コールバック引数の対象として渡す(今回の例でいうと、.then(console.log)のような呼び出し方)のは危ない(気づきにくい不具合を作り込んでしまう)ようなので最初の書き方(無名のアロー関数を定義してセット)を習慣づけるほうが、安全かもしれませんね。
guest

0

コールバックしているだけですね

javascript

1["a","b","c"].forEach(console.log)

投稿2018/10/26 00:24

yambejp

総合スコア114769

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2018/10/26 01:07

console.logのthisをconsole以外にしても、正常に動作することが保証されているのか少し気になりました。
Meganezaru

2018/10/26 01:52

@maisumakun さん この呼び出し方で、thisが影響すると認識できませんでした(^_^;) 差し支えなければ、ご教授いただければ、うれしいです。
maisumakun

2018/10/26 02:03

「.then(console.log)」とすると、関数だけ取り出して渡す形となるので、console.log内から見たthisはnullあるいはwindowとなって、consoleではなくなってしまいます。 「f = console.log; f('abc');」のようにしたのと同じ意味合いです。
miyabi-sun

2018/10/26 03:05 編集

Node.jsのconsole.logはv0.12系で確認してもthis非依存でした。 Chromeでもthis非依存で普通に使えます。 ただし、[1, 2, 3].forEach(fn)で渡される引数の順番は「要素、インデックス、本体の配列そのもの」の3要素である為、console.logを入れて1, 2, 3を表示するのに使うとゴミデータがうじゃうじゃ出てきてdamm itになります。
Meganezaru

2018/10/26 02:27

なるほど・・・log()の中でthisを利用した実装があれば、影響しそうですね。ユーザーがやっちゃう確率が高い気もするので、明示的にconsoleオブジェクトを参照する?など、何か工夫してるんですかね? this・・・おまじない的に、bind()使ったり、アロー関数にしてしまったりして、あまり意識してませんが、これは意識しておかないと、怖い仕様ですね(^_^;) @maisumakun さん 勉強になりました。ご教授ありがとうございました!
maisumakun

2018/10/26 03:02

実際、高精度に時間を取るためのperformance.nowというメソッドがありますが、これはthisがperformance以外になると失敗しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問