元スレ+ JavaScript の質問用スレッド vol.114 +
JavaScript覧 / PC版 /みんなの評価 :
901 = :
プロトタイプに持たせるプロパティーとインスタンスに持たせるプロパティーって
使ってる側では判別できないですよね
this._hoge = 'hoge';
と書いても、_hogeがインスタンスのものなのかプロトタイプのものなのかはそれだけだと分からない
プロトタイプのプロパティーは名前を変えたりした方がいいのでしょうか
902 = :
とりあえずプロトタイププロパティーはプリフィックスを変えました
クロックフォードはこの問題に何も言ってないのでしょうか
903 = :
>>901
この書き方だとインスタンスプロパティーにしか書けないと分かりました
プロトタイププロパティーは読み込みはthis.hogeで出来ますが
書き込みは出来ないようです
JS奥深し
904 = :
>>898
横からだが、undefined がNGなのはお互いの認識が一致してる
議論するなら配列をnullで初期化するか、[] で初期化するか、だけ
争点をはっきりさせないと、無駄に時間を使うことになるから注意
905 = :
インスタンスから、プロトタイプのプロパティーに明示的にアクセスしたい時
__proto__を使えば出来ますが、__proto__の有無はブラウザ依存なのでまだ使わない方がいいと見たことがあります
正式にはどうやればいいのでしょうか
906 = :
>>905
.constructor.prototypeではなくて?
907 = :
>>906
そうでした・・
かなり分かってきたと思っていたのですが何かまだ混乱しているようです
ありがとうございました
909 = :
undefinedは別に悪くない。undefinedのまま放っておくのがダメなだけ。
もしくはインスタンスと連想配列をごっちゃにして好き勝手使うような設計が悪い。
厳しくやるならインスタンスのプロパティの値へのアクセスは必ずゲッターセッターを伴い、
その時にインスタンスかどうかとセットアップ済みかどうかを確認するのが鉄則。
セットアップ前なのにインスタンスの情報が書き換えられるような設計にしてはいけない。
重要なのはスロットがあるかどうかをまず確認すること。
そして使うスロットは必ずundefinedで置いておくのが流儀。nullに未初期化の意味は無い。
そしてインスタンスとして使われる状態になるとき初めて、適切な型で初期化をする。
つまりスロット作成は継承されるプリコンストラクタで行い、コンストラクタでは値を代入するセットアップ作業だけに努める形になる。
今まで書いたことはES6では常識。ネイティブのコンストラクタは皆そうなってる。
ES5でもES6の<継承>@@create-constructor<非継承>が<継承>[[constructor]]-constructor<非継承>のような形で見えないだけで大体の概念は同じ。
突き詰めていくとJavaScriptでのコンストラクタは<継承>-<非継承>2段階となる宿命。
だから<継承>initialize-constructor<非継承>のような仕組みを考えるのは、実はとてつもなくセンスがいい。
ES5の範囲でまとめきるのはとても大変だが、やるなら<継承>ではundefinedのまま置いておき、<非継承>で代入してセットアップとしてネイティブに沿うのが普通。
910 = :
>>903
こんな風にしてみるとわかりやすいかも
function F(){
this.hoge = 1;
}
F.prototype.fuga = 2;
var f = new F();
console.log( f.hoge );
console.log( f.fuga );
console.log( f.hasOwnProperty('hoge') ); // true
console.log( f.hasOwnProperty('fuga') ); // false
f.hoge = 3;
f.fuga = 4;
console.log( f.hasOwnProperty('hoge') ); // true
console.log( f.hasOwnProperty('fuga') ); // true
911 = :
>>904
それはスマンな
配列をnullで初期化するか[]にするかは難しいところだが、
[]で初期化すると何も処理してない状態かデータが1つもなかったかが
判別出来ないのでやっぱりnullがいいと思われる
ただ、↓みたいなコードが増えて若干気持ち悪いが…
if (!array) {
array = [value];
} else {
array.push(value);
}
912 = :
>>909
最後の方が今一分からんが…1つ質問
var hoge = obj.getHoge(); // hogeは何らかのオブジェクト(数字とかではない)
とした時に、obj.hoge_ が未初期化(setHoge()されてない)時に何を返すの?
普通 null でしょ。undefined を返しちゃうの?
それとも getHoge() { return this.hoge_ ? this.hoge_ : null; } みたいなのを全部に書くか?
これだと this.hoge_ を undefined にしたままに出来るが面倒だ
913 = :
>>912
未初期化(hoge_===undefined)だとエラーにする。メソッドは未初期化なのに処理を進めてはいけない。
ただし未初期化な状態というのは原則継承の最中の特別な状態でしかありえない。
当然コンストラクタを通して使える状態にするときにはundefinedは残さない。
逆に、未初期化な状態だと分かるためにundefinedで置いておくことが大事。
未初期化なのにnullにしてしまうと、未初期化なのか正常に初期化された結果nullが入っているのか分からない。
つまりメソッドは処理をしていいかどうか分からない。
その場合別途、初期化フラグのプロパティを用意しなければならなくなる。
そういったことを考慮するとこれが
function Human(name) {
this.name = name;
}
こんな感じになる
914 = :
import ASSERT from 'lib/ASSERT.js';
const _HumanName_ = Symbol('HumanName');
export class Human {
static [Symbol.create]() {
let obj = {
__proto__: this.prototype,
[_HumanName_]: undefined
};
//* プロトタイプ最上位にProxy検問を設ける
ASSERT.SET_PROTO_UNDEFINED_BARRIER(obj);
// test only */
return obj;
}
constructor(name) {
// instanceof && hasOwn && isUndefined
ASSERT.CHECK_UNINITIALIZED(this, [_HumanName_]);
ASSERT.MATCH_STRING(this, {minLength: 1, maxLength: 100});
this[_HumanName_] = str;
}
get name() {
// instanceof && hasOwn && !isUndefined
ASSERT.CHECK_INITIALIZED(this, [_HumanName_]);
return this[_HumanName_];
}
}
915 = :
>>911
個人的には配列は [] で初期化して値チェックを行わない処理にする
null で初期化すると値の正当性検査が必要だが、[] なら for, forEach 共にそのままパスする
Array.prototype 系メソッドもそういう処理になってたと思う(自分の知る限りでは)
916 = :
>>898
> > ・変数定義するときは必ず代入する(代入したら値はなるべく変更しない)
> なるべく変更しないって曖昧な表現だけどまぁundefined以外の値で初期化と同じ事だよ
それはたぶん勘違いしてる。
君の言うのは「とりあえず初期化しておいて、あとで変更する」
この二つが一連の操作になってるでしょ?
それは、値を書き換えているわけで、それをやっちゃだめと言ってる。
> var a;
> if (hoge) a = b[c];
このコード、明らかに aをundefinedから何かの値に書き換えるという操作を行う。
ここで書くべきなコードはこれ。
var a = hoge ? b[c] : undefined;
aには最初に値を入れてから書き換えない。
undefinedは値が存在しないことを意味するので、原則として代入したらいけない。
だからこの例はaにundefinedを代入することになるのでよくない。
(しかし元のコードがundefinedになる以上それに合わせるしか無いのでこう書いた
>>899の例はhogeが偽の時の仕様がa = undefined から -1 に変わってるのでだめ。
917 = :
>>911
> 配列をnullで初期化するか[]にするかは難しいところだが、
> []で初期化すると何も処理してない状態かデータが1つもなかったかが
それは一概に決めるもんじゃない。
変数が配列しか入らないのなら[]にするべき。
区別する必要があるときだけnullを入れる。
何も考えずに適当な値で初期化していればいいという考え方はダメ。
原則として変数は正常な値を代入し、その後で書き換えないようにする。
これが完全にできるとは限らないが、そうした方がコードは複雑にならずに済む。
918 = :
スロットって何?ES6の概念?
920 = :
>>918 「スロット」はゲッタセッタのように、メッセージを受け取って値を保管したり提出したりするもの
もしくは単体で扱うことができれば変数のような存在になる
そしてプロトタイプベース言語では、名前付きスロットの集合がオブジェクトと呼ばれる
そして「プロパティ」は普通クラスベース言語でのクラスによって紐付けられるアクセサの集合のことを言う
スロットと違うのはオブジェクトの構成要素というより、フィールドを介してオブジェクトに関連付けられてるものということ
ただしJavaScriptでは、スロットの集合であるディスクリプタの集合がオブジェクトというようになっていて
その「オブジェクトに属するスロット二重構造」のことをプロパティと読んでいる
そして、ECMA仕様では所謂内部プロパティのことを、ディスクリプタを格納するわけではないのでinternal slotと呼ぶ
921 = :
初期化されてなくて潜在的バグになるって経験があまりないから
喧喧諤諤されてる話題がいまひとつ分からないな
オブジェクトが渡るところにundefinedで渡る→メンバアクセスでエラー
ってことは良くあるけど
ちゃんとエラーになるから潜在的にはならないし
922 = :
jqueryのイベントハンドラでは
イベントを起こした要素がthisに入っていますが
同じものはイベントオブジェクトのcurrentTargetにも入っているので、
thisに入れる必要なんてないのでは?
何のために入れてるんですか?
923 = :
IEで意味不明なバグが出てきたんですが
W =window.open(~)
↓
子ウインドウを消す
↓
if(W && W.window){
↓
Wが存在しているらしいのでW.window調べるとナゼかエラーが発生し
呼び出し先 (サーバー アプリケーションではなく、サーバー) は消失し、利用できません。すべての接続は無効です。呼び出しは実行されていません。
と表示されWを調べても [object] { } というのが出てきてこのオブジェクトが存在するのかしないのかよくわかんないです
924 = :
>>922
なんでだろうね。楽だからじゃね?
$.eachなんかもそうだけど、あのせいで
本来のthisキーワードの使い方がわからなくなってる人が増えた印象
925 = :
>>923
IEのwindowにはclosedっていうプロパティがあるよ
926 = :
var obokata={}
obokata.value="捏造";
obokata.stap=(function(){alert(this.value)});
obokata.stap();//捏造
obokata.stap2=(function(){alert(this.value)})();・・undefined
何故、obokata.stap2=(function(){alert(this.value)})();では
this.valueに文字列"捏造"が入らないのでしょうか?
obokata.stap2=(function(){alert(this.value)})();の即時実行関数式
でthis.valueに文字列を入れる方法を教えて下さい
929 = :
画像の高さと幅を取得する方法を教えてください
931 = :
>>930
グローバルじゃなきゃ困るんじゃね?
932 = :
>>931
そうなんですか?
933 = :
>>932
thisキーワードってのは、超大雑把に言うと
その関数が実行された時、その関数は誰のメソッドだったか?ってことじゃん
obokata.stap=(function(){alert(this.value)});
obokata.stap();//捏造
こう書いたらfunction(){alert(this.value)}はまさに、obokataオブジェクトのメソッドとして実行されてる
obokata.stapって書いてるんだから。これはわかるでしょ
いっぽう
obokata.stap2=(function(){alert(this.value)})();
この場合、function(){alert(this.value)}は、obokataの持ち物じゃないじゃん?
ただ( 関数オブジェクト )() って書いて実行しただけなのだから
934 = :
>>913
なんか話しが噛み合わないが…多分、初期化(未初期化)の事を勘違いしてる
初期化ってのは(メンバー)オブジェクトを使える状態にする事だぞ
コンストラクタで全部初期化出来ればそりゃ楽だが、どうしても物凄く後になる事もある
(ユーザー操作の結果によって初期化するとか)
なのに順番を間違って先にアクセスしちゃった場合に未初期化なのか、そもそも存在しない
メンバーにアクセスしてundefinedになったのか、どっかのバグで初期化後にundefinedが
伝搬して代入されているのかを判別しやすくするってだけだ
だからundefinedをみつけたら完全にtypoのようなコーディングミスといえる
> 未初期化なのか正常に初期化された結果nullが入っているのか分からない。
んなわけない
nullはオブジェクトとして使える状態なわけないからnullの場合は未初期化と同じ事
初期化してエラーになった可能性もあるが、そういう事がある場合は別途エラーコードを
用意した方がいいのかも
935 = :
>>915
確かに厳密に値の正当性チェックが必要ないならそれでいいとは思う
(うっかりnullにアクセスしないから安全だし)
936 = :
>>925
ありがとうございます。
これからはそれ使う事にします
937 = :
>>916
これも>>934で返答したのと同じだ
null→未初期化変数にアクセスしてる
undefined→typoとかしょうもないミスの可能性がある
これを区別するってだけのことだよ
パフォーマンス的な事を気にしてるっぽいけど、それはarray.lengthをfor文の外に
かかないと駄目だっていってるようなもんだぞ
計測結果でもみせてくれ
938 = :
>array.lengthをfor文の外に
>かかないと駄目だっていってるようなもんだぞ
こんなの常識だろ
ハイパフォーマンスJavaScriptにも書いてある
オライリーなめてんの?
940 = :
array.length 程度のものはループ内に書こうが事実上変わらないだろう
ループの外に変数作ってループの中から代入や再利用する類いの最適化は
コンパイラの最適化が利かなくなって
却ってパフォーマンスを落とすこともある
941 = :
どんなしょぼい最適化だよw
ループ中にあろうが結局全部巻き上げられるんだから
そんなわけの分からないことは起きないだろ
942 = :
コンパイラの一般論として
var len = array.length;
for (i = 0; i < len; ++i) {
これだとforを越えてlenを保存しておかないといけない
for (i = 0; i < array.length; ++i) {
これだとfor内でarrayが変更されない限りはarray.lengthはfor内の一時変数になる
巻き上げとは無関係だ
943 = :
実際に測ればそんな変な最適化なんてありえないと分かると思うんだが
944 = :
>>935
読み返してみたら誤解を招く書き方だったので訂正を
・値の正当性検査は予めしておくが、nullチェックはしない
・必要なら Array.isArray を使う
・あるいは、ToObject する(ArrayLikeなオブジェクトを許容する為。forEachはこの挙動だったと思う。)
いずれにしても、Object型であることは保証して最低限のエラーは出さないようにコーディングする
nullを混在させると無駄にチェックが必要になるので、個人的には使わない
945 = :
実際に測れば起きるよ
数値演算主体で変数が多いやつとか
変数は全部ループ内で宣言+初期化した方が10倍くらい速くなったりする
946 = :
そんなベンチ結果見たことない
証拠を出さないとおぼちゃんと同じ
947 = :
「初期化した方が速くなりまぁす」
「何倍ですか?」
「200倍くらいです」
948 = :
「変数の値がもしundefinedかnullなら指定した値を代入」をする
lodashの関数はありませんか?
_.defaultsにして欲しいのですが、オブジェクトのプロパティにしか対応してないようで
949 = :
jqueryプラグインは無名関数の中で設定すると書いてあるサイトがありますが
jQuery.fnのメンバを追加するだけなので、
他の変数に影響を与えることも、
方の変数の影響を受けることもないので、別にいいのでは?
950 = :
>>942
array.lengthを使うと、インタプリタには、
配列のサイズが変わったかどうかがわからないから、
毎回アクセスするんじゃないの?
配列のサイズが変わったかどうかを突き止めるのは、
かなり大変でしょ?
インタプリタはそんなに賢いかな?
var len = array.length;
と最適化を信じず、変数に代入しても、メモリの損はしれてる
漏れは、何回も呼ぶ関数はすべて、変数に代入してから、
その変数で呼び出しているよw
どこまで最適化されるか、わからないから
// 乱数を発生させる。少数点以下を切り捨てる
var fRnd = Math.random, fFlo = Math.floor;
fFlo(fRnd() * 100);
類似してるかもしれないスレッド
- + JavaScript の質問用スレッド vol.113 + (1001) - [97%] - 2014/1/25 12:46
- + JavaScript の質問用スレッド vol.118 + (1002) - [97%] - 2014/8/29 22:30
- + JavaScript の質問用スレッド vol.116 + (1002) - [97%] - 2014/7/1 0:45
- + JavaScript の質問用スレッド vol.115 + (1001) - [97%] - 2014/5/29 16:16
- + JavaScript の質問用スレッド vol.113 + (1001) - [97%] - 2014/3/15 21:30
- + JavaScript の質問用スレッド vol.119 + (1002) - [97%] - 2014/10/3 15:30
- + JavaScript の質問用スレッド vol.112 + (1001) - [97%] - 2013/11/27 16:46
- + JavaScript の質問用スレッド vol.111 + (1001) - [97%] - 2013/11/4 6:00
- + JavaScript の質問用スレッド vol.110 + (1001) - [97%] - 2013/10/13 14:01
- + JavaScript の質問用スレッド vol.134 + (1001) - [97%] - 2018/8/3 23:15
- + JavaScript の質問用スレッド vol.117 + (1009) - [97%] - 2014/8/5 3:30
- + JavaScript の質問用スレッド vol.104 + (1001) - [97%] - 2013/1/28 4:00
- + JavaScript の質問用スレッド vol.124 + (1001) - [97%] - 2015/7/16 1:30
- + JavaScript の質問用スレッド vol.144 + (288) - [97%] - 2020/5/17 20:00
- + JavaScript の質問用スレッド vol.121 + (1001) - [95%] - 2015/1/1 18:30
- + JavaScript の質問用スレッド vol.120 + (1002) - [95%] - 2014/11/8 1:15
- + JavaScript の質問用スレッド vol.122 + (1004) - [95%] - 2015/2/14 4:45
トップメニューへ / →のくす牧場書庫について