Why is it that I can do the following in javascript:
function a() {};
a.foo = 30;
Specifically, why can I set a property on the function a? After all, I cannot do this:
var a = 20;
a.foo = 30;
You really can't do this because it's a syntax error
function a = function() {};
I suppose you simply want to say:
function a() {}
Anyway. The reason that you cannot get a property out of a number, is that it is not a real Object.
a = 20;
a.foo = 30; // this works
alert(a.foo); // this alerts nothing
Believe it or not, the same goes for strings:
a = "ohai";
a.foo = 30; // this works
alert(a.foo); // this alerts nothing
However if it's String object, then it works as expected:
a = new String("ohai");
a.foo = 30; // this works
alert(a.foo); // this alerts 30
Or if it's an Number object. You get the point.
String and number literals are not objects in Javascript. That's the reason.
In JavaScript the dot (.) operator expects it's left value to be an object. And in JavaScript, functions are objects.
Basically, in JavaScript, there are four main datatypes:
Number
String
Boolean
Object
Objects encompasses functions, arrays, date objects, and (for lack of a better word) regular objects. The function object is unique in that it contains executable code, and can be invoked.
Numbers are primitives, and thus you cannot access/assign properties to/from them.
In Javascript, a function is an object, so you can set properties on it:
function a() {};
a.foo = 30;
a.foo; // evaluates to 30
A number literal however creates a primitive value (which has no properties) and not an object.
a = 20; // Create primitive value using number literal
When you set a property on a primitive value, in fact you create a wrapper object around the primitive value and set the property on the wrapper object, not the primitive value.
a.foo = 30; // wrapper object created and directly thrown away
(new Number(a)).foo = 30; // --> equivalent
When you read the property, again you create a wrapper object, whihch hasn't the property defined.
a.foo; // wrapper object created, has no foo property
(new Number(a)).foo; // --> equivalent, evaluates to undefined
In javascript functions are objects. Or they inherit from objects, or something.
try doing
a = function(){};
alert(typeof a.prototype);
Related
So I was playing around the other day just to see exactly how mass assignment works in JavaScript.
First I tried this example in the console:
a = b = {};
a.foo = 'bar';
console.log(b.foo);
The result was "bar" being displayed in an alert. That is fair enough, a and b are really just aliases to the same object. Then I thought, how could I make this example simpler.
a = b = 'foo';
a = 'bar';
console.log(b);
That is pretty much the same thing, isn't it? Well this time, it returns foo not bar as I would expect from the behaviour of the first example.
Why does this happen?
N.B. This example could be simplified even more with the following code:
a = {};
b = a;
a.foo = 'bar';
console.log(b.foo);
a = 'foo';
b = a;
a = 'bar';
console.log(b);
(I suspect that JavaScript treats primitives such as strings and integers differently to hashes. Hashes return a pointer while "core" primitives return a copy of themselves)
In the first example, you are setting a property of an existing object. In the second example, you are assigning a brand new object.
a = b = {};
a and b are now pointers to the same object. So when you do:
a.foo = 'bar';
It sets b.foo as well since a and b point to the same object.
However!
If you do this instead:
a = 'bar';
you are saying that a points to a different object now. This has no effect on what a pointed to before.
In JavaScript, assigning a variable and assigning a property are 2 different operations. It's best to think of variables as pointers to objects, and when you assign directly to a variable, you are not modifying any objects, merely repointing your variable to a different object.
But assigning a property, like a.foo, will modify the object that a points to. This, of course, also modifies all other references that point to this object simply because they all point to the same object.
Your question has already been satisfyingly answered by Squeegy - it has nothing to do with objects vs. primitives, but with reassignment of variables vs. setting properties in the same referenced object.
There seems to be a lot of confusion about JavaScript types in the answers and comments, so here's a small introduction to JavaScript's type system:
In JavaScript, there are two fundamentally different kinds of values: primitives and objects (and there is no thing like a 'hash').
Strings, numbers and booleans as well as null and undefined are primitives, objects are everything which can have properties. Even arrays and functions are regular objects and therefore can hold arbitrary properties. They just differ in the internal [[Class]] property (functions additionally have a property called [[Call]] and [[Construct]], but hey, that's details).
The reason that primitive values may behave like objects is because of autoboxing, but the primitives themselves can't hold any properties.
Here is an example:
var a = 'quux';
a.foo = 'bar';
document.writeln(a.foo);
This will output undefined: a holds a primitive value, which gets promoted to an object when assigning the property foo. But this new object is immediately discarded, so the value of foo is lost.
Think of it like this:
var a = 'quux';
new String(a).foo = 'bar'; // we never save this new object anywhere!
document.writeln(new String(a).foo); // a completly new object gets created
You're more or less correct except that what you're referring to as a "hash" is actually just shorthand syntax for an Object.
In the first example, a and b both refer to the same object. In the second example, you change a to refer to something else.
here is my version of the answer:
obj = {a:"hello",b:"goodbye"}
x = obj
x.a = "bonjour"
// now obj.a is equal to "bonjour"
// because x has the same reference in memory as obj
// but if I write:
x = {}
x.a = obj.a
x.b = obj.b
x.a = "bonjour"
// now x = {a:"bonjour", b:"goodbye"} and obj = {a:"hello", b:"goodbye"}
// because x points to another place in the memory
You are setting a to point to a new string object, while b keeps pointing to the old string object.
In the first case you change some property of the object contained in the variable, in the second case you assign a new value to the variable. That are fundamentally different things. The variables a and b are not somehow magically linked by the first assignment, they just contain the same object. That's also the case in the second example, until you assign a new value to the b variable.
The difference is between simple types and objects.
Anything that's an object (like an array or a function) is passed by reference.
Anything that's a simple type (like a string or a number) is copied.
I always have a copyArray function handy so I can be sure I'm not creating a bunch of aliases to the same array.
I was reading a book called Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript, Point 4 Prefer Primitives to Object Wrappers and came across this sentence.
Getting and setting properties on primitives implicitly creates object
wrappers
Does this create an object wrapper?
"hello".someProperty = 17;
EDIT
If the above statement create an object then please explain this behaviour.
var test = "foo";
test.bar = "new prop";
test.bar //this prints undefined.
"hello".someProperty = 17;
The above statement does create an object wrapper, but it is disposed of as soon as its task is done.
var hello = 'Hello';
hello.someProperty = 17;
console.log(hello.someProperty);
This explains why trying to assign properties to a primitive doesn't work, but also doesn't throw an error. Assigning the property succeeds, but the property is set on a wrapper object which is immediately destroyed. So when you go to look up the property later, there is nothing there anymore.
Internally, this of primitive type is object.
String.prototype.thisType = function () {
return typeof this;
};
var hello = "hello";
console.log(typeof hello);
console.log(hello.thisType());
Read more Here
Yes, it creates an intermediate object, which is discarded after use. So the statement
"hello".someProperty = 17;
will internally be executed like this:
var temp = new String("hello"); // or any other variable name
temp.someProperty = 17;
So, now temp (or whatever named variable is created by JavaScript) will not be accessible because it is created and discarded immediately.
you have to create String Object by new Keyword.
var str = new String("My String");
//Here str is looks like
//String {"My String"}
str .xyz=5
str
//now String {"My String", xyz: 5}
I am really fixed with JS object related concepts. For ex:
Crockford says: Objects produced from object literals are linked to Object.prototype
Now on console when I type:
// input represented with >
> var a = {};
> console.log(Object.getPrototypeOf(a));
Object {} // <-- output
> console.log(a.prototype);
undefined
Crockford says:Function objects are linked to Function.prototype (which is itself linked to Object.prototype)
> function b(){};
> console.log(Object.getPrototypeOf(b));
function()
> console.log(b.prototype);
b{}
> console.log(b.prototype.prototype);
undefined
> console.log(Object.getPrototypeOf(b.prototype));
Object {}
When I do getPrototypeOf() I get the expected output, but when I try to use the prototype property I get undefined. Cant figure out the reason.
Also for line 5 return value is function(). Can some please explain does this say ? I expected an Object to be returned.
It would be great if someone please give me insight/good links/some class diagrams(as we have in java) to follow for understanding prototypal inheritance.
Okay. Here's the thing. There are some concepts in JS that seem really convoluted at the start, but are actually really straightforward. Let's have a look at a few of them.
1) function.prototype property
When you define a function, the JS engine creates an anonymous object and binds the two using property names prototype and constructor as follows:
function foo(){}
/* Performed by JS engine internally */
// foo.prototype = {};
// foo.prototype.constructor = foo;
Therefore, only functions have .prototype.
The .prototype is used only and only when the function is invoked using the new operator.
2) References
In JS, references can be used to pass along a variable, without creating a duplicate of it. Perhaps an example might help here:
var a = 1;
var b = { val: 1 };
var c = { val: 1 };
var x;
/*variable cloned*/
x = a;
x++;
console.log(a); // 1
console.log(x); // 2
/*variable refernced*/
x = b;
x.val++;
console.log(b); // { val: 2 }
console.log(x); // { val: 2 }
/*variable cloned*/
x = c.val;
x++;
console.log(c); // { val: 1 }
console.log(x); // 2
3) object.__proto__ property
Any object created by invoking a function with the new keyword, like var x = new foo();, will have a __proto__ property on it that is the object referenced by its constructor function's .prototype property. Re-assigning foo.prototype to somethings else will not affect objects that have already been created.
In other words,
function foo(){}
// foo.prototype = {};
// foo.prototype.constructor = foo;
var x = new foo();
console.log(x.__proto__ === foo.prototype); // true
Also, when you create an object like var x = {};, it is the exact same thing as:
var x = new Object();
Therefore, x.__proto__ is the object referenced by Object.protoype.
Conclusion
How does all this add up?
foo.prototype acts as a "blueprint" for the objects created using the function foo.
When we do create an object x = new foo(), JS engine stores a reference (link) to "the blueprint that was used to make x" as the __proto__ property.
When I do getPrototypeOf() I get the expected output, but when I try to use the prototype property I get undefined. Cant figure out the reason.
Object.getPrototypeOf(...) returns the __proto__ property, not prototype.
Also for line 5 return value is function(). Can some please explain does this say ? I expected an Object to be returned.
In JS, all data types have an associated "Wrapper" function.
Similar to how x = {} is the same as x = new Object(), doing function b(){} is the same as b = new Function()
since b was created invoking a function using new, it has a __proto__ property, that is the object referenecd by its constructor function's prototype. In this case, Function.prototype, which is also Function.
Still confused? I'd recommend having a good long read at http://www.javascripttutorial.net/
As a beginner, working with existing code, I've come across the following:
var foo = {};
which I believe is equivalent to:
var foo = new Object();
I was under the impression that any variable was automatically an Object, so what would be the purpose of specifically coding that, rather than just declaring an empty variable:
var foo;
I was under the impression that any variable was automatically an Object
That is a mistaken impression. If you declare a variable and do not assign it a value, it is initialised to undefined (as mention in the spec and described in detail), which is not an object (it's a primitive value):
var foo;
console.log(foo); // undefined
If you were to attempt to set a property of an undefined variable you would receive a TypeError:
var foo;
foo.example = "hello"; // TypeError: Cannot set property 'example' of undefined
However, if you assign an empty object to that variable, the above code will succeed:
var foo = {}; // Now refers to an empty object (equivalent to `new Object()`)
foo.example = "hello";
console.log(foo); // '{example:"hello"}'
I believe your understanding probably stems from the common misunderstanding that "everything in JavaScript is an object". This is not true. Many things in JavaScript are objects, but primitive values are not. For example:
var a = "hello"; // String primitive, not an object
var b = new String("hello"); // String instance, object
var c = 10; // Number primitive, not an object
var d = true; // Boolean primitive, not an object
var e; // Undefined value, not an object
var f = null; // Null value, not an object
James's answer is correct. In case he's throwing too much info too quickly (refer back to it later, if so), here's a quick summary.
You are correct in this: var foo = {} and var foo = new Object() are not only equivalent, the results are identical. Only use object literals. (ignore new Object(), new Array(), etc).
var foo; does nothing other than declare a variable. It is 'undefined' by default.
var foo = new Object() also gives the new object a prototype property which can be used to manipulate object inheritance and call standard object functions defined by javascript
see here for details on how you can manipulate the object.protype:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/prototype
I am curious as to what's going on here. As you can see, I have defined a constructor function called range to build new range objects. I've extended the range constructor through it's prototype, adding a simple includes method. I've created my new object and used the variable of p. When I attempt to use this method with my range objects, all is well and it works as expected. The problem is when I try to look at at p.prototype it tells me that it's type is undefined and p.prototype has no methods... Huh??
What's going on here?? How is p an object and p.prototype is not?
function range(from, to) {
this.from = from;
this.to = to;
}
range.prototype = {
includes: function(x) { return this.from <= x && x <= this.to; },
}
var p = new range(1, 4);
console.log(typeof p) //outputs object
console.log(typeof p.prototype) //outputs undefined
console.log(Object.getOwnPropertyNames(range.prototype)); //outputs includes
console.log(Object.getOwnPropertyNames(p.prototype)); //throws error, p.prototype is not an object
The problem is when I try to look at at p.prototype it tells me that it's type is undefined
That's correct. The objects created by your range constructor do not have a prototype property, but they do have an underlying prototype (which is drawn from the prototype property of the range function).
Let's look at what happens when you do new range():
The JavaScript engine creates a new, blank object.
The JavaScript engine assigns that object's underlying prototype (not prototype) to be the object referenced by range.prototype. (In the spec, this property — which is not directly accessible in code but see below — is called [[Proto]].)
The JavaScript engine calls range with this referring to the new object.
Assuming range doesn't return a different object (which it can do; this is a bit obscure), the result of new range is the new object created in step 1.
Later, when you use this.includes, this is what happens:
The engine looks at the actual object to see if it has an includes property.
Since it doesn't, the engine looks at [[Proto]] to see if it has one.
Since it does, it uses that one (if not, it would have looked at [[Proto]]'s [[Proto]] and so on).
The key things here are:
Objects have underlying prototypes, which are not accessible via any named property on the object itself. (In fact, it used to be we couldn't get to them at all. Now, in ES5, we have Object.getPrototypeOf.)
Objects created via new SomeFunctionName get their prototype from SomeFunctionName.prototype property, which is a perfectly normal property of the SomeFunctionName object (functions are first-class objects in JavaScript).
Side note: You're replacing the prototype of range with your code. In general, although it works, I would avoid that. Instead, augment the existing object referred to by range.prototype. (Add properties to it, rather than replacing it.) But that's not central to your question.
I think you wanted was:
range.prototype.includes = function(x) {
return this.from <= x && x <= this.to;
}
You redefined the prototype object, so the reference to the original one has disappeared. Try this way:
range.prototype.includes = function(x) {
return this.from <= x && x <= this.to;
}
Number.prototype.myRound = function (decimalPlaces) {
var multiplier = Math.pow(10, decimalPlaces);
return (Math.round(this * multiplier) / multiplier);
};