
正文
JavaScript Garden2
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
Types
Equality and Comparisons
JavaScript has two different ways of comparing the values of objects for equality.
The Equality Operator
The equality operator consists of two equal signs:
==
JavaScript features
weak typing
. This means that the equality operator
coerces
types in order to compare them.
"" == "0" // false
0 == "" // true
0 == "0" // true
false == "false" // false
false == "0" // true
false == undefined // false
false == null // false
null == undefined // true
" \t\r\n" == 0 // true
The above table shows the results of the type coercion, and it is the main reason why the use of
==
is widely regarded as bad practice. It introduces hard-to-track-down bugs due to its complicated conversion rules.
Additionally, there is also a performance impact when type coercion is in play; for example, a string has to be converted to a number before it can be compared to another number.
The Strict Equality Operator
The strict equality operator consists of
three
equal signs:
===
.
It works like the normal equality operator, except that strict equality operator does
not
perform type coercion between its operands.
"" === "0" // false
0 === "" // false
0 === "0" // false
false === "false" // false
false === "0" // false
false === undefined // false
false === null // false
null === undefined // false
" \t\r\n" === 0 // false
The above results are a lot clearer and allow for early breakage of code. This hardens code to a certain degree and also gives performance improvements in case the operands are of different types.
Comparing Objects
While both
==
and
===
are called
equality
operators, they behave differently when at least one of their operands is an
Object
.
{} === {}; // false
new String('foo') === 'foo'; // false
new Number(10) === 10; // false
var foo = {};
foo === foo; // true
Here, both operators compare for
identity
and
not
equality; that is, they will compare for the same
instance
of the object, much like
is
in Python and pointer comparison in C.
In Conclusion
It is highly recommended to only use the
strict equality
operator. In cases where types need to be coerced, it should be done explicitly and not left to the language's complicated coercion rules.
The
typeof
Operator
The
typeof
operator (together with
instanceof
) is probably the biggest design flaw of JavaScript, as it is almost
completely broken
.
Although
instanceof
still has limited uses,
typeof
really has only one practical use case, which does
not
happen to be checking the type of an object.
Note:
While
typeof
can also be called with a function like syntax, i.e.
typeof(obj)
, this is not a function call. The parentheses behave as normal and the return value will be used as the operand of the
typeof
operator. There is
no
typeof
function.
The JavaScript Type Table
Value Class Type
-------------------------------------
"foo" String string
new String("foo") String object
1.2 Number number
new Number(1.2) Number object
true Boolean boolean
new Boolean(true) Boolean object
new Date() Date object
new Error() Error object
[1,2,3] Array object
new Array(1, 2, 3) Array object
new Function("") Function function
/abc/g RegExp object (function in Nitro/V8)
new RegExp("meow") RegExp object (function in Nitro/V8)
{} Object object
new Object() Object object
In the above table,
Type
refers to the value that the
typeof
operator returns. As can be clearly seen, this value is anything but consistent.
The
Class
refers to the value of the internal
[[Class]]
property of an object.
From the Specification:
The value of
[[Class]]
can be one of the following strings.
Arguments
,
Array
,
Boolean
,
Date
,
Error
,
Function
,
JSON
,
Math
,
Number
,
Object
,
RegExp
,
String
.
In order to retrieve the value of
[[Class]]
, one has to make use of the
toString
method of
Object.prototype
.
The Class of an Object
The specification gives exactly one way of accessing the
[[Class]]
value, with the use of
Object.prototype.toString
.
function is(type, obj) {
var clas = Object.prototype.toString.call(obj).slice(8, -1);
return obj !== undefined && obj !== null && clas === type;
}
is('String', 'test'); // true
is('String', new String('test')); // true
ES5 Note:
For convenience the return value of
Object.prototype.toString
for both
null
and
undefined
was
changed
from
Object
to
Null
and
Undefined
in ECMAScript 5.
In the above example,
Object.prototype.toString
gets called with the value of this being set to the object whose
[[Class]]
value should be retrieved.
Testing for Undefined Variables
typeof foo !== 'undefined'
The above will check whether
foo
was actually declared or not; just referencing it would result in a
ReferenceError
. This is the only thing
typeof
is actually useful for.
In Conclusion
In order to check the type of an object, it is highly recommended to use
Object.prototype.toString
because this is the only reliable way of doing so. As shown in the above type table, some return values of
typeof
are not defined in the specification; thus, they can differ between implementations.
Unless checking whether a variable is defined,
typeof
should be avoided.
The
instanceof
Operator
The
instanceof
operator compares the constructors of its two operands. It is only useful when comparing custom made objects. Used on built-in types, it is nearly as useless as the typeof operator.
Comparing Custom Objects
function Foo() {}
function Bar() {}
Bar.prototype = new Foo();
new Bar() instanceof Bar; // true
new Bar() instanceof Foo; // true
// This just sets Bar.prototype to the function object Foo,
// but not to an actual instance of Foo
Bar.prototype = Foo;
new Bar() instanceof Foo; // false
Using
instanceof
with Native Types
new String('foo') instanceof String; // true
new String('foo') instanceof Object; // true
'foo' instanceof String; // false
'foo' instanceof Object; // false
One important thing to note here is that
instanceof
does not work on objects that originate from different JavaScript contexts (e.g. different documents in a web browser), since their constructors will not be the exact same object.
In Conclusion
The
instanceof
operator should
only
be used when dealing with custom made objects that originate from the same JavaScript context. Just like the
typeof
operator, every other use of it should be
avoided
.
Type Casting
JavaScript is a
weakly typed
language, so it will apply
type coercion
wherever
possible.
// These are true
new Number(10) == 10; // Number.toString() is converted
// back to a number
10 == '10'; // Strings gets converted to Number
10 == '+10 '; // More string madness
10 == '010'; // And more
isNaN(null) == false; // null converts to 0
// which of course is not NaN
// These are false
10 == 010;
10 == '-10';
ES5 Note:
Number literals that start with a
0
are interpreted as octal (Base 8). Octal support for these has been
removed
in ECMAScript 5 strict mode.
To avoid the issues above, use of the strict equal operator is
highly
recommended. Although this avoids a lot of common pitfalls, there are still many further issues that arise from JavaScript's weak typing system.
Constructors of Built-In Types
The constructors of the built in types like
Number
and
String
behave differently when being used with the
new
keyword and without it.
new Number(10) === 10; // False, Object and Number
Number(10) === 10; // True, Number and Number
new Number(10) + 0 === 10; // True, due to implicit conversion
Using a built-in type like
Number
as a constructor will create a new
Number
object, but leaving out the
new
keyword will make the
Number
function behave like a converter.
In addition, passing literals or non-object values will result in even more type coercion.
The best option is to cast to one of the three possible types
explicitly
.
Casting to a String
'' + 10 === '10'; // true
By prepending an empty string, a value can easily be cast to a string.
Casting to a Number
+'10' === 10; // true
Using the
unary
plus operator, it is possible to cast to a number.
Casting to a Boolean
By using the
not
operator twice, a value can be converted a boolean.
!!'foo'; // true
!!''; // false
!!'0'; // true
!!'1'; // true
!!'-1' // true
!!{}; // true
!!true; // true
JavaScript has two different ways of comparing the values of objects for equality.
The Equality Operator
The equality operator consists of two equal signs:
==
JavaScript features weak typing . This means that the equality operator coerces types in order to compare them.
"" == "0" // false
0 == "" // true
0 == "0" // true
false == "false" // false
false == "0" // true
false == undefined // false
false == null // false
null == undefined // true
" \t\r\n" == 0 // true
The above table shows the results of the type coercion, and it is the main reason why the use of
==
is widely regarded as bad practice. It introduces hard-to-track-down bugs due to its complicated conversion rules.
Additionally, there is also a performance impact when type coercion is in play; for example, a string has to be converted to a number before it can be compared to another number.
The Strict Equality Operator
The strict equality operator consists of
three
equal signs:
===
.
It works like the normal equality operator, except that strict equality operator does not perform type coercion between its operands.
"" === "0" // false
0 === "" // false
0 === "0" // false
false === "false" // false
false === "0" // false
false === undefined // false
false === null // false
null === undefined // false
" \t\r\n" === 0 // false
The above results are a lot clearer and allow for early breakage of code. This hardens code to a certain degree and also gives performance improvements in case the operands are of different types.
Comparing Objects
While both
==
and
===
are called
equality
operators, they behave differently when at least one of their operands is an
Object
.
{} === {}; // false
new String('foo') === 'foo'; // false
new Number(10) === 10; // false
var foo = {};
foo === foo; // true
Here, both operators compare for
identity
and
not
equality; that is, they will compare for the same
instance
of the object, much like
is
in Python and pointer comparison in C.
In Conclusion
It is highly recommended to only use the strict equality operator. In cases where types need to be coerced, it should be done explicitly and not left to the language's complicated coercion rules.
The
typeof
Operator
The
typeof
operator (together with
instanceof
) is probably the biggest design flaw of JavaScript, as it is almost
completely broken
.
Although
instanceof
still has limited uses,
typeof
really has only one practical use case, which does
not
happen to be checking the type of an object.
Note:
While
typeof
can also be called with a function like syntax, i.e.
typeof(obj)
, this is not a function call. The parentheses behave as normal and the return value will be used as the operand of the
typeof
operator. There is
no
typeof
function.
The JavaScript Type Table
Value Class Type
-------------------------------------
"foo" String string
new String("foo") String object
1.2 Number number
new Number(1.2) Number object
true Boolean boolean
new Boolean(true) Boolean object
new Date() Date object
new Error() Error object
[1,2,3] Array object
new Array(1, 2, 3) Array object
new Function("") Function function
/abc/g RegExp object (function in Nitro/V8)
new RegExp("meow") RegExp object (function in Nitro/V8)
{} Object object
new Object() Object object
In the above table,
Type
refers to the value that the
typeof
operator returns. As can be clearly seen, this value is anything but consistent.
The
Class
refers to the value of the internal
[[Class]]
property of an object.
From the Specification:
The value of
[[Class]]
can be one of the following strings.
Arguments
,
Array
,
Boolean
,
Date
,
Error
,
Function
,
JSON
,
Math
,
Number
,
Object
,
RegExp
,
String
.
In order to retrieve the value of
[[Class]]
, one has to make use of the
toString
method of
Object.prototype
.
The Class of an Object
The specification gives exactly one way of accessing the
[[Class]]
value, with the use of
Object.prototype.toString
.
function is(type, obj) {
var clas = Object.prototype.toString.call(obj).slice(8, -1);
return obj !== undefined && obj !== null && clas === type;
}
is('String', 'test'); // true
is('String', new String('test')); // true
ES5 Note:
For convenience the return value of
Object.prototype.toString
for both
null
and
undefined
was
changed
from
Object
to
Null
and
Undefined
in ECMAScript 5.
In the above example,
Object.prototype.toString
gets called with the value of this being set to the object whose
[[Class]]
value should be retrieved.
Testing for Undefined Variables
typeof foo !== 'undefined'
The above will check whether
foo
was actually declared or not; just referencing it would result in a
ReferenceError
. This is the only thing
typeof
is actually useful for.
In Conclusion
In order to check the type of an object, it is highly recommended to use
Object.prototype.toString
because this is the only reliable way of doing so. As shown in the above type table, some return values of
typeof
are not defined in the specification; thus, they can differ between implementations.
Unless checking whether a variable is defined,
typeof
should be avoided.
The
instanceof
Operator
The
instanceof
operator compares the constructors of its two operands. It is only useful when comparing custom made objects. Used on built-in types, it is nearly as useless as the typeof operator.
Comparing Custom Objects
function Foo() {}
function Bar() {}
Bar.prototype = new Foo();
new Bar() instanceof Bar; // true
new Bar() instanceof Foo; // true
// This just sets Bar.prototype to the function object Foo,
// but not to an actual instance of Foo
Bar.prototype = Foo;
new Bar() instanceof Foo; // false
Using
instanceof
with Native Types
new String('foo') instanceof String; // true
new String('foo') instanceof Object; // true
'foo' instanceof String; // false
'foo' instanceof Object; // false
One important thing to note here is that
instanceof
does not work on objects that originate from different JavaScript contexts (e.g. different documents in a web browser), since their constructors will not be the exact same object.
In Conclusion
The
instanceof
operator should
only
be used when dealing with custom made objects that originate from the same JavaScript context. Just like the
typeof
operator, every other use of it should be
avoided
.
Type Casting
JavaScript is a
weakly typed
language, so it will apply
type coercion
wherever
possible.
// These are true
new Number(10) == 10; // Number.toString() is converted
// back to a number
10 == '10'; // Strings gets converted to Number
10 == '+10 '; // More string madness
10 == '010'; // And more
isNaN(null) == false; // null converts to 0
// which of course is not NaN
// These are false
10 == 010;
10 == '-10';
ES5 Note:
Number literals that start with a
0
are interpreted as octal (Base 8). Octal support for these has been
removed
in ECMAScript 5 strict mode.
To avoid the issues above, use of the strict equal operator is
highly
recommended. Although this avoids a lot of common pitfalls, there are still many further issues that arise from JavaScript's weak typing system.
Constructors of Built-In Types
The constructors of the built in types like
Number
and
String
behave differently when being used with the
new
keyword and without it.
new Number(10) === 10; // False, Object and Number
Number(10) === 10; // True, Number and Number
new Number(10) + 0 === 10; // True, due to implicit conversion
Using a built-in type like
Number
as a constructor will create a new
Number
object, but leaving out the
new
keyword will make the
Number
function behave like a converter.
In addition, passing literals or non-object values will result in even more type coercion.
The best option is to cast to one of the three possible types
explicitly
.
Casting to a String
'' + 10 === '10'; // true
By prepending an empty string, a value can easily be cast to a string.
Casting to a Number
+'10' === 10; // true
Using the
unary
plus operator, it is possible to cast to a number.
Casting to a Boolean
By using the
not
operator twice, a value can be converted a boolean.
!!'foo'; // true
!!''; // false
!!'0'; // true
!!'1'; // true
!!'-1' // true
!!{}; // true
!!true; // true
The
typeof
operator (together with
instanceof
) is probably the biggest design flaw of JavaScript, as it is almost
completely broken
.
Although
instanceof
still has limited uses,
typeof
really has only one practical use case, which does
not
happen to be checking the type of an object.
Note:
While
typeof
can also be called with a function like syntax, i.e.
typeof(obj)
, this is not a function call. The parentheses behave as normal and the return value will be used as the operand of the
typeof
operator. There is
no
typeof
function.
The JavaScript Type Table
Value Class Type
-------------------------------------
"foo" String string
new String("foo") String object
1.2 Number number
new Number(1.2) Number object
true Boolean boolean
new Boolean(true) Boolean object
new Date() Date object
new Error() Error object
[1,2,3] Array object
new Array(1, 2, 3) Array object
new Function("") Function function
/abc/g RegExp object (function in Nitro/V8)
new RegExp("meow") RegExp object (function in Nitro/V8)
{} Object object
new Object() Object object
In the above table,
Type
refers to the value that the
typeof
operator returns. As can be clearly seen, this value is anything but consistent.
The
Class
refers to the value of the internal
[[Class]]
property of an object.
From the Specification:
The value of
[[Class]]
can be one of the following strings.
Arguments
,
Array
,
Boolean
,
Date
,
Error
,
Function
,
JSON
,
Math
,
Number
,
Object
,
RegExp
,
String
.
In order to retrieve the value of
[[Class]]
, one has to make use of the
toString
method of
Object.prototype
.
The Class of an Object
The specification gives exactly one way of accessing the
[[Class]]
value, with the use of
Object.prototype.toString
.
function is(type, obj) {
var clas = Object.prototype.toString.call(obj).slice(8, -1);
return obj !== undefined && obj !== null && clas === type;
}
is('String', 'test'); // true
is('String', new String('test')); // true
ES5 Note:
For convenience the return value of
Object.prototype.toString
for both
null
and
undefined
was
changed
from
Object
to
Null
and
Undefined
in ECMAScript 5.
In the above example,
Object.prototype.toString
gets called with the value of this being set to the object whose
[[Class]]
value should be retrieved.
Testing for Undefined Variables
typeof foo !== 'undefined'
The above will check whether
foo
was actually declared or not; just referencing it would result in a
ReferenceError
. This is the only thing
typeof
is actually useful for.
In Conclusion
In order to check the type of an object, it is highly recommended to use
Object.prototype.toString
because this is the only reliable way of doing so. As shown in the above type table, some return values of
typeof
are not defined in the specification; thus, they can differ between implementations.
Unless checking whether a variable is defined,
typeof
should be avoided.
The
instanceof
Operator
The
instanceof
operator compares the constructors of its two operands. It is only useful when comparing custom made objects. Used on built-in types, it is nearly as useless as the typeof operator.
Comparing Custom Objects
function Foo() {}
function Bar() {}
Bar.prototype = new Foo();
new Bar() instanceof Bar; // true
new Bar() instanceof Foo; // true
// This just sets Bar.prototype to the function object Foo,
// but not to an actual instance of Foo
Bar.prototype = Foo;
new Bar() instanceof Foo; // false
Using
instanceof
with Native Types
new String('foo') instanceof String; // true
new String('foo') instanceof Object; // true
'foo' instanceof String; // false
'foo' instanceof Object; // false
The
instanceof
operator compares the constructors of its two operands. It is only useful when comparing custom made objects. Used on built-in types, it is nearly as useless as the typeof operator.
Comparing Custom Objects
function Foo() {}
function Bar() {}
Bar.prototype = new Foo();
new Bar() instanceof Bar; // true
new Bar() instanceof Foo; // true
// This just sets Bar.prototype to the function object Foo,
// but not to an actual instance of Foo
Bar.prototype = Foo;
new Bar() instanceof Foo; // false
instanceof
with Native Types
new String('foo') instanceof String; // true
new String('foo') instanceof Object; // true
'foo' instanceof String; // false
'foo' instanceof Object; // false
One important thing to note here is that
instanceof
does not work on objects that originate from different JavaScript contexts (e.g. different documents in a web browser), since their constructors will not be the exact same object.
In Conclusion
The
instanceof
operator should
only
be used when dealing with custom made objects that originate from the same JavaScript context. Just like the
typeof
operator, every other use of it should be
avoided
.
Type Casting
JavaScript is a
weakly typed
language, so it will apply
type coercion
wherever
possible.
// These are true
new Number(10) == 10; // Number.toString() is converted
// back to a number
10 == '10'; // Strings gets converted to Number
10 == '+10 '; // More string madness
10 == '010'; // And more
isNaN(null) == false; // null converts to 0
// which of course is not NaN
// These are false
10 == 010;
10 == '-10';
JavaScript is a weakly typed language, so it will apply type coercion wherever possible.
// These are true
new Number(10) == 10; // Number.toString() is converted
// back to a number 10 == '10'; // Strings gets converted to Number
10 == '+10 '; // More string madness
10 == '010'; // And more
isNaN(null) == false; // null converts to 0
// which of course is not NaN // These are false
10 == 010;
10 == '-10';
ES5 Note:
Number literals that start with a
0
are interpreted as octal (Base 8). Octal support for these has been
removed
in ECMAScript 5 strict mode.
To avoid the issues above, use of the strict equal operator is highly recommended. Although this avoids a lot of common pitfalls, there are still many further issues that arise from JavaScript's weak typing system.
Constructors of Built-In Types
The constructors of the built in types like
Number
and
String
behave differently when being used with the
new
keyword and without it.
new Number(10) === 10; // False, Object and Number
Number(10) === 10; // True, Number and Number
new Number(10) + 0 === 10; // True, due to implicit conversion
Using a built-in type like
Number
as a constructor will create a new
Number
object, but leaving out the
new
keyword will make the
Number
function behave like a converter.
In addition, passing literals or non-object values will result in even more type coercion.
The best option is to cast to one of the three possible types explicitly .
Casting to a String
'' + 10 === '10'; // true
By prepending an empty string, a value can easily be cast to a string.
Casting to a Number
+'10' === 10; // true
Using the unary plus operator, it is possible to cast to a number.
Casting to a Boolean
By using the not operator twice, a value can be converted a boolean.
!!'foo'; // true
!!''; // false
!!'0'; // true
!!'1'; // true
!!'-1' // true
!!{}; // true
!!true; // true








