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

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

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

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

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Q&A

解決済

4回答

741閲覧

Jqueryのlengthはなぜlength()ではないのか

退会済みユーザー

退会済みユーザー

総合スコア0

JavaScript

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

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

0グッド

0クリップ

投稿2019/05/13 16:59

Jqueryにおいて、Jqueryオフジェクトの要素の個数を取得するのにlengthを使いますが、なぜlength()でないのかを教えていただきたいです。調べてみると"メソッドではなくプロパティだから"とでてきましたが、納得がいきません。

javascript

1$('.hoge').length;

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

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

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

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

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

think49

2019/05/13 23:34

BAを選ばれましたが、完全に納得したわけではないようですね。 「なぜlength()である必要があると考えたのか」が不明なので、具体的な回答ご出来ない状況です。質問を具体化する工夫があると良いと思います。
退会済みユーザー

退会済みユーザー

2019/05/14 02:25

lengthは要素数を調べるという操作ではないかと考えたとき、プロパティよりもメソッドという単語の方が似合うと思ったからです。似合うという主観を交えてしかその理由を説明できなかったため今回は省略しました。
guest

回答4

0

最終的にプロパティだからで終わりますが、
JavaScriptのArray.lengthがちょっと珍しいgetter, setterのプロパティとして実装しているからです。

イメージとしてはこんな感じ

JavaScript

1var obj = { 2 get length () { return 10; } 3} 4console.log(obj.length); // 10 5obj.length = 100; 6console.log(obj.length); // 10 <- getterプロパティは代入しても変化しない

setterも定義すれば挙動を定義できます。
配列を司るArrayはlengthプロパティに無理やり数値をねじ込むことで配列の要素数を拡張したり、0を代入することで空配列に変更することが可能ですが、
数値以外を代入するとエラーになります。

JavaScript

1var arr = []; 2arr.length = "hoge"; 3// Uncaught RangeError: Invalid array length

このArrayがlengthプロパティを所持しているという仕様は、
「ふーん、配列はlengthをプロパティで作ったのね」だけでは収まらず、多くの場所で「前提」となっています。

配列は機能(メソッド・プロパティ)は、配列を便利に扱う為のものですから、
他のコレクションを扱うオブジェクト(クラスやインスタンス)を定義する時に足りないと感じる事もありますよね。
なのでビルトインのクラスとして配列に似た用途別のオブジェクトが多数存在します。

しかし、それらにはforEachやmapといった配列用のメソッドがなく、
「あ〜配列に変換したいな〜」というケースも多々あります。
その時に「配列っぽい」値を本物の配列と同じように扱う機能があります。

参考: 配列風オブジェクト

JavaScript

1// 配列に変換したい! 2var obj = {0: "taro", 1: "jiro", length: 2}; 3console.log(Array.prototype.slice.call(obj, 0)); 4// ["taro", "jiro"] 5 6// 配列っぽくforEachメソッドに放り込みたい 7Array.prototype.forEach.call(obj, function(it){ 8 console.log(it); 9}); 10// "taro" 11// "jiro"

こんな風にlengthを所持しているオブジェクトかつ、
数値の添字でアクセス可能なオブジェクトは、
Arrayの多くのメソッドに直接放り込んでメソッドを起動させることが出来ます。


Jqueryのlengthはなぜlength()ではないのか

jQueryは$(selector)でjQueryオブジェクトを返すことで有名ですが、
こいつ、中に配列っぽいものを内包しているんですね。
例えばfindで子孫の要素を探しに行くときも配列の全てを探索しますし、
cssメソッドでcssプロパティを書き換える時も、掴んだ要素全てが対象です。

で、このjQueryも配列っぽいコレクションのオブジェクトを定義する時に、
「じゃあ、慣習に従って、jQueryオブジェクトにもlengthプロパティを所持させようか」
という決定がなされたはずです。

この慣習や、言語のルールに従うというのはとても重要な感覚の一つで、
私も仮にJavaScriptで何かしらのコレクションを作る事を決めてライブラリとして公開する際はlengthプロパティはつけて当然だなと考えています。

因みにjQueryを作ったジョン・レシグ氏はJavaScriptのウィザード的な存在として認知されており、JavaScript Ninjaの極意という有名な書籍を書いています。

投稿2019/05/14 03:58

miyabi-sun

総合スコア21158

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

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

退会済みユーザー

退会済みユーザー

2019/05/14 07:53

回答ありがとうございます。 var obj = { get length () { return 10; } } のところの文法構造がわかりません。教えていただけませんか?
miyabi-sun

2019/05/14 08:47

ES2015というJavaScriptの新仕様で追加された構文です。 {}でオブジェクトを宣言する際にいろんな書き方が出来ます。 https://qiita.com/kura07/items/356bd37733f457d3177f 昔は{key1: value1, key2: value2}のみだったのですが、 なんじゃこりゃ?みたいな書き方もありますね。
退会済みユーザー

退会済みユーザー

2019/05/14 21:41

なるほどです。オブジェクトリテラルの書き方が色々あることはわかりました。 lengthがプロパティであることも、なんとなくですが理解しました。 が、完全に理解するには知識と経験が不足しています。 せっかく丁寧に回答していただいたのに申し訳ないです。
guest

0

getter/setter

オブジェクトのプロパティに設定されるgetter/setterは Object.getOwnPropertyDescriptor() で確認することが出来ます。

JavaScript

1const arrayLike = {}; 2Object.defineProperty(arrayLike, 'length', { 3 enumerable: true, configurable: true, 4 get: function get () { 5 return Object.keys(this).length; 6 }, 7 set: function set (length) { 8 length = Math.abs(length) || 0; 9 length -= length % 1; 10 11 for (let i of Object.keys(this)) { 12 if ((+i).toString() === i && i >= length) { 13 delete this[i]; 14 } 15 } 16 17 return length; 18 } 19}); 20 21console.log(Object.getOwnPropertyDescriptor(arrayLike, 'length')); // {get: ƒ, set: ƒ, enumerable: false, configurable: false}

余談(arrayLike は配列ライクな何か)。

JavaScript

1console.log(arrayLike.length); // 0 2arrayLike[0] = 'a'; 3arrayLike[1] = 'b'; 4console.log(arrayLike.length); // 2 5console.log(arrayLike); // {0: "a", 1: "b"} 6arrayLike.length = 0; 7console.log(arrayLike.length); // 0 8console.log(arrayLike); // {}

jQuery#length

jQuery#length と Array#length の挙動は、似て非なるものです。
jQuery#length は getter 及び setter ではなく、ただの静的プロパティとして定義されています。
大雑把に疑似コードを書くなら、こうです。

JavaScript

1function jQuery (selectorText) { 2 const nodeList = document.querySelectorAll(selectorText); 3 const jqueryObjects = {}; 4 5 nodeList.forEach((element, index) => jqueryObjects[index] = element); 6 jqueryObjects.length = nodeList.length; // 要素数に変動があった時、lengthプロパティに要素数を代入しておく 7 8 return jqueryObjects; 9} 10 11console.log(jQuery('body').length); // 1

jQuery#length が参照された時、予め代入された数値を呼び出しています。
ですので、[質問への追記・修正、ベストアンサー選択の依頼] で質問者さんが想像されたように、

lengthは要素数を調べるという操作ではないかと考えたとき、プロパティよりもメソッドという単語の方が似合うと思ったからです。

length プロパティを参照した時に要素数を計算して返しているわけではありません


getter/setterではない事は、Object.getOwnPropertyDescriptor() で確認できます。
(以降、jquery-3.4.1.min.js が読み込まれている前提のコードを書きます)

HTML

1<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> 2<script> 3'use strict'; 4const jquery1 = jQuery(document); 5 6console.log(jquery1.length); // 1 7console.log(Object.getOwnPropertyDescriptor(jquery1, 'length')); // {value: 1, writable: true, enumerable: true, configurable: true} 8</script>

jQuery()new jQuery() は等価であり、要素が存在しない時には jQuery.prototype.length が参照される挙動をします(Array#length は違います)。

JavaScript

1const jquery2 = new jQuery; 2console.log(jquery2.length); // 0 3console.log(Object.getPrototypeOf(jquery2).length); // 0 4console.log(Object.getOwnPropertyDescriptor(jQuery.prototype, 'length')); // {value: 0, writable: true, enumerable: true, configurable: true} 5console.log(Object.getOwnPropertyDescriptor(jquery2, 'length')); // undefined

jQuery#length は「ただの代入されたプロパティ」なので、他所のコードから任意の数値に変更する事が出来てしまいます(Array#length は違います)。

JavaScript

1const jquery3 = jQuery('html'); 2 3console.log(jquery3.length); // 1 4jquery3.length = 4; // 不正値を代入してみる 5console.log(jquery3.length); // 4 (不正値に書き換わってしまう)

Array#length

Array#length は、getter/setter ではありません

JavaScript

1console.log(Object.getOwnPropertyDescriptor([], 'length')); // {value: 0, writable: true, enumerable: false, configurable: false}

Array#length がsetterのような挙動を示すのは、配列がExotic Objectsとして内部メソッド [[DefineOwnProperty]] を書き換えている為です。

JavaScript

1const array2 = [1,2,3,4,5,6,7,8,9]; 2 3array2.length = 3; // 要素数を3つに設定する 4console.log(array2); // [1,2,3]; (4つ目以降の要素が削除されている)

Array#length はgetterでもありませんので、「要素数が確定するタイミング」は jQuery#length と基本的に同じです。
Array#length を参照した時に要素数を計算しているわけではなく、要素数の変動が起こる処理(Array#push, Array#filter等)の中で予め、length値を確定させています。

JavaScript

1const array1 = [1,2]; 2 3array1.push(3); // Array#push は length プロパティに 3 を代入する 4console.log(array1.length); // 3

Array#length は要素数ではない

便宜上、「Array#length = 配列の要素数」の体で説明しましたが、厳密には要素数ではありません。

JavaScript

1const array3 = [1,,,4,5,6,,8,,10]; 2const values = Object.values(array); 3 4console.log(array3.length); // 10 5console.log(values.length); // 6 6console.log(values); // [1, 4, 5, 6, 8, 10]

上記コードで分かるように、Array#length は存在する要素インデックスに1を加算した数値になります。

Re: KoO. さん

投稿2019/05/14 13:31

編集2019/05/14 13:48
think49

総合スコア18164

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

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

退会済みユーザー

退会済みユーザー

2019/05/14 21:50

回答ありがとうございます。 javascript歴4日ほどの僕には少々話が難しすぎました。 理解できず申し訳ないです。 もう少し勉強が進んでから読み直してみます。
think49

2019/05/14 23:45 編集

ざっくりいえば、jQuery#length は「jQuery(), jQuery#add() 等の要素数が変化する動作を行った時に値を代入し直しているだけの普通のプロパティ」です。 値を変化させているのは、jQuery(), jQuery#add() 等であって、lengthプロパティは何もしていません。ごく普通のプロパティです。 Array#length は上記に加えて、「プロパティ書き換えにトラップを仕掛け、プロパティ名が "length" だった場合に要素値を変化させる機構」があります([プロパティ書き込みを行う [DefineOwnProperty]] を独自処理に書き換えています)。 jQuery#length がこの機構を模倣するには、new Proxy() を使用する必要があります。
guest

0

BA選出されており、解決済みになっておりますが、
気になったので回答です。

過去バージョンのjQueryには、size()メソッドがありました。
(jQueryバージョン3以降では完全に廃止されている。)
機能としては今日のlengthプロパティと同じ機能です。

miyabi-sunさんのご回答が、的を射ていると思いますが、
ネイティブJavaScriptにおける、HTMLCollection型変数の要素数が格納されているプロパティも、
メソッドではなく、element.lengthとなっているので、
そのネイティブと同じように扱える、仕様を統一する、といったことも考慮されての仕様なのではないでしょうか?
あくまで個人的な感想であり、ジョン・レシグ氏の記事や意図などを参考にしているわけではありません。
そのライブラリ作成者の意図や、思いも参照されると、納得いく答えが見つかるかもしれませんよ。

投稿2019/05/14 08:09

miyabi_takatsuk

総合スコア9528

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

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

退会済みユーザー

退会済みユーザー

2019/05/14 21:44

回答ありがとうございます。 ライブラリ作成者の意図や、思いを参照するというのは全く思いつきませんでした。
miyabi_takatsuk

2019/05/15 01:57

優秀なエンジニアほど、なんとなくでそうしているというものは少なく、必ずそういう仕様にしているのは、理由や意図が存在しています。 JavaScriptは4日目とのことですが、まずは疑問はノートにでもメモして、とりあえず置いておき、 今はひとまず疑問あっても、参考にしているものの通りにやってみて、使い方や言語の性質や役割を学んでいかれるのがいいと思いますよー。 どうか頑張ってください。
guest

0

ベストアンサー

たしかに「メッソドではなくプロパティだから」は、「なんでプロパティにしたのか」についての回答にはなってないですね。

https://qiita.com/toshi0383/items/656c10388f71c6ab44d2

JavaでもArray.lengthはプロパティらしく、↑の下部のコメントでやり取りがちょっとありますね。
文法を似せようとしていたはずなので、javascriptでも同様にプロパティにしたのかもしれません。

それと、自分も知らなかったのですが、、、

https://builder.japan.zdnet.com/script/sp_javascript-kickstart-2007/20366841/

lengthは書き込み可能ですw
この仕様だとプロパティになっている方が自然な気はします。

投稿2019/05/13 17:23

otolab

総合スコア765

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

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

退会済みユーザー

退会済みユーザー

2019/05/13 17:41

回答ありがとうございます。 なんとなくですが、わかりました。 まだ勉強し始めたばかりで記事の内容でよくわからない箇所がいくつもあるので、一つ一つ調べてみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問