diff --git a/Libraries/LibJS/Runtime/ObjectConstructor.cpp b/Libraries/LibJS/Runtime/ObjectConstructor.cpp index 95237401af..34fea44646 100644 --- a/Libraries/LibJS/Runtime/ObjectConstructor.cpp +++ b/Libraries/LibJS/Runtime/ObjectConstructor.cpp @@ -41,6 +41,7 @@ ObjectConstructor::ObjectConstructor() put("prototype", interpreter().global_object().object_prototype()); put_native_function("defineProperty", define_property, 3); + put_native_function("is", is, 2); put_native_function("getOwnPropertyDescriptor", get_own_property_descriptor, 2); put_native_function("getOwnPropertyNames", get_own_property_names, 1); put_native_function("getPrototypeOf", get_prototype_of, 1); @@ -146,4 +147,20 @@ Value ObjectConstructor::define_property(Interpreter& interpreter) return &object; } +Value ObjectConstructor::is(Interpreter& interpreter) +{ + auto value1 = interpreter.argument(0); + auto value2 = interpreter.argument(1); + if (value1.is_nan() && value2.is_nan()) + return Value(true); + if (value1.is_number() && value1.as_double() == 0 && value2.is_number() && value2.as_double() == 0) { + if (value1.is_positive_zero() && value2.is_positive_zero()) + return Value(true); + if (value1.is_negative_zero() && value2.is_negative_zero()) + return Value(true); + return Value(false); + } + return typed_eq(interpreter, value1, value2); +} + } diff --git a/Libraries/LibJS/Runtime/ObjectConstructor.h b/Libraries/LibJS/Runtime/ObjectConstructor.h index 06fdac9c9e..4fbfa6ed59 100644 --- a/Libraries/LibJS/Runtime/ObjectConstructor.h +++ b/Libraries/LibJS/Runtime/ObjectConstructor.h @@ -43,6 +43,7 @@ private: virtual const char* class_name() const override { return "ObjectConstructor"; } static Value define_property(Interpreter&); + static Value is(Interpreter&); static Value get_own_property_descriptor(Interpreter&); static Value get_own_property_names(Interpreter&); static Value get_prototype_of(Interpreter&); diff --git a/Libraries/LibJS/Runtime/Value.h b/Libraries/LibJS/Runtime/Value.h index 3bed8c2db7..701cad1de3 100644 --- a/Libraries/LibJS/Runtime/Value.h +++ b/Libraries/LibJS/Runtime/Value.h @@ -57,6 +57,8 @@ public: bool is_nan() const { return is_number() && __builtin_isnan(as_double()); } bool is_infinity() const { return is_number() && __builtin_isinf(as_double()); } + bool is_positive_zero() const { return is_number() && 1.0 / as_double() == __builtin_huge_val(); } + bool is_negative_zero() const { return is_number() && 1.0 / as_double() == -__builtin_huge_val(); } bool is_finite_number() const { if (!is_number()) diff --git a/Libraries/LibJS/Tests/Object.is.js b/Libraries/LibJS/Tests/Object.is.js new file mode 100644 index 0000000000..e58d1ded22 --- /dev/null +++ b/Libraries/LibJS/Tests/Object.is.js @@ -0,0 +1,53 @@ +load("test-common.js"); + +try { + assert(Object.is.length === 2); + + var a = [1, 2, 3]; + var o = {foo: "bar"}; + + assert(Object.is("", "") === true); + assert(Object.is("foo", "foo") === true); + assert(Object.is(0, 0) === true); + assert(Object.is(+0, +0) === true); + assert(Object.is(-0, -0) === true); + assert(Object.is(1.23, 1.23) === true); + assert(Object.is(42, 42) === true); + assert(Object.is(NaN, NaN) === true); + assert(Object.is(Infinity, Infinity) === true); + assert(Object.is(+Infinity, +Infinity) === true); + assert(Object.is(-Infinity, -Infinity) === true); + assert(Object.is(true, true) === true); + assert(Object.is(false, false) === true); + assert(Object.is(null, null) === true); + assert(Object.is(undefined, undefined) === true); + assert(Object.is(undefined) === true); + assert(Object.is() === true); + assert(Object.is(a, a) === true); + assert(Object.is(o, o) === true); + + assert(Object.is("test") === false); + assert(Object.is("foo", "bar") === false); + assert(Object.is(1, "1") === false); + assert(Object.is(+0, -0) === false); + assert(Object.is(-0, +0) === false); + assert(Object.is(42, 24) === false); + assert(Object.is(Infinity, -Infinity) === false); + assert(Object.is(-Infinity, +Infinity) === false); + assert(Object.is(true, false) === false); + assert(Object.is(false, true) === false); + assert(Object.is(undefined, null) === false); + assert(Object.is(null, undefined) === false); + assert(Object.is([], []) === false); + assert(Object.is(a, [1, 2, 3]) === false); + assert(Object.is([1, 2, 3], a) === false); + assert(Object.is({}, {}) === false); + assert(Object.is(o, {foo: "bar"}) === false); + assert(Object.is({foo: "bar"}, o) === false); + assert(Object.is(a, o) === false); + assert(Object.is(o, a) === false); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +}