If I create multiple objects using Object.create() on an object literal, I get multiple unique objects that don't share property values. However, when I use Object.create() on an object returned from a module, it looks like they share the same reference? Why is that?
#1 Module:
var objModule = (function () {
var name = "module 1";
var setName = function( strName ) {
name = strName;
};
var getName = function() {
return name;
};
return {
setName: setName,
getName: getName
};
}());
var objModule2 = Object.create(objModule);
objModule2.setName("module 2");
console.log(objModule.getName()); // WRONG prints "module 2"
console.log(objModule2.getName()); // prints "module 2"
#2 Literal:
var objLiteral = {
name : "literal 1"
};
var objLiteral2 = Object.create(objLiteral);
objLiteral2.name = "literal 2";
console.log(objLiteral.name); // prints "literal 1"
console.log(objLiteral2.name); // prints "literal 2"
EDIT
#3 Module "Constructor":
var module = function () {
var name = "module 1";
var setName = function( strName ) {
name = strName;
};
var getName = function() {
return name;
};
return {
setName: setName,
getName: getName
};
};
var objModule1 = module();
var objModule2 = module();
objModule2.setName("module 2");
console.log(objModule1.getName()); // prints "module 1"
console.log(objModule2.getName()); // prints "module 2"
EDIT
If I use the module like a constructor (as suggested by #Matt Browne) and create 2 objects, the result is like using an object literal. What I'd like to understand is why does module example #1 behave differently than module example #3?
EDIT 2
As #ben336 explained, the code:
var objModule2 = Object.create(objModule);
will set the objModule2's prototype to objModule. That doesn't happen in example #3, so those two objects don't share the same closure property.
Example 1
The first argument of Object.create specifies the prototype object for the new object being created. Since in your first example you're setting your existing object to be the prototype of your new object, when you call the functions they're modifying the variable you've stored in a closure, which is then accessed by both your existing object and the new one.
The 2 key things to understand here are:
This code
var objModule = function () {
var name = "module 1";
var setName = function( strName ) {
name = strName;
};
var getName = function() {
return name;
};
return {
setName: setName,
getName: getName
};
}();
creates a closure with the functions getName and setName holding access to the name variable.
those functions are properties of objModule, and when you call Object.create you set objModule to be the prototype of objModule2, and it gains access to those functions as well.
Since the 2 objects share those functions, and they have access to the closure created by the module rather than storing the name property locally on either object, when you call the set function with one object, it will update the closure and thus update both objects.
Example 2
In the second example you're also setting the object to be the prototype of the new object, but you're declaring a property on the local object which overrides the property on the prototype.
objModule2.setName refers to the same function as objModule.setName, but with a different this. (Object.create doesn't copy anything)
Calling it will set the same local variable.
objLiteral2.name = "literal 2" creates a new property on objLiteral2, which shadows the inherited objLiteral.name.
I think what you're going for here would be better accomplished by removing the parentheses () at the end of the objModule function, and renaming it to something that makes it clear it's a constructor, i.e. do this instead:
var makeObjModule = function() {
var name = "module 1";
var setName = function( strName ) {
name = strName;
};
var getName = function() {
return name;
};
return {
setName: setName,
getName: getName
};
}; //removed parentheses here
(Personally I'd use the function objModule() syntax too while I was at it, but that's a separate point and a matter of personal preference.)
Then you can create your instances:
var objModule = makeObjModule();
var objModule2 = makeObjModule();
The Object.create approach is of course a valid way of going about this as well; for more details on making that work, see #ben336's answer.
Personally I find Object.create to be more useful when doing inheritance than when doing simple construction like this. (Some people also prefer it to using the new keyword when using prototypal inheritance, but since you're using the module pattern I think it's easier to just use a "maker"/constructor function as I showed above.)
Related
i'm new to JS and got the following problem:
Why is this not working / what is this code doing?
var Test = {};
Test.prop = "test property";
Test.Class1 = function () {
}
Test.Class1.prototype = {
m1: function() {
console.log(this.prop);
}
}
Test.Class1.m1();
My understanding of this code would be:
creating a new object called Test
adding the property prop to Test
creating a new object called Class1 in Test
adding a method m1 to Class1
calling the m1 method of Class1 in Test
In JavaScript, even the prototype property of a function is an object. Prior to creating an object whose prototype is the one you've defined, Test1.Class1.prototype is just a regular object. Basically it works the same way as the following code snippet:
var Test1 = { prototype { m1: function() {} } };
// You're trying to call an undefined function!
Test.m1();
// This is fine
Test1.prototype.m1();
In the other hand, when you use the new operator, you're creating a new object whose prototype is the one set to the constructor function. And here starts the magic:
var Test1 = function() {};
Test1.prototype = {
doStuff: function() {}
};
var object1 = new Test1();
// This works!
object1.doStuff();
When you access a property, JavaScript's runtimes inspect the object to find out if there's a function called doStuff, otherwise it looks for it on the object's prototype, otherwise it looks on the prototype of the prototype and so on...
Actually new operator is a syntactic sugar. ECMA-Script 5 introduced Object.create which makes everything more clear:
var Test1 = {
doStuff: function() {
}
};
// The first parameter of Object.create is
// the object that's going to be the prototype of
// Test1 object!
var object1 = Object.create(Test1);
// This works too!
object1.doStuff();
Probably you should check this other Q&A: How does JavaScript .prototype work?
You need to create an instance of the prototype before you're able to use its methods:
var instance = new Test.Class1();
console.log(instance.m1());
Even as such, Test.prop is not part of the instance, and will not be accessible to m1
Edit: Here's a working example:
var test = function() {
this.prop = "A property";
}
test.prototype.m1 = function() {
console.log(this.prop);
}
var instance = new test();
console.log(instance.m1());
prototype chaining only works for instances created with the new operator.
Otherwise you will have to explicitly call prototype to access the method.
let testClass = new Test.Class1();
testClass.m1();
Also since you are trying to access the prop property.
Test.Class1.prototype = {
m1: function() {
console.log(this.prop);
}
}
The call site is Test.Class1, the prop should be part of Test.Class1 and not on Test
I changed up the names of things, but this should work.
var Person = function(){
this.message = "Hello, world!";
};
Person.prototype = Object.create(Object.prototype);
Person.prototype.constructor = Person;
Person.prototype.greet = function(){
console.log(this.message);
alert(this.message);
};
var tom = new Person();
tom.greet();
I have a variable at some point of a JavaScript code. Now I would like to get the name of the function (aka scope) where that variable was declared. So for example if that variable is a field of an oject, I would like to get the name of the object's type.
Consider the following code:
function MyClass() {
this.name = "MyName";
this.age = 20;
}
var myVariable = new window.MyClass();
alert(getDeclaringScope(myVariable)) // should alert 'window'
alert(getDeclaringScope(myVariable.name)) // should alert 'MyClass
Is there any way to implement the getDeclaringScope function?
UPDATE
I wanted to use some technic like this to access to access a kind of "static" variable where meta information is stored for knockoutjs observable. A farly simplified example:
var META = {};
META["MyClass"] = {};
META["MyClass"]["MyArray"] = { ElementType: "MyOtherClass" };
function MyClass() {
this.MyArray = ko.observableArray();
}
function MyOtherClass() {
this.name = "a";
}
ko.observableArray.fn.addFromPlainObjects = function(plainItems) {
var elemType = .... here I wanted to get "MyOtherClass" from the META global variable
// create MyOtherClass and map the plain items to it... etc.
}
No.
The object has a reference to its constructor, but the constructor could be referenced from many objects, not just window in this case. It could be accessed directly with a variable (as opposed to a property):
var MyClass = window.MyClass;
var foo = new MyClass();
You can create a back-reference explicitly in your object model, as constructor functions are objects.
window.MyClass.backref = window;
Though this is most likely not what you want. I suspect you have a misunderstanding regarding what the scope of a variable is; a variable scope has nothing to do with object properties. As such, there is no notion of "declaring scope" that represents the object and object property from which a variable reference was retrieved, as you seem to conceptualize it.
You can use instanceof and constructor:
Eg.
myVariable instanceof MyClass; //true
myVariable.constructor;
// returns
function MyClass() {
this.name = "MyName";
this.age = 20;
}
Check: instanceof and constructor
When trying to test prototype functionality, I got this odd result:
Here is my first test:
<script>
function Hello() {
}
var a = new Hello();
Hello.prototype.name = "Fred";
alert(a.name);
</script>
And, here's the second one:
<script>
function Hello() {
}
var a = new Hello();
Hello.prototype = {
name : "Fred",
}
alert(a.name);
</script>
I can't understand why the first will return a alert with "Fred" and the second is "undefined" though these mean the same thing?
Could you help me with it?
Thank you.
When you define a function in JavaScript, the interpreter makes a special prototype property available on the function, which points to an object, in case you use that function as a constructor. The [[Prototype]] internal property points to this object when you create a new object using the constructor.
When you replace the prototype property with a new one, you are replacing that reference, and if you do it after you instantiate an object, you will find the prototype object appears to be stale (that object's [[Prototype]] is pointing to the original object that prototype pointed to).
Solutions
Only assign new properties directly on the prototype property.
var constructor = function() { };
constructor.prototype.someMethod = function() { };
Use an extend type function to extend the existing prototype property with your new object (in this example, I used Underscore's extend() function).
var constructor = function() { };
_.extend(constructor.prototype, { someMethod: function() { } });
Make sure after the constructor, assigning the prototype property is the very next step in your program (generally not recommended).
var constructor = function() { };
constructor.prototype = { someMethod: function() { } };
Your ordering is messed up. You need assign the object to the prototype before using the new operator:
function Hello() {
}
Hello.prototype = {
name : "Fred",
}
var a = new Hello();
alert(a.name);
Demo.
The two code snippets are not actually equal.
In the first script you only override Hello.prototype.name, while in the second script you override the whole content of Hello.prototype.
Whats the difference between (via prototypes)
var Todo = {};
Todo.prototype.name = "...";
Todo.prototype.hello = function() { ... }
Vs (variables & functions "outside" object)
var Todo = {}
Todo.name = "..."
Todo.hello = function() { ... }
Or even the below : variables & functions in object
var Todo = {
name: "...",
hello = function() { ... }
}
Think it like
A property or a function declared with prototype is an instance member of Todo.
A property or a function declared without prototype is a static member of Todo.
The first one doesn't make sense as you are dealing with an object instance (({}) instanceof Object === true), it won't have a prototype property (Object does).
You may be inquiring about the difference between these two patterns...
var ObjA = function() {
this.method = function() {};
};
var ObjB = function() {};
ObjB.prototype.method = function() {};
jsFiddle.
The former will use more memory when instantiated - each object has their own method. The latter won't each have their own method, the method lives on the prototype object, which is the next in command on the prototype chain when its attempted to be accessed on the parent.
Todo.prototype is also an object, so the difference is if you declare property with prototype, then every object who created from this prototype will have the property, otherwise, the property is only for Todo the object self.
A significant difference between method #1 and #2 (which is almost identical to example #3) is on new keyword that you need to use if you extend your function via prototype, e.g.
var Todo1 = function() {};
Todo1.prototype.name = "Foobar";
var Todo2 = {name: "Foobar" }
var a = Todo1;
console.log(a.name); // no property retrieved
var b = Todo2;
console.log(b.name); // Foobar
var c = new Todo1;
console.log(c.name); // Foobar
When we make an object like this
function myObject(){
Properties and methods here----
};
We write “function” keyword before name of object is it necessary? All objects are functions in real? Can we not write direct object name like this?
myObject(){
Properties and methods here----
};
No, not all objects are functions. (All functions are objects, though.)
Here, obj isn't a function:
var obj = {
foo: "bar"
};
Nor dt here:
var dt = new Date();
The function keyword is necessary in order to say "what follows is a function declaration or function expression." It's just part of the basic syntax of JavaScript.
in the first case, the function can be used as the constructor for an object. So you can have:
function Person(name) {
this.name = name
}
Person.prototype = {
// methods can go in here
}
person1 = new Person("bob");
alert(person1.name) // alerts "bob"
It is also true that you can use a function as an object. For example:
function myObject() {
return myObject.test;
}
myObject.test = "bob";
alert(myObject()) // would alert "bob"
but all objects are not functions.
var someObject = {
name: "bob",
moody: "sad"
}
alert(someObject.name); // alerts "bob"
try {
someObject();
} catch (er) {
alert(er); // alerts "TypeError: object is not a function"
}
I'd suggest you take a look at https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function
One reason is obviously disambiguity;
function foo()
{
alert("cake")
}
foo()
{
alert("burb");
}
foo();
alerts cake, burb, cake as the 2nd foo() {...} is just a regular function call followed by a regular compound statement enclosed in {}.
function declares a function. Because of the way JavaScript works, a function can be used as a class, to make objects.
But if you really just want an object, use squiggly braces, like this:
var myObject = {
x : 30, // a property
getX : function() { // a method
return this.x;
}
}
But your understanding of JavaScript needs a lot of work: read a few books about it.
In Javascript we can create objects in various ways:
1) Literals
let employee = {"name": "tyrion","age":34}
2) Constructor functions(functions having this)
function employee(name, age) {
this.name = name;
this.age = age;
}
let specificEmployee = new employee("tyrion",34);
Constructor function always need to have a new operator to create a object
3) Using Object constructor
let employee = Object.create(null);
employee.name = "tyrion";
employee.age = 34
In javascript every thing other than primitive type is an instance inherited from Object constructor.
No it's not required. You can also have:
var myObject = {
Prop1: "Value1",
Prop2: "Value2",
Method1: function() {
alert("hello");
}
};
Live test case: http://jsfiddle.net/rKunx/
You can write:
myObject = {
Properties and methods here----
}
If you want to avoid the function keyword as much as possible in Java you could use classes:
class Person {
name;
setName(name) {
this.name = name;
this.doStuff();
}
doStuff() {
//...
}
}
The obvious disadvantage to using classes though is that any property or function has to be accessed with this. An advantage of this keyword is that it is clear to know that you are referring to a class property or function and not a local one within the function.
Some people use a var or let in the top:
setName(name) {
let t = this;
t.name = name;
t.doStuff();
}
Still, many prefer to use a function to define some kind of class instead since that does not need this in order to reach the properties which are just variables in the scope of the function. Put inside a module you will still be able to contain these in much the same way you would a class.
If I could make a wish for the future of Javascript it would be to find some way that this is implicitly referring to the class in some way to have a smaller code style with less tokens and easier readability.