I'm facing an issue and I'm not sure why. I'm setting a StorageFile as a property of a javascript object:
var myFile = MethodThatReturnsAFile();
var obj = { file: myFile };
The problem comes when I need to 'clone' that object. Based on a lot of SO answers on the matter I've come to use this method for cloning my objects:
for (var pty in obj)
if (obj.hasOwnProperty(pty) && target[pty] !== obj[pty])
target[pty] = obj[pty];
Where obj is my current object and target is the object I want to create, in my case var target = {}.
It works fine 'almost' everytime, expect when obj has a StorageFile in one of its properties. (I get the message from the subject)
I unserstand Storagefile is sealed and can't be extended, but why is who (WinJS?) trying to extend it? Should I change my clone method or should I not have StorageFile as property values?
JavaScript object properties may be not enumerable and hidden from 'for' or 'Object.keys'
Look defineProperty method https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Related
I have an empty object myscroll defined as var myscroll = {}. Now I want to add an array property to it. I did it as follows:
var myscroll = {}
myscroll.point[0] = getScrollpos("home");
myscroll.point[1] = getScrollpos("artists");
myscroll.point[2] = getScrollpos("songs");
myscroll.point[3] = getScrollpos("beats");
myscroll.point[4] = getScrollpos("contact");
I get the error myscroll.point is not defined. Then I first defined it as myscroll.point = [];, then the code worked.
So, Why can't we directly set array values and add that property to an object in javascript? Why do we have to define it first independently?
When you are dealing with object properties, by default you can access any object property and value of that property would be undefined if it wasn't set before. So, by accessing not defined property with index (myscroll.point[0]) you are trying to access property 0 of undefined, which is primitive value in javascript and has no properties, so you are getting TypeError.
As result you can set primitive values to not defined object property, but cannot dial with not defined prop as with object.
Also wanna to point you and explain situation with a little bit similar from first view situations in code below:
var obj = []
obj[0] = 10
notDefinedObj[0] = 10 // cause ReferenceError
Array is object. In JS you can't modify/add/delete object properties without initialising object before.
That's caused because objects are stored in memory and you can access them by reference. When you attempt to add new property to it, for instance add new element to list, you are trying to attach property to variable which has no Reference, that's why you are getting ReferenceError.
Good Luck!
With myscroll.point you're trying to access a point property on the myscroll object. But there is no such property on that object. That's why you're getting a undefined is not an object error message (or something similar - depending on your browser).
If you're coming from PHP, this might be strange but actually it's much more explicit than the magic involved in the following php snippet for example:
$myscroll = [];
$myscroll['point'][0] = getScrollpos("home");
// ...
PHP automagically created sub arrays for keys that do not exist.
Update after comment
There is a significant difference between myscroll.mypoint = 5; and myscroll.point[0] = getScrollpos("home");.
In the first case your setting the point property on myscroll to 5 explicitly. But in the second case you're trying to access the [] operator (which is an array operator) on a non-existing property point. Theoretically Javascript could do the same magic as PHP and create the array automagically on the fly, but it doesn't. That's why your getting an error.
It's the same as trying to access a fictitious property myproperty on myscroll.mypoint like myscroll.mypoint.myproperty. This will not work as well, because you're trying to access myproperty on mypoint which is undefined on myscroll.
Because myscroll.point[0] = getScrollpos("home"); can be understood as Get the first element of the point array inside of myscroll and set it to... You can't access the first element of an non-existing array.
Simply check typeof of myscroll array variable and then check the typeof of myscroll.point. You have tried to assign properties of an array, outside of an array. It is empty or undefined.
You are trying to access the point property of myscroll which is not defined (because myscroll = {}).
If you will look at the console with myscroll.point, it will return you undefined. Here you were trying to put something in undefined so you got TypeError: myscroll.point is undefined.
If you define myscroll like this:
var myscroll = {
point : []
}
Then your code will work and you won't need to define myscroll.point = [].
if you have an an empty object and you want to set a new property that holds an array you should do this.
var obj = {};
obj['propertyName'] = [];
this will put a property with corresponding propertyName that holds an array that you can later populate.
if your getScrolloops() returns an array you can do this
obj['propertyName'] = getScrolloops();
Idealy in your case you can do this:
obj['propertyName'] = [getScrollpos("home"),
getScrollpos("atrist"),
getScrollpos("songs"),
getScrollpos("beats"),
getScrollpos("contact")
];
EDIT: Explanation: Why is your code not working?
As explained here:
You can define a property by assigning it a value.
What you do is trying to define a property by assigning a value to an index of that property. This will not work because you are not assigning a value to the property it's self but to index of a property that dose not exist.
Also i need to mention that you can use both property accessors to achieve that. This could be a helpful link.
In Javascript an array [] can have properties too, because it's an object. However if you send this object to server via ajax/socket.io, it's array content stays, but its properties get lost.
For example:
var arr = ['john','peter'];
arr.a = 1;
console.log(arr.a); // 1
After sending this object via ajax, what the server sees:
console.log(arr.a); // undefined
Does anyone know why? I'm using Node.JS for server btw, thanks!
As others have mentioned, JSON.stringify() doesn't serialize array properties, even if they aren't "inherited" from proto.
If you're using jquery, a quick fix is to just use $.extend({},arr)
http://jsfiddle.net/15vn4shu/1/
If not, you can write a function to convert to an object easily:
function convertArrToObj(arr){
//assuming typeof arr === 'object', put in guards if needed
var obj = {};
for (var key in arr){
if (arr.hasOwnProperty(key))
obj[key]=arr[key];
}
return obj;
}
Personally, I'd just make an object with a property being the value of this array, add add to this parent object whatever you need. I'm not sure how feasible this is in your use case though (I'd have to see the code).
var toSend = {data:arr, customProp:'value'};
Easy, supported by all versions of js, doesn't require a framework, and no O(n) run through to do the conversion (arr is a pointer here... Which may be a gotcha, but it doesn't seem like it for your case).
I'm working on an AngularJS SPA and I'm using prototypes in order to add behavior to objects that are incoming through AJAX as JSON. Let's say I just got a timetable x from an AJAX call.
I've defined Timetable.prototype.SomeMethod = function() and I use https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf in order to set the prototype of x to TimeTable.prototype. I have the polyfill in place too.
If I call x.SomeMethod() this works in IE > 9, FF, Chrome etc. However, IE 9 gives me a headache and says throws an error stating 'x does not have property or member SomeMethod'.
Debugging in IE shows me that the _proto_ of x has SomeMethod() in the list of functions, however, calling x.SomeMethod() gives the same error as described.
How can I make this work in IE9 ?
More comment than answer
The main problem with "extending" a random object retrieved from some other environment is that javascript doesn't really allow random property names, e.g. the random object may have a property name that shadows an inherited property. You might consider the following.
Use the random object purely as data and pass it to methods that access the data and do what you want, e.g.
function getName(obj) {
return obj.name;
}
So when calling methods you pass the object to a function that acts on the object and you are free to add and modify properties directly on the object.
Another is to create an instance with the methods you want and copy the object's properties to it, but then you still have the issue of not allowing random property names. But that can be mitigated by using names for inherited properties that are unlikely to clash, e.g. prefixed with _ or __ (which is a bit ugly), or use a naming convention like getSomething, setSomething, calcLength and so on.
So if obj represents data for a person, you might do:
// Setup
function Person(obj){
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
this[p] = obj[p];
}
}
}
Person.prototype.getName = function(){
return this.name;
};
// Object generated from JSON
var dataFred = {name:'fred'};
// Create a new Person based on data
var p = new Person(dataFred);
You might even use the data object to create instances from various consructors, e.g. a data object might represent multiple people, or a person and their address, which might create two related objects.
This is how I solved it at the end:
Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
if (!isIE9()) {
obj.__proto__ = proto;
} else {
/** IE9 fix - copy object methods from the protype to the new object **/
for (var prop in proto) {
obj[prop] = proto[prop];
}
}
return obj;
};
var isIE9 = function() {
return navigator.appVersion.indexOf("MSIE 9") > 0;
};
I've been using dean edwards base.js (http://dean.edwards.name/weblog/2006/03/base/) to organise my program into objects ( base.js is amazing btw, if you havent used it before !).Anyway, my question is generic and you don't have to know base.js to know my answer.
I have a property in one of my objects called ref which is a reference to a DOM element, and this object is meant to be saved as JSON using JSON.stringify, but as you can imagine since DOM elements are circular structure, I won't be able to convert the object into JSON.
Now to get around this problem I have a method called html() which is meant to return the ref property, but I need to have ref as a private property which is only accessible from within the object, and hence won't be sent to stringify.
What's the best way to do that?
You probably know that you cannot have private properties in JavaScript.
Interestingly, if you pass an object to JSON.stringify which has a method toJSON, JSON.stringify will automatically call that method to get a JSONable representation of that object. So all you have to do is implement this method.
For example you can create a shallow copy of the object which only contains the properties you want to copy:
MyConstructor.prototype.toJSON = function() {
var copy = {},
exclude = {ref: 1};
for (var prop in this) {
if (!exclude[prop]) {
copy[prop] = this[prop];
}
}
return copy;
};
DEMO
Another way would be to use a custom replacer function, but it might be more difficult to control which ref to exclude and which one to keep (if different objects have ref properties):
JSON.stringify(someInstance, function(key, value) {
if(key !== 'ref') {
return value;
}
});
DEMO
here is sample to to set variable visibility
function Obj(){
this.ref = 'public property'; // this property is public from within the object
var ref = 'private proerty'; // this property is private.
var self = this;
this.showRef = function(){
alert(ref);
alert(self.ref);
};
}
var obj = new Obj();
obj.showRef();
What does assigning a variable to {}, mean? Is that initializing it to a function? I have code in a javascript file that says this
GLGE.Wavefront = function(uid) {
GLGE.Assets.registerAsset(this,uid);
this.multimaterials = [];
this.materials = {}; // <---
this.instances = [];
this.renderCaches = [];
this.queue = [];
};
how is that assignment different from an array? Is it a type of array?
What does assigning a variable to {}, mean?
It is an object literal (with no properties of its own).
Is that initializing it to a function?
No, that would be = function () { }.
how is that assignment different from an array?
An array has a bunch of features not found in a basic object, such as .length and a bundle of methods.
Objects are often used to store arbitrary key/value pairs. Arrays are for ordered values.
This is javascript object notation. Particularly {} means empty object, the same as new Object();. See json.org.
That would be an empty JavaScript object.
Using {} creates an object. You can use the object like a hash-map or similar to how you can use arrays in PHP.
var obj = {};
obj['test'] = 'valuehere';
obj.secondWay = 'secondValue';
and you could access them by calling obj.test and obj['secondWay'].
It's an initialized empty object, eg. an object of no particular type. It serves to provide a definition for this.materials so that the code won't have to check it for null or being defined later.
It does create an empty object.
var myObj = {};
Within an object you can define key/value pairs, e.g.:
myObj.color = 'red';
A value can be a function, too:
myObj.getColor = function() { return this.color };
It's JON (Javascript Object Notation) for creating a new empty object. Almost equal in idea to how you'd normally do Object x = new Object() in java, minus the initialization part...