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

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

新規登録して質問してみよう
ただいま回答率
85.50%
JavaScript

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

Q&A

解決済

2回答

1846閲覧

オブジェクトのプロパティに関数を宣言するのは如何なものか

manzyun

総合スコア2244

JavaScript

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

2グッド

2クリップ

投稿2017/03/27 14:40

編集2017/03/28 04:38

背景

現在個人的にMixxxというDJソフトのスクリプトを書いているのですが、どうしても「<任意の関数> is not function」というエラーがでてしまい、コレはもしかして自分のコードの書き方が原因なのではと思ったので質問させていただきます。(Mixxxのスクリプトは正確にはQtScript4ではありますが、ECMA-262 5th Editionの仕様に則っているため、JavaScriptのタグをつけさせていただきました。)

問題点

問題のソースを一部抜粋します。

JavaScript

1numarkNV.activeButtons = {};

JavaScript

1numarkNV.unShiftedButtons = { 2 play: function play (channel, control, value, status, group) { 3 if (value) { 4 engine.setParameter(group, 'play', !(engine.getParameter(group, 'play'))); 5 } 6 },

JavaScript

1numarkNV.shiftedButtons = { 2 play: function (channel, control, value, status, group) { 3 if (value) { 4 engine.setParameter(group, 'play_stutter', !(engine.getParameter(group, 'play_stutter'))); 5 } 6},

JavaScript

1numarkNV.shiftButton = function (channel, control, value, status, group) { 2 // This function mapping to Shift button 3 if (!value) return; 4 numarkNV.activeButtons = numarkNV.shiftedButtons //※: この行はオリジナルにはありませんが、説明のために書き足しました。

オリジナルのソースコードはgithubで公開しております

なぜコノような関数の宣言方法をしているのかというと、このMIDIコントローラーはそれのShiftキーを押した際に振る舞いが変化するためです。

振る舞いの変化のさせ方は、shiftキーが押されている間はnumarkNV.activeButtonsオブジェクトにnumarkNV.shiftedButtonsオブジェクトを参照するようにさせるというアプローチをしております。

が、Shiftキーを押しながら再生ボタンを押しても振る舞いが変化すること無く、お察しかもしれませんが、MixxxのログでnumarkNV.activeButton.play is not functionと叱られて動作しません。

質問

ここでようやく質問なのですが、

  1. このような関数の宣言はやはり間違っているのでしょうか。
  2. 間違っているとすれば、どのような関数の宣言が適切なのでしょうか。

私個人としては、

javascript

1numarkNV.unShiftedButton.prototype.play = function play (channel, control, value, status, group) { 2 if (value) { 3 engine.setParameter(group, 'play', !(engine.getParameter(group, 'play'))); 4 }

という具合で、prototypeを使って関数を登録するべきなのかと思っているのですが、
「あれ? そもそもオブジェクト生成時にprototypeは生成されたっけ?」
と、少し自信が無いです。

javascript/es5 at es5-deprecated · airbnb/javascriptを眺めながらそんな気はするものの、闇雲にスクリプトを書いて実行してトライアンドデバッグするのも少々疲れてきてしまっていて開発が停滞中のため、少しteratailの皆様のお知恵を拝借しようと思った次第でございます。


以上です。長々とした質問、かつインターネットブラウザにおけるJavaScriptの質問ではないのに最後までお読みいただき、有難うございます。

mhashi, s.t.👍を押しています

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

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

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

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

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

Lhankor_Mhy

2017/03/28 04:12

コードでは numarkNV.activeButtons とあり、エラーメッセージは numarkNV.activeButton.play is not function となっていますが、この's'の有無はtypoか何かで、実際のコードでは整合がとれているのでしょうか?
manzyun

2017/03/28 04:16

現状のソースコードをそのままgithubにあげたものなので。実際のコードもそうなっているものと思われます。ご指摘ありがとうございます!
guest

回答2

0

javascriptには暗いですが興味があるので自分なりに調べてみました。冗長で要領の悪い内容ですがご容赦いただければと思います。

numarkNV.activeButton.play is not function

というエラーは文字通りplayプロパティーを参照した結果が関数オブジェクトではなかったということを意味すると思います。javascriptのオブジェクトや関数はどんなふうになっているかを調べてみました。使用エンジンはjava8付属のnashorn(ECMAScript-262 Edition 5準拠)です。

オブジェクトのプロパティーの一覧をダンプするために以下のような関数を定義しています。

javascript

1function dumpObj(o) { 2 var level = 0 3 while (o) { 4 print("--- level " + level + " ---") 5 level += 1 6 var propNames = Object.getOwnPropertyNames(o) 7 for (var i in propNames) { 8 var name = propNames[i] 9 print(name + ": " + o[name]) 10 } 11 o = Object.getPrototypeOf(o) 12 } 13}

最初に{}を調べてみました。

javascript

1var numarkNV = {} // とりあえずテストのため 2numarkNV.activeButton = {} 3 4dumpObj(numarkNV.activeButton) 5==>結果 6--- level 0 --- 7--- level 1 --- 8toString: function toString() { [native code] } 9toLocaleString: function toLocaleString() { [native code] } 10valueOf: function valueOf() { [native code] } 11hasOwnProperty: function hasOwnProperty() { [native code] } 12isPrototypeOf: function isPrototypeOf() { [native code] } 13propertyIsEnumerable: function propertyIsEnumerable() { [native code] } 14constructor: function Object() { [native code] } 15__proto__: null

つまり何も自身のプロパティーを持たずObjectとしての振る舞いができるようにObjectのprototypeを引き継いでいるもの(=Objectのインスタンス)ということですね。この状態でnumarkNV.activeButton.play()などとすると、当然ながら以下のエラーになります。

TypeError: numarkNV.activeButton.play is not a function

次にオブジェクトリテラルでplayプロパティーを持つオブジェクトを記述してみました。

javascript

1numarkNV.shiftedButton = { 2 play: function() { print('play') } 3} 4 5dumpObj(numarkNV.shiftedButton) 6==>結果 7--- level 0 --- 8play: function() { print('play') } 9--- level 1 --- 10toString: function toString() { [native code] } 11...12__proto__: null

この状態でnumarkNV.shiftedButton.play()とすると期待どおり実行できます。また以下のようにしてみるとnumarkNV.activeButton.play()も実行できました。

javascript

1numarkNV.activeButton = numarkNV.shiftedButton 2numarkNV.activeButton.play()

こうしてみると原因は「オブジェクトリテラルで定義するかprototypeを用いて定義するかといった定義フォームの問題ではなく単に「playという関数プロパティーを持つオブジェクトをnumarkNV.activeButtonに設定してあるかどうか」がポイントと思いました。


オブジェクトリテラルとして定義するかprototypeを使うかについては、自分は**(A)他のオブジェクトとと共通のプロパティーを持たないシングルトンでいいならオブジェクトリテラル**、(B)インスタンスを動的に生成したり一部の属性を他のオブジェクトと共有する前提ならprototypeで書くとよいと思いました。継承を使いたいなら(B)という言い方とも言えましょう。

質問文から自分はshiftedButton, unShiftedButtonなどが(A)に該当するような印象を受けました。

(B)として考えるなら例えば以下のようにクラスとして書くとよいと思います。(継承をどう書くかは調べてません><)

javascript

1function ShiftedButton() { 2 prototype = { 3 play: function(...) { ... } 4 otherMehotd: function(...) { ... } 5 ... 他のプロパティー 6 } 7} 8 9numarkNV.shiftedButton = new ShiftedButton

投稿2017/03/28 03:23

KSwordOfHaste

総合スコア18392

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

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

manzyun

2017/04/04 21:57 編集

わざわざ調査までしていただいてありがとうございます。 となると問題点が色々明るくなってきました。 おそらく今回質問文に掲載しているものとは別に、イベントハンドラ用のxmlでのメソッドの呼び出しでtypoしている説が濃厚になってきました。 # 2017-04-05 追記 後から色々考えると、KSwordOfHasteさんの回答のほうがベストアンサーだったような気がします……。
guest

0

ベストアンサー

shiftedButtonsのplayが無名関数を指定しているように
unShiftedButtonsのplayも同様の無名関数を利用してみては
いかがでしょうか?

投稿2017/03/28 03:20

yambejp

総合スコア114572

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

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

manzyun

2017/03/28 03:28

それが無名関数にしていた際にも <無名関数を入れた変数> is not function. と怒られているので、もしかして名前つけてやったらと思った次第だったのですが、やはり無名関数を変数に代入する方がスマートなのでしょうか。 それと、やっぱりprototypeを使って関数をプロパティに代入した方がEcmaScriptの仕様上正しいものなのでしょうか? 今回一番お尋ねしたいのはこちらだったりします。
yambejp

2017/03/28 04:01

prototypeで宣言しなくても 予め名前をつけて関数を宣言しておけば参照できませんか? function play(v1,v2,v3){ return v1+':'+v2+':'+v3; }; var obj={"play":play} console.log(obj.play("x","y","z"));
manzyun

2017/03/28 04:20

あーなるほど。その方がしっくりきそうです!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問