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

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

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

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

Q&A

解決済

2回答

1310閲覧

javascript callメソッドについて

退会済みユーザー

退会済みユーザー

総合スコア0

JavaScript

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

1グッド

0クリップ

投稿2019/02/20 15:56

https://qiita.com/Chrowa3/items/b3e2961c4930abc1369b

callメソッドの勉強で、こちらの記事を読んでいるのですが、

js

1var lists = document.getElementsByTagName('li'); 2lists = Array.prototype.slice.call(lists,0);

こちらの部分で

var lists = document.getElementsByTagName('li');

この時のvar listsは

"配列ではなく、lengthを持っている HTMLCollection であって配列用のメソッドは使えない"

と言われてます。

まず、HTMLCollectionというのは配列とは異なったオブジェクトなんですよね...。

そしてcallメソッドとは例えば以下のような場合
Array.prototype.slice.call(lists,0);
Arrayオブジェクトの中で宣言されてるthisがvar listsに置き換わるイメージでしょうか。

ちょっとかなり混乱しながら書いてて申し訳ないです。

Array.prototype.slice.call(lists,0);

ここでcallメソッドの引数で渡されてるlistsはHTMLCollectionという配列とは異なったオブジェクトらしいですが、なぜ配列とは異なったオブジェクトがArrayオブジェクトの中のthisに置き変われるのか分からないです...。

退会済みユーザー👍を押しています

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

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

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

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

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

guest

回答2

0

ベストアンサー

まずソース:Qiitaをやめましょう。
別に参考にしたり新しい事に出会うために利用するのは良いのですが、Firefox作ってる団体が管理されているMDNの方が100倍信憑性が高いので裏付けを取るようにしてください。

まずはcallメソッドとはなんぞやを見に行きましょう。
JavaScriptのメソッドというのは、オブジェクトのプロパティに関数を代入したものです。

つまり関数とメソッドは定義上の違いはなくって、
thisに依存した設計の関数はオブジェクトのプロパティに持たせた方が便利だからメソッド、
thisに依存せず独立した関数はそのまま関数として取り扱った方が良い。

これくらいの違いです。


メソッドはFunction.prototypeで定義されているプロパティが使用可能です。
Function.prototype.callのページを見に行きます。

Arrayオブジェクトの中で宣言されてるthisがvar listsに置き換わるイメージでしょうか。

そのとおり、第一引数はthisになるとバッチリ書かれています。
ちゃんとMDNを見に行けば答えが書いてあるでしょ?


ここでcallメソッドの引数で渡されてるlistsはHTMLCollectionという配列とは異なったオブジェクトらしいですが、なぜ配列とは異なったオブジェクトがArrayオブジェクトの中のthisに置き変われるのか分からないです...。

JavaScriptは動的型付け言語なので、
Stringを期待している変数や引数に、NumberやObject、null値等をねじ込んでも別にエラーになりません。
(所持しているメソッドや文字列操作等で失敗して実行時エラーが飛び出す可能性はあるけどね)

Array.prototype.sliceというメソッドが存在したとして、
それのthisを無理やりすげ替えても別にエラーになりません。
これはどんなメソッドに関しても言えます。

もちろん、実行時エラーになる可能性も高いのでちゃんと裏付けを取ること。

じゃあなんで動くのか

少々寄り道しましたが、これが今回の話のキモになります。
まずArray.prototype.sliceに対応しているという
「配列の様なオブジェクト」に関して説明しなければなりません。

JavaScriptには配列(Array)に似てるけど型が違うというオブジェクトが沢山存在します。

まずなんでしたっけ?
element.getElementsByTagNameの戻り値を確認しましょう。
「elements は見つかった要素の「生」の NodeList で、サブツリー内に出現した順番になります。」
NodeListじゃねーか!

まぁいいや、このNodeListはNodeListという型であってArray型ではありません。
でもlengthプロパティはあるし[0]というふうな添字プロパティでアクセス出来ますね?
この2つの条件を持つオブジェクトは「配列の様なオブジェクト」とJavaScriptで定義されており、
多くのArray.prototype系のメソッドのthisとして放り込んでも使える設計になっています。

Array ジェネリックメソッド - MDN

つまり、こんなお手製のしょぼいオブジェクトをあてがっても正常動作してしまいます。

JavaScript

1var obj = { 2 "0": "taro", 3 "1": "jiro", 4 "length": 2 5} 6Array.prototype.slice.call(obj, 0); 7// ["taro", "jiro"]

はい、見事本物の配列になって帰ってきました。
要するに実際に数値のプロパティにアクセス出来て、lengthプロパティを所持してれば何でも良いんですよ。

投稿2019/02/20 17:08

miyabi-sun

総合スコア21158

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

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

miyabi_takatsuk

2019/02/21 01:03

横槍失礼します。 大変に勉強になったもので・・・。 obj.slice()とかだと、実行エラーになることから、 プロパティ名が数値で、length持った上で、 大元のprototype定義の方から、callでthisを置き換えたら、 実行できるってことですよね。 ほんと、よくわからないですね、JavaScript・・・。 HTMLCollection型も、配列型をオーバーライドした型とすれば、直接配列メソッド使えてよかったのに。
退会済みユーザー

退会済みユーザー

2019/02/21 01:24

毎回とても丁寧な回答ありがとうございます。 分かりました、MDNちゃんと見るようにします(T_T)。 Arrayクラスの中で宣言されてる各functionは、そこで宣言されているthisが、Arrayではなく、Array-likeなものでも動くように設計されているという事でしょうか。 そして、今回のsliceもそのように設計されていて、Arrayオブジェクトにして返してくれるんですね。
miyabi-sun

2019/02/21 03:28

JSは元がLispでプロトタイプベースです。 Lisp由来の縛りを嫌った思想が原因でこんなゴネゴネとキメラを作るような言語になったのだと思われます。 オブジェクト指向って○○だよねの元凶はJavaですが、 元々JavaScriptはLiveScriptという名で開発され、 リリース直前でJavaが流行ってるから改名した経緯があります。 つまり一切Javaを参考にしてないんだからこんなもんでしょという気はします。
guest

0

Array.prototype.slice等は、「lengthプロパティと、0からlength-1までの数字のプロパティを持つオブジェクト(Array-likeオブジェクト)」であれば、呼び出せるようです。

他の例:

JavaScript

1a = {} 2a[0]=10 3a[1]=20 4a.length=2 5 6Array.prototype.forEach.call(a, function(x){ console.log(x);} ) 7 8// a.forEach( function(x){ console.log(x);} ) // これはエラー 9 10console.log(a) 11Array.prototype.pop.call(a) 12console.log(a) 13 14// a.pop() // これはエラー

popみたいに書き換えるメソッドは駄目かと思いましたが、いけますね。
すべてのメソッドが使えるのかどうかは知りませんが、いけそうな気がします。

投稿2019/02/20 16:33

otn

総合スコア84423

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

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

otn

2019/02/20 16:36

Array-like でググるといろいろ情報があります。
退会済みユーザー

退会済みユーザー

2019/02/21 01:26

なるほどです、ありがとうございました。 Array-likeググってみます(>_<)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問