When I run the following...
var obj = {
array: ['1.mp3', '2.mp3', '3.mp3'],
audio: new Audio(this.array[0])
};
...I get an error saying that it cannot read property '0' of undefined. However, when I run the following...
var obj = {
array: ['1.mp3', '2.mp3', '3.mp3'],
};
var audio = new Audio(this.obj.array[0]);
...everything runs smoothly. How would I fix the first example? Am I doing something wrong with this?
How would I fix the first example? Am I doing something wrong with this?
You can't. The object is not yet created, so you can't refer to the property, using this
You can however do this
var obj = {
array: ['1.mp3', '2.mp3', '3.mp3'],
}; // object now created
obj.audio = new Audio(this.obj.array[0]); // set the property.
Note that you can refer to this to refer to the obj inside functions, but not outside them.
var obj = {
prop: (console.log(this), "Some value") // most probably Window but never obj
func: function(){
console.log(this); // obj
}
}
The problem is using this inside of a constructor: it's not referring to obj, it's referring to the new Audio object. You won't be able to reference it using this from inside the object like that.
Another way to do the same thing would be as follows:
var refArray = ['1.mp3', '2.mp3', '3.mp3'];
var myObj = {
array: ['1.mp3', '2.mp3', '3.mp3'],
audio: new Audio(this.obj.array[0]);
};
This does the same thing as stated in other answers, but allows you to add the audio object (as a property to the myObj) while you are defining the myObj variable.
Related
var x = {
name: "japan",
age: 20
}
x.prototype.mad = function() {
alert("USA");
};
x.mad();
The above code does not work.
object literals cannot be extended? or x.mad() not the right way to call.
You can't do it this way. To be able to define object methods and properties using it's prototype you have to define your object type as a constructor function and then create an instance of it with new operator.
function MyObj() {}
MyObj.prototype.foo = function() {
// ...
}
var myObj = new MyObj();
myObj.foo()
If you want to keep using object literals, the only way to attach behaviour to your object is to create its property as anonymous function like so
var myObj = {
foo: function() {
// ...
}
}
myObj.foo();
The latter way is the quickest. The first is the way to share behaviour between mutiple objects of the same type, because they will share the same prototype. The latter way creates an instance of a function foo for every object you create.
Drop the prototype.
Replace:
x.prototype.mad = function() {
With:
x.mad = function() {
This simply adds a mad property to the object.
You dont have .prototype available on anything but function object. So your following code itself fails with error TypeError: Cannot set property 'mad' of undefined
x.prototype.mad = function() {
alert("USA");
};
If you need to use prototype and extension, you need to use function object and new keyword. If you just want to add property to your object. Assign it directly on the object like following.
x.mad = function() {
alert("USA");
}
x.constructor.prototype.mad = function() {
alert("USA");
};
x.mad();
This also works, by the way:
Object.prototype.mad = function() {
alert("USA");
}
var x = {
name: "japan",
age: 20
}
x.mad();
But then, the mad function will be part of any object what so ever,
literals, "class" instances, and also arrays (they have typeof === "object").
So - you'll probably never want to use it this way. I think it's worth mentioning so I added this answer.
I have a constructor and i want to initialize an array inside the object to be created. This array is supposed to contain a couple of objects.
function Cluster3DObject(name){
this.name = name;
this.array = [];
}
Cluster3DObject.prototype.add = function(obj) {
this.array.push(this.obj);
};
Here i define the "class" and i have added one method "add" and it is supposed to push an object into this.array..
var cluster = new Cluster3DObject("clster");
var testObj = new THREE.CSS3DObject(testDiv);
var testVector = new THREE.Vector3();
cluster.add(testObj);
When i call the cluster.add method i get the "undefined is not a function error" but i can't seem to find out what i'm doing wrong?
i am new to using constructors..
It's not this.obj, just obj
Cluster3DObject.prototype.add = function(obj) {
this.array.push(obj);
};
otherwise it seems fine, but that wouldn't really produce a "undefined is not a function error", it would just push undefined, so the error probably comes from trying to use the array filled with undefined values ?
FIDDLE
For better code structure, I want to use a javascript object holding all properties instead of using multiple vars:
// 1. WAY
// This returns an error, as _inp cannot be accessed by input_value
// Uncaught TypeError: Cannot read property 'value' of undefined
var ref = {
_inp: input.target,
input_value: _inp.value,
....
};
// 2. WAY
// When using this, it works
var ref = {
_inp: input.target,
input_value: input.target.value,
....
};
// 3. WAY
// This obviously works, too.
var
_inp = input.target,
input_value = _inp.value,
My Question is, why does 3. Way works and 1.Way doesnt?
In example 1, _inp will be a property of an object. It isn't a variable. You can only access it from a reference to the object (and it won't be a property of the object until the object exists, which will be after the object literal has been evaluated, see also Self-references in object literal declarations).
Because _inp will only be filled in with the input.target value after passing through the entire var ref = { ... }; statement. This means that when you try to use it, it doesn't exist yet.
The 1st way don't work because you refers to "_inp" which is not an existing var. and the ref object is not fully created (that's why input_value: this._inp.value won't work either)
To create objects and assigning values to its properties, you can use a function (I keep most of your code):
var ref = {
_inp: input.target,
input_value: null,
init: function()
{
this.input_value = this._inp.value;
}
};
ref.init();
console.log(ref.input_value); // will contains the same as input.target.value
but usually, people create objects with all property with default values, and pass an argument to their init function:
var ref = {
_inp: null,
input_value: null,
init: function(input)
{
if (input)
{
this._inp = input.target;
this.input_value = input.target.value;
}
}
};
var input = {target:{value:"foo"}};
ref.init(input);
I'm working with a data object lit, then trying to create a new object that changes properties in the data property just for that instance, here's some test code from jsbin
data = {
innerData : 1
}
-------------
'This works :-)'
construct = function(d){
this.data = Object.create(d);
};
construct.prototype.c = function(n){
this.data.innerData = n;
};
construct.prototype.d = function(){
console.log(this.data.innerData)
};
--------------
'This does not :-{'
construct = {
data : Object.create(data),
changeData : function(n){
this.data.innerData = n;
},
showData:function(){
console.log(this.data.innerData)
}
}
--------------
newInst = Object.create(construct);
newInst.changeData(5);
newInst.showData();
newInst2 = Object.create(construct);
newInst2showData();
when I run it using the constructor/prototype functions it works and the console outputs 5,2
when I run it using the object literal the console outputs 5,5 I guess when I create the first instance it changes the actual data object and not the data property of the instance of the construct object.
If someone could explain in depth why this happens that would be much help as I've not been working with OOJS for that long
UPDATE:
so I had a little go at merging what I found useful from the answers and I've come up with this....
data = {
innerData : 1
}
function construct(d){
return {
data : Object.create(d),
changeData : function(n){
this.data.innerData = n;
},
showData : function(){
console.log(this.data.innerData)
}
}
}
build = function(){
return(new construct(data));
}
newInst = build();
newInst.changeData(5);
newInst.showData();
newInst2 = build();
newInst2.showData();
Given what we know about the inheritance, what does the following actually do
this.data.innerData = n;
where this is the result of Object.create(construct)?
this does not have own property data, so look up in the inherited properties.
Okay we found a data === Object.getPrototypeOf(this).data, call it d
Next set innerData of d to n
So what the actual result has ended up is the innerData property has been set on the reference from the prototype, and not a new Object.
Why has this happened? Because if you have o = {} and try to do o.foo.bar, you get a TypeError: Cannot read property 'bar' of undefined, and therefore for it to not throw an error, it has to be accessing a defined Object.
var proto = {foo: {bar: 'fizz'}},
obj = Object.create(proto);
obj.foo.bar = 'buzz';
proto.foo.bar; // "buzz" (i.e. NOT "fizz" anymore)
// and
obj.foo === Object.getPrototypeOf(obj).foo; // true
In your second example, there is only ever one data object. That object lives inside construct and is available to all the subsequent objects on the prototype chain.
In your first example, you make a new data object every time a new instance is created. So each object gets its own copy of data.
Try this, for the first example:
console.log(newInst.data === newInst2.data); // should be false
and for the second example:
console.log(newInst.data === newInst2.data); // should be true
The second piece of code works just fine:
construct.changeData(2);
construct.showData(); // 2
The only difference is that in the above example construct is not a constructor, so there will be only a single instance of construct.data as opposed to the first approach; calling Object.create() on it will create a new object but will keep the same .data reference as the first.
This looks like an attempt to create a factory function instead of a constructor function. Since Object.create is now widespread, and shimmable for these purposes where not available, this has become perhaps the best default, although there are plenty of constructor functions still around.
Some of the other answers explain what went wrong with your attempt. Here's how you might do it so that it works as expected:
var factory = (function() {
var clone = function(obj) {return JSON.parse(JSON.stringify(obj));};
var data = {
innerData : 1
};
var proto = {
changeData : function(n){
this.data.innerData = n;
},
showData:function(){
console.log(this.data.innerData)
}
};
return function() {
var obj = Object.create(proto);
obj.data = clone(data);
return obj;
}
}());
But it looks as though your innerData might have been an experiment to try to get these things working. It it's not necessary, this would be cleaner:
var factory = (function() {
var proto = {
data: 1,
changeData : function(n){
this.data = n;
},
showData:function(){
console.log(this.data)
}
};
return function() {
return Object.create(proto);
}
}());
I am new to "object-oriented" JavaScript. Currently, I have an object that I need to pass across pages. My object is defined as follows:
function MyObject() { this.init(); }
MyObject.prototype = {
property1: "",
property2: "",
init: function () {
this.property1 = "First";
this.property2 = "Second";
},
test: function() {
alert("Executing test!");
}
}
On Page 1 of my application, I am creating an instance of MyObject. I am then serializing the object and storing it in local storage. I am doing this as shown here:
var mo = new MyObject();
mo.test(); // This works
window.localStorage.setItem("myObject", JSON.stringify(mo));
Now, on Page 2, I need get that object and work with it. To retrieve it, I am using the following:
var mo = window.localStorage.getItem("myObject");
mo = JSON.parse(mo);
alert(mo.property1); // This shows "First" as expected.
mo.test(); // This does not work. In fact, I get a "TypeError" that says "undefined method" in the consol window.
Based on the outputs, it looks like when I serialized the object, somehow the functions get dropped. I can still see the properties. But I can't interact with any of my functions. What am I doing wrong?
JSON doesn't serialize functions.
Take a look at the second paragraph here.
If you need to preserve such values, you can transform values as they are serialized, or prior to deserialization, to enable JSON to represent additional data types.
In other words, if you really want to JSONify the functions, you can convert them to strings before serializing:
mo.init = ''+mo.init;
mo.test = ''+mo.test;
And after deserializing, convert them back to functions.
mo.init = eval(mo.init);
mo.test = eval(mo.test);
However, there should be no reason to do that. Instead, you can have your MyObject constructor accept a simple object (as would result from parsing the JSON string) and copy the object's properties to itself.
Functions can not be serialized into a JSON object.
So I suggest you create a separate object (or property within the object) for the actual properties and just serialize this part.
Afterwards you can instantiate your object with all its functions and reapply all properties to regain access to your working object.
Following your example, this may look like this:
function MyObject() { this.init(); }
MyObject.prototype = {
data: {
property1: "",
property2: ""
},
init: function () {
this.property1 = "First";
this.property2 = "Second";
},
test: function() {
alert("Executing test!");
},
save: function( id ) {
window.localStorage.setItem( id, JSON.stringify(this.data));
},
load: function( id ) {
this.data = JSON.parse( window.getItem( id ) );
}
}
To avoid changing the structure, I prefer to use Object.assign method on object retrieval. This method merge second parameter object in the first one. To get object methods, we just need an empty new object which is used as the target parameter.
var mo = window.localStorage.getItem("myObject");
// this object has properties only
mo = JSON.parse(mo);
// this object will have properties and functions
var completeObject = Object.assign(new MyObject(), mo);
Note that the first parameter of Object.assign is modified AND returned by the function.
it looks like when I serialized the object, somehow the functions get dropped... What am I doing wrong?
Yes, functions will get dropped when using JSON.stringify() and JSON.parse(), and there is nothing wrong in your code.
To retain functions during serialization and deserialization, I've made an npm module named esserializer to solve this problem -- the JavaScript class instance values would be saved during serialization on Page 1, in plain JSON format, together with its class name information:
var ESSerializer = require('esserializer');
function MyObject() { this.init(); }
MyObject.prototype = {
property1: "",
property2: "",
init: function () {
this.property1 = "First";
this.property2 = "Second";
},
test: function() {
alert("Executing test!");
}
}
MyObject.prototype.constructor=MyObject; // This line of code is necessary, as the prototype of MyObject has been overridden above.
var mo = new MyObject();
mo.test(); // This works
window.localStorage.setItem("myObject", ESSerializer.serialize(mo));
Later on, during the deserialization stage on Page 2, esserializer can recursively deserialize object instance, with all types/functions information retained:
var mo = window.localStorage.getItem("myObject");
mo = ESSerializer.deserialize(mo, [MyObject]);
alert(mo.property1); // This shows "First" as expected.
mo.test(); // This works too.
That's because JSON.stringify() doesn't serialize functions i think.
You're right, functions get dropped. This page might help:
http://www.json.org/js.html
"Values that do not have a representation in JSON (such as functions and undefined) are excluded."