Multivariable Assignment in Javascript - javascript

Can someone explain why if I add a property to foo, somehow bar also inherits that property when I do this:
var foo = bar = {};
foo.hi = 'hi';
console.log(bar); //Object {hi: "hi"}
How does this work? I'm setting properties on foo, not bar. I realized I passed the object to bar and then bar to foo, but I must be missing something here.
Integer assignment works differently and more sense (to me anyhow):
var foo = bar = 5;
foo = 4;
console.log(bar); // 5

Objects are passed by reference in JavaScript. Strings and number literals are not. In your code foo === bar, is the same object. You can simply declare the variables separately:
// Two different object instances
var foo = {};
var baz = {};

by doing foo = bar = {};, foo and bar are pointers to same object. so when you do:
foo.hi = 'hi';
It sets bar.hi also, because foo and bar point to the same object. To make it different, you should do:
var foo = {}, bar = {};
foo.hi = 'hi';

Related

Is there a way to get prototype of an object that was initialized with {}

In JavaScript, if I initialize an object like so:
var foo = {};
is there a way to get the prototype of that object? The prototype quite well may be undefined. But actually, what I really want is just the defined fields and functions/methods that foo may have:
var foo = {
field1: '',
method1: function(){}
};
I am trying to create a classical inheritance system, but Object.create() seems to want arguments that represent prototypes and nothing else.
In other words, I want var bar = {} to inherit from foo. But both bar and foo are objects initialized with {}.
How can I add the methods from one object to another with or without dealing with prototypes?
When you instantiate an object with new ({} is the same as new Object()), the prototype becomes its properties. Here is a simple example of prototypal inheritance :
// Foo constructor
var Foo = function() {};
Foo.prototype = {
field1: '',
method1: function(){}
};
// bar constructor
var Bar = function(){
Foo.call(this); // calling the parent ctor
};
Bar.prototype = Object.create(Foo.prototype); // inherit from Foo
Bar.prototype.constructor = Bar; // set the ctor just in case it was set by Foo
var bar_instance = new Bar();
bar_instance.method1(); // <-- it works!
I would suggest you go read the code for Google's Closure Library, PrototypeJS and Mootools Class system to inspire you in your endeavor.
Hope this helps.
You may use Object.create():
var foo = {
field1: '',
method1: function(){}
};
var bar = Object.create(foo);
You may try this:
http://jsfiddle.net/kc0Lshrp/1/
var foo = {};
foo.constructor.prototype.field1='FOO';
foo.constructor.prototype.method1=function(){ alert(this.field1)};
var bar={field1:'BAR'};
bar.prototype=Object.create(foo);
bar.method1();

Is there a difference in Obj['var'] and Obj.prototype.var?

I am not quite sure how to state the question in word terms as I do not know what to call this -> Obj['var] = something.
I believe the title sums it up, is there any difference in declaring a variable or function of an object in those two different manners, or are they the same, different ways of doing the same thing.
EDIT:
An Example of my code:
Sorry for the confusing variable names, watch out for the capital characters :/
buttons = document.getElementsByClassName('button');
Buttons = new Button_Objs();
for (i = 0 ; i < buttons.length ; i++){
button = buttons[i];
Buttons['button' + i] = new Button(button);
}
var Button = function(elem){
this.buttonType = elem.getAttribute('button-type');
if (this.buttonType = 'safety'){
constructSafetyButton(elem, this);
}
}
function constructSafetyButton(elem, button){
button['setState'] = function(state){//do something}
}
I get yelled at by browsers when trying to use button.prototype.setState = func...
Obj['var'] = ... (and Obj.var = ... for that matter) assigns a property to the object which Obj is referring to.
Example:
var obj = {};
obj['foo'] = 'bar';
// or obj.foo = 'bar';
console.log(obj.foo); // shows 'bar'
Obj.prototype.var = ... will most likely throw an error, unless Obj is a function. Functions have a special property called prototype from which all new instances inherit when the function is called as constructor function, i.e. called with the new keyword.
Example:
function Foo() {}
Foo.prototype.bar = 'baz';
var foo = new Foo();
console.log(foo.bar); // shows 'baz'
Since functions themselves are objects too, you can assign properties to them as well
Foo.someProp = 'someVal';
but this does not influence instances created by Foo at all. New instances only inherit from Foo.prototype:
console.log(foo.someProp); // shows undefined
While both statements assign properties to objects (in this regard they are "the same"), the outcome is entirely different.
If you want to learn more about prototypal inheritance in JavaScript, have a look at MDN - Details of the Object Model and MDN - Inheritance and the prototype chain.
Based on the question in the title, no they are different.
Obj['var'] = something
is equivalent to this:
Obj.var = something;
Which is entirely different from setting a value on the prototype property of some object.
Obj.prototype.var = somthing

Referring to previously defined properties within an object literal

When using object constructors, properties can be directly assigned to the value of previously defined properties:
var foo = new (function() {
this.bar = 5;
this.baz = this.bar;
})();
alert(foo.baz) // 5
I would like to refer to a previously defined property within an OBJECT LITERAL:
var foo = {
bar : 5,
baz : bar
}
alert (foo.baz) // I want 5, but evaluates to undefined
I know that I could do this:
var foo = {
bar : 5,
baz : function() {
alert(this.bar); // 5
}
But I want to assign baz directly to a value rather than a function. Any ideas?
No, you won't be able to use any properties of the object literal before it has been created. Your closest option is probably to use a temporary variable like so:
var tmp = 5,
foo = {
bar : tmp,
baz : tmp
}
If you are free to use ECMAScript 5 features, you could write a getter function for the baz property that instead returns the value of bar:
var yourObject = {
bar: 5
};
Object.defineProperty(yourObject, 'baz', {
get: function () { return yourObject.bar; }
});
You can also just build a literal by parts:
var foo = {bar:5};
foo.baz = foo.bar;
If you need to fit this inside an expression (instead of through multiple statements) you can try abusing the comma operator or you can make a helper function:
(Warning: untested code)
function make_fancy_object(base_object, copies_to_make){
var i, copy_from, copy_to_list;
for(copy_from in copies_to_make){
if(copies_to_make.hasOwnProperty(copy_from)){
copy_to_list = copies_to_make[copy_from];
for(var i=0; i<copy_to_list.length; i++){
base_object[copy_to_list[i]] = base_object[copy_from];
}
}
}
}
var foo = make_fancy_object(
{bar: 5},
{bar: ["baz", "biv"]}
);
//foo.baz and foo.biv should be 5 now as well.

What Javascript types can have properties?

Given var x, what is the best way to determine if x can have properties? Can I just do
if(x instanceof Object)
Is that sufficient to ensure that x can have properties or do I need to check for anything else? I know primitives can't have properties but is there anything else? I've been going through checking various types:
var a = false;
a.foo = "bar";
console.log(a["foo"]);
// Logs undefined
var b = "b";
b.foo = "bar";
console.log(b["foo"]);
// Logs undefined
var c = new Array(1,2,3);
c.foo = "bar";
console.log(c["foo"]);
// Logs bar
var d = new Object();
d.foo = "bar";
console.log(d["foo"]);
// Logs bar
var e = new RegExp("");
e.foo = "foo";
console.log(e["bar"]);
// Logs bar
var f = new Number(1);
f.foo = "bar";
console.log(f["foo"]);
// Logs bar
var g = function(){};
g.foo = "bar";
console.log(g["foo"]);
// Logs bar
etc..
Yes, that is sufficient. Note: String can also accept properties, which you are not checking for:
var a = new String("hello");
a.foo = "bar";
But since String instanceof Object == true you should be fine.
For fun, try this (it works, since /x/ instanceof Object == true):
var x = /hello/;
x.foo = "bar";
Another note: your instanceof check will catch this, but I want you to be aware that while normal a javascript function is an Object, a closure (function() { })() is not necessarily an Object, but it might be depending on the value it returns.
Hope that helps.
-tjw
You need to create a JavaScript object first like so:
<script>
var foo = {};
foo.bar = 'test';
console.log(foo.bar);
</script>
Vars a and b are just plain ole variables. The var foo = {}; bit is similar to a builtin object called foo and you created an instance like var bar = new foo();

Javascript Function-Pointer Assignment

Consider this javascript code:
var bar = function () { alert("A"); }
var foo = bar;
bar = function () { alert("B"); };
foo();
When running this code I get "A". Is this behavior a part of javascript specification and can I rely on it?
In other examples, nothing was passed by value; everything was passed by reference.
bar and foo are BOTH pointers
All vars/handles to NON primitive objects in javascript are pointers; pointers ARE native to javascript, they are the default.
var bar = function () { alert("A"); } //bar is a pointer to function1
var foo = bar; //pointer copied; foo is now also a pointer to function1
bar = function () { alert("B"); }; //bar points to function2
foo(); //foo is still a pointer to function1
You will run into hidden errors and bugs if you think they are copies. Especially so if you work with complex objects. For example
function person(name){this.name = name}
var john = new person("john")
var backup = john
backup.name //john
john.name = "jack"
backup.name //jack, NOT john
To really COPY a non-primitive in javascript takes more work than just a = b.
For example:
function person(name){ this.name = name}
var john = new person("john")
var backup = new Object()
backup = JSON.parse(JSON.stringify(john))
backup.__proto__ = john.__proto__ //useful in some cases
john.name = "jack"
backup.name //john
Yes that is expected and by design.
Your question is basically: does foo reference bar as a pointer or reference would in another language?
The answer is no: the value of bar at the time of assignment is assigned to foo.
I'm a bit late here but I thought I'd give an answer anyways and flesh something out.
It's best not to think in terms of pointers and memory references when discussing the internals of JavaScript (or ECMAScript) when dealing with the specifications. Variables are environment records internally and are stored and referenced by name, not memory address. What your assignment statement is doing, internally and by design, is looking up the environment record name (either "foo" or "bar") and assigning the value to that record.
So,
var bar = function () { alert("A"); }
is assigning the environment record "bar" the value (anonymous function).
var foo = bar;
internally calls GetValue("bar") which retrieves the value associated with the record "bar" and then associates that value with the record "foo". Hence, afterwards the original value of bar can still be used as it's now associated with foo.
Because JavaScript references by string and not memory address is precisely why you can do things like this:
someObject["someProperty"]
which is looking up the value based on the property name.
You are assigning the value of an anonymous function to a variable not a pointer.
If you want to play with pointers, you can use objects that are passed by reference, not copy.
Here are some examples:
"obj2" is a reference of "obj1", you change "obj2", and "obj1" is changed. It will alert false:
var obj1 = {prop:true},
obj2 = obj1;
obj2.prop = false;
alert(obj1.prop);
"prop" points to a property that is not an object, "prop" is not a pointer to this object but a copy. If you change "prop", "obj1" is not changed. It will alert true:
var obj1 = {prop:true},
prop = obj1.prop;
prop = false;
alert(obj1.prop);
"obj2" is a reference to the "subObj" property of "obj1". if "obj2" is changed, "obj1" is changed. It will alert false:
var obj1 = {subObj:{prop:true}},
obj2 = obj1.subObj;
obj2.prop = false;
alert(obj1.subObj.prop);
Yes, there's nothing special about the fact that the variables are referring to functions, there's no aliasing involved.
var bar = 1;
var foo = bar;
bar = "something entirely different";
// foo is still 1
Yes, this is the correct behavior.
//create variable bar and assign a function to it
var bar = function () { alert("A"); }
//assign value of bar to the newly created variable foo
var foo = bar;
//assign a new function to the variable bar
//since foo and bar are not pointers, value of foo doesn't change
bar = function () { alert("B"); };
//call the function stored in foo
foo();
This is assigning a variable to an unnamed function, not a pointer to a function
Yes, you've created a pointer to the original "A" function. When you reassign bar, you're reassigning it, but you're still leaving any references to the old function alone.
So to answer your question, yes, you can rely on it.
Those are not function pointers (and there are no pointers in JS natively). Functions in JS can be anonymous and are first class objects. Hence
function () { alert("A"); }
creates an anonymous function that alerts "A" on execution;
var bar = function () { alert("A"); };
assign that function to bar;
var foo = bar;
assign foo to bar, which is the function "A".
bar = function () { alert("B"); };
rebind bar to an anonymous function "B". This won't affect foo or the other function "A".
foo();
Call the function stored in foo, which is the function "A".
Actually in languages where there are function points e.g. C it won't affect foo either. I don't know where you get the idea of getting "B" on reassignment.
void A(void) { printf("A\n"); }
void B(void) { printf("B\n"); }
typedef void(*fptr_t)(void);
fptr_t foo = A;
fptr_t bar = foo;
bar = B;
foo(); // should print "A"
I would just like to add this also works for pre-defined named functions as well:
function myfunc() { alert("A"); }
var bar = myfunc;
var foo = bar;
bar = function () { alert("B"); };
foo();
This will do the same thing, indicating that function names act like array names (pointers).
For each FunctionDeclaration f in code, in source text order do:
Let fn be the Identifier in FunctionDeclaration f.
Let fo be the result of instantiating FunctionDeclaration f as described in Clause 13.
Let funcAlreadyDeclared be the result of calling env’s HasBinding concrete method passing fn as the argument.
If funcAlreadyDeclared is false, call env’s CreateMutableBinding concrete method passing fn and configurableBindings as the arguments.
References
ECMAScript-5: Section 10.5

Categories

Resources