Trying to get my JavaSscript funda开发者_开发问答mentals strong. So the question is about string literals. Aren't they Objects
? If your answer is 'yes' then my question is why is instanceof
returning false
?
> var s = new String
> s.constructor.toString()
function String() { [native code] }
> typeof s
object
> s instanceof String
true
> s instanceof Object
true
> s instanceof Number
false
So far so good.
> typeof 'c'
string
> 'c' instanceof Object
false
> 'c' instanceof String
false
> 'c'.length
1
> 'c'.charAt(0)
c
> 'c'.constructor.toString()
function String() { [native code] }
String literals are primitives (String values), String objects can be created with the String constructor in a new
expression:
"foo" instanceof String // false
new String("foo") instanceof String // true
Edit: Something that seems to be confusing (by looking at the accepted answer here), is that you can still access properties defined on the prototype objects of primitive values, for example:
"foo".indexOf == String.prototype.indexOf // true
"foo".match == String.prototype.match // true
String.prototype.test = true;
"foo".test // true
true.toString == Boolean.prototype.toString
(3).toFixed == Number.prototype.toFixed // true
// etc...
The reason of that relies on the Property Accessors, the dot notation .
and the bracket notation []
.
Let's give a look to the algorithm in the ECMA-262 specification:
The production MemberExpression : MemberExpression [ Expression ] (or MemberExpression . Identifier) is evaluated as follows:
Evaluate
MemberExpression
.Call
GetValue(Result(1))
.Evaluate Expression.
Call
GetValue(Result(3))
.Call
ToObject(Result(2))
.Call
ToString(Result(4))
.Return a value of type Reference whose base object is Result(5) and whose property name is
Result(6)
.
In the Step 5, the ToObject
internal operator type-converts the MemberExpression to object, depending on it's type.
The primitives are converted to Objects without noticing, and that's why you can access the properties defined on the prototype.
Great explanation of this here. Copied for reference below.
That's because those things are primitives, and unless they need to be used as objects (when you are calling methods on them, for example) they remain so. The only time they "become" objects is when they need to be wrapped. If you are familiar with the concept of "boxing" in .NET, then think of it in that way.
Here is an example - take a look at this code:
Number.prototype.times = function(func) {
for(var index = 1; index <= this; index++) {
func(index);
}
};
So, the following code will fail:
3.times(print); // assume 'print' writes to standard out
3, by itself is a primitive. That said, the following will work:
(3).times(print); // assume 'print' writes to standard out
That would display the numbers 1, 2, and 3. Because of the parenthesis, the JavaScript interpreter will temporarily wrap the primitive 3 in a Number object, call the method, and then garbage collect the object since it isn't needed any longer.
Anyway, a full discussion of this can be found in "JavaScript: The Definitive Guide."
精彩评论