4

オブジェクトを数値で「分割」できるのはなぜですか?

4

5 に答える 5

5

更新の遅れ
私の回答には不完全で、時には完全に間違った情報が含まれていたことを考えると、間違いを訂正するのが最善だと思いました。遅くなりましたが、ここに行きます:

ほとんどすべてのJSオブジェクトには、共通の2つの3つvalueOf()のメソッドがあります。dateオブジェクトの場合、メソッドにマップされgetTime()、数値が返されます。この数値は、1970年1月1日からのミリ秒数です。多くのプログラミング言語は、この日付を使用して日付を基にしています。これはUnixタイムスタンプと呼ばれ、日付はUnixエポックと呼ばれます。あなたが疑問に思っていた場合に備えて。
別のメソッドはtoString、文字列を返す(明らかに)です。
3番目の方法はですhasOwnProperty。これはプロトタイプチェーンでにさかのぼることができますが、Object.prototypeこの質問では重要ではありません。

2つの値(オブジェクトかどうか)を比較するときはいつでも、JSは、2つの値を安全に比較できるように、両方のオペランドのタイプを強制します(たとえば1 == '1'、文字列'1'をに強制しますNumber)。
この型強制は、オブジェクトまたはプリミティブ値が連結されて攪拌される場合、または式が特異値に評価される場合にも適用されます(たとえば、コンソールで、new Date;と入力すると、意味がわかります)。
オブジェクトのデフォルトの動作はDate文字列に強制変換され、toStringメソッドが呼び出されます。

したがって、Dateインスタンスに違いはありません。これらはオブジェクトです。つまり、変数の値はオブジェクトへの参照になります。ただし、式/ステートメントでは/、オブジェクトに対して算術演算子()を使用しています。このコンテキストでは文字列はあまり意味がないため、JSはvalueOfメソッドにフォールバックします(Dateさまざまな方法で文字列を数値に強制変換できます)。これにより、簡単に分割できるが生成されます。比較演算子、、、およびを使用する場合も、 同じ動作が期待できます(実際に観察できます)。 これは、日付を比較し、それらを使用して出力を生成することは、ほとんどの場合、楽勝であることを意味します。Number
><<=>=

var d1 = new Date();
var d2 = new Date(1234567890123);
if (d1 > d2)
{
   //do stuff
}

完全に書かれた場合、これは次のとおりです。

Date.prototype.valueOf = Date.prototype.getTime; //<-- this isn't how its done, but think of the valueOf method as doing something similar

if (d1.getTime() > d2.getTime()) //OR:
if (d1.valueOf() > d2.valueOf())

比較とは別に、他の利点もあります。

var d3 = new Date(d1 - 1000); //new date, 1 second before d1

ただし、トレードオフ/落とし穴があります。JSのすべてのオブジェクトと同様に、または
を使用した等価性チェックは、最初は少し奇妙です。=====

var a = new Date();
var b = new Date(a.valueOf());
console.log(a.toString() === b.toString());//true
console.log(a.valueOf() === b.valueOf());//true, to the milisecond
console.log(a == b);//false!
console.log(a === b);//false!!

私が言ったように、オブジェクトが割り当てられた変数は、実際にはそのオブジェクトの値を保持せず、それを参照します。aとは同じオブジェクトの異なるインスタンスを参照しているためb、等しくありません。また、それらは両方とも(同じタイプの)オブジェクトであるため、型強制は行われません。
住所を除いて、すべての点で100%等しい2軒の家と考えてください。強制がない場合は、実際には
「フィクションストリート1とフィクションストリート2に家があります。これら2つの家は同じですか?」のように言っています。答えは断然ノーです。

これを修正するには、JSに、これらの家を別のタイプに手動で強制することによって、これらの家の外観を比較するように明示的に依頼する必要があります。これは思ったよりずっと簡単です:

console.log(a.valueOf() == b.valueOf());//true
//or shorter, still:
console.log(+(a) == +(b));
//coerce to strings, either call toString, or:
console.log((''+a) == (''+b));

繰り返しますが、これは最初はばかげているように見えるかもしれませんが、この方法で、少なくとも2つの変数が実際に同じインスタンスを参照しているかどうかをテストできます。2つのオブジェクトがメモリを占有していると仮定します。実際に必要なのは1つだけですが、これらのインスタンスの1つへの参照を解放してGCすることができます。

if (a !== b && +(a) === +(b))
{//their values are the same, but different instances
    b = a;//now b references the same object as a
}
console.log(a === b);//true
console.log(+(a) === +(b));// true again

Date今でも、特にオブジェクトに影響を与えるいくつかの奇妙な点があります。次のステートメントがログに記録する内容を推測してみてください。

a.setTime(a.getTime() + 1000);//add 1 second
console.log(a == (b + 1000));
console.log(a === (b + 1000));
console.log((a-1000) == b);
console.log((a-1000) === +b);

答えは次のとおりです。false、false、false、true。どうして?
最初のケースは単純です。+演算子はオーバーロードされ、文字列も連結され、Dateオブジェクトのデフォルトの動作はtoStringそれ自体であるため、b+1000として評価されb.toString() + '1000'ます。
次に、型と値のチェック===を使用すると、強制が行われないため、ほとんどの場合falseになります。次に、オーバーロードされていない
算術演算子 を使用して1000を減算することにより、左側のオペランドが引き続き数値に評価されることを意味します。ただし、右のオペランドは、文字列に強制変換されるという誤った動作に戻ります。それらは等しくありません。-
最後の例では、右のオペランドを明示的に数値に強制し、trueを返します。

上記のすべての場合に対処するためtrueに、ここに何を書くべきか

console.log(+a == (+b + 1000));
console.log(+a === (+b + 1000));
console.log((a-1000) == +b);
console.log((a-1000) === +b);

インスタンスを明示的に強制するだけDateで、問題はありません。

于 2012-08-17T14:23:02.883 に答える
4

除算演算子を使用すると、new Date()は暗黙的に数値に変換されるためです(1970年1月1日から始まるこの日付の合計ミリ秒を表します)。+文字列では合計ではなく連結を意味するため、演算子は機能しません。+日付を合計しようとすると、ミリ秒ではなく、その日付のtoString()が返されますが、文字列には演算子*がないため、機能します。 *。たとえば、を試してくださいnew Date() * 2

Dateグローバルオブジェクトの詳細については、https ://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Dateを参照してください。

編集:日付が/を含む式に含まれている場合、日付は文字列に変換されると言いましたが、もちろん間違っていました。私はすでに答えを訂正しました。私の答えをさらに明確にすることができるいくつかのコメントが以下にあります。文字列から数値への動作は引き続き機能します。つまり、有効な数値を表す文字列は乗算、除算、減算できますが、合計演算子を使用して文字列を連結するため、加算できません。見てください:

console.log( "10" + "1" );
console.log( "10" - "1" );
console.log( "10" * "2" );
console.log( "10" / "3" );

console.log( 10 + "1" );
console.log( 10 - "1" );
console.log( 10 * "2" );
console.log( 10 / "3" );

console.log( "10" + 1 );
console.log( "10" - 1 );
console.log( "10" * 2 );
console.log( "10" / 3 );
于 2012-08-17T14:11:08.793 に答える
4

オブジェクトに対して算術演算を実行すると、そのvalueOf関数が暗黙的に呼び出されます。

実際に分割できるオブジェクトを作成するには、次のことを試してください。

function Foo() {

    this.valueOf = function() {
        return 500;
        };

    }

var bar = new Foo();
console.log(bar/1000); // -> 0.5
于 2012-08-17T14:24:11.383 に答える
1

分割前の日付オブジェクトは、1970年1月1日からのミリ秒を与える数値に変換されます

new Date()/1000 => Number(new Date()) / 1000 = some number

于 2012-08-17T14:14:31.930 に答える
0

ほとんどの言語は、実際には、日付を独自の内部言語で単なる数値として表します。Javascriptが使用する規則は、1970年1月1日からのミリ秒数であり、他の多くの言語にも同様の規則があります。これは、タイミング方法が機能するのと同じ方法で、単純に日付を相互に減算できるのと同じ理由です。

于 2012-08-17T14:11:48.863 に答える