Okay, so this is complicated so try to bear with me, i will try to keep it as simple as possible:
I have a "class" Struct, that creates a "struct like" skeleton to apply to ArrayBuffers within Javascript. The problem is when I am attempting to mimic the 'c' like behavior of allowing a struct to contain other structs.
The problem is that it clobbers the iterator of the calling method (obviously a closure problem), that i cant seem to figure out.
Here is an example of the code that gets clobbered (hopefully this is enough code to get the answer, if not I will add more as necessary, just trying to keep extraneous code out of here):
function StructObject(){
this.applyBuf = function(buf, start){
var struct = {};
for (obj in this){
//problem is here:
console.log(obj); //prints "c" on the way in
struct[obj] = this[obj].__createFromBuf();
console.log(obj); //prints "foo" (see the structs below)
}
return struct;
}
}
function struct(strctObj, name){
var structObject = new StructObject();
...
//create the skeleton
for (item in strctObj){
//the specific code that fails me
structObject[item].__createFromBuf = function(buf, pos){
return structs[this.name].applyBuf(buf, pos);
}
...
//store the skeleton for later application
structs[name] = structObject;
}
//Creating structs looks like this:
new struct({ foo: type.INT }, "bar");
new struct({
a: type.INT, //defines size of memory (like c's sizeof)
b: type.LONG,
c: {type: type.STRUCT, name: "bar"},
d: type.SHORT}, "myStruct");
structs.myStruct.applyBuf(new ArrayBuffer(35));
When I iterate through the first struct on the class method applyBuf, it calls __createFromBuf on each item within the struct skeleton, if the item is another struct __createFromBuf calls applyBuf on the other "struct skeleton" object and returns an instance of that struct back to the calling struct, which works as intended.
JSFIDDLE -- Here is the link to a working example :)
clean your for statements:
if not declared properly, the for loop index becomes a global member.
demonstration:
for (item in strctObj) // item becomes a global member
for (var item in strctObj) // item is scoped within the loop's owner function
Related
I used C++ before and I realized that pointers were very helpful. Is there anything in javascript that acts like a pointer? Does javascript have pointers? I like to use pointers when I want to use something like:
var a = 1;
var b = "a";
document.getElementById(/* value pointed by b */).innerHTML="Pointers";
I know that this is an extremely simple example and I could just use a, but there are several more complex examples where I would find pointers very useful. Any ideas?
No, JS doesn't have pointers.
Objects are passed around by passing a copy of a reference. The programmer cannot access any C-like "value" representing the address of an object.
Within a function, one may change the contents of a passed object via that reference, but you cannot modify the reference that the caller had because your reference is only a copy:
var foo = {'bar': 1};
function tryToMungeReference(obj) {
obj = {'bar': 2}; // won't change caller's object
}
function mungeContents(obj) {
obj.bar = 2; // changes _contents_ of caller's object
}
tryToMungeReference(foo);
foo.bar === 1; // true - foo still references original object
mungeContents(foo);
foo.bar === 2; // true - object referenced by foo has been modified
You bet there are pointers in JavaScript; objects are pointers.
//this will make object1 point to the memory location that object2 is pointing at
object1 = object2;
//this will make object2 point to the memory location that object1 is pointing at
function myfunc(object2){}
myfunc(object1);
If a memory location is no longer pointed at, the data there will be lost.
Unlike in C, you can't see the actual address of the pointer nor the actual value of the pointer, you can only dereference it (get the value at the address it points to.)
I just did a bizarre thing that works out, too.
Instead of passing a pointer, pass a function that fills its argument into the target variable.
var myTarget;
class dial{
constructor(target){
this.target = target;
this.target(99);
}
}
var myDial = new dial((v)=>{myTarget = v;});
This may look a little wicked, but works just fine. In this example I created a generic dial, which can be assigned any target in form of this little function "(v)=>{target = v}". No idea how well it would do in terms of performance, but it acts beautifully.
due to the nature of JS that passes objects by value (if referenced object is changed completely) or by reference (if field of the referenced object is changed) it is not possible to completely replace a referenced object.
However, let's use what is available: replacing single fields of referenced objects. By doing that, the following function allows to achieve what you are asking for:
function replaceReferencedObj(refObj, newObj) {
let keysR = Object.keys(refObj);
let keysN = Object.keys(newObj);
for (let i = 0; i < keysR.length; i++) {
delete refObj[keysR[i]];
}
for (let i = 0; i < keysN.length; i++) {
refObj[keysN[i]] = newObj[keysN[i]];
}
}
For the example given by user3015682 you would use this function as following:
replaceReferencedObj(foo, {'bar': 2})
Assigning by reference and arrays.
let pizza = [4,4,4];
let kebab = pizza; // both variables are references to shared value
kebab.push(4);
console.log(kebab); //[4,4,4,4]
console.log(pizza); //[4,4,4,4]
Since original value isn't modified no new reference is created.
kebab = [6,6,6,6]; // value is reassigned
console.log(kebab); //[6,6,6,6]
console.log(pizza); //[4,4,4,4]
When the compound value in a variable is reassigned, a new reference is created.
Technically JS doesn't have pointers, but I discovered a way to imitate their behavior ;)
var car = {
make: 'Tesla',
nav: {
lat: undefined,
lng: undefined
}
};
var coords: {
center: {
get lat() { return car.nav.lat; }, // pointer LOL
get lng() { return car.nav.lng; } // pointer LOL
}
};
car.nav.lat = 555;
car.nav.lng = 777;
console.log('*** coords: ', coords.center.lat); // 555
console.log('*** coords: ', coords.center.lng); // 777
I've created 2 objects (object1 and object2) using different ways.
I found no difference between them, except for the way how it is displayed in the Chrome Dev Console (see this in the below screenshot)
var F;
function create(parent, properties) {
F = function(p) {
for(var i in p){
this[i] = p[i].value;
}
};
F.prototype = parent;
return new F(properties);
}
var prop={ p: { value: 42 } };
var masterObject = {a: "masterObject value"}
var object1 = create(masterObject, prop);
var object2 = Object.create(masterObject, prop);
Following are my questions:
As I'm following different ways to create objects, will there be any difference between the objects - object1 and object2?
What is the difference that can be seen in the above screenshot (encircled in red)?
Both Objects have the same properties, and inherit from the same object. However, theres a small difference:
new F();
//vs.
Object.create(F.prototype);
The constructor (the function called to build the object) should be different:
object1.constructor!==object2.constructor
So these objects should not be equal, however it has no real effect as the constructor is rarely used.
Should because basically
F.prototype=parent;
breaks the whole thing, as F.prototype.constructor is initialized with F , so youre overridding this. More info at
Why is it necessary to set the prototype constructor?
When you assign a function to a variable, you created a named function.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
They are functionally the same.
Consider the following two ways of creating the instance of an object:
function f() { return { k: 'v'} }
var inst1 = f();
function F() { this.k = 'v'; }
var inst2 = new F();
The behavior of inst1 and inst2 is the same, the only difference is that a different constructor is saved to the object:
inst1.constructor; // Object()
inst2.constructor; // F()
What's the constructor of an array? See:
var xs = [];
xs.constructor; // Array()
Until this Point I understand the logic. But I bumped into the following:
var tags = document.getElementsByTagName("*");
typeof tags; // object
tags.constructor; // HTMLCollection()
So far it's similar to the inst2 example. But when I console.log with Firebug, I receive something like an Array with a 'named' constructor:
console.log(tags); // HTMLCollection[tag1, tag2, ...]
The block brackets confuse me, I would have expected curly one here. There must be an explanation to this, anybody knows the answer?
It sounds like the crux of your question lies in determining how Firebug displays your object. Firebug examines objects you passed to it, and chooses how it will display objects as a string based on what properties they have.
HTMLCollection is "array-like" so it has a length property, and stores its contents in properties named 0, 1, 2, etc. This makes it array-like and Firebug recognizes this, outputting the string representation of your object like it would an array.
In the case of Firebug, if it sees a length and a splice property, it will treat the object as array-like:
var MyArrayLike = function(){
this[0] = 1;
this.length = 1;
this.splice = function(){};
}
Firebug output:
-> new MyArrayLike();
<- [1]
Looking at the following code, can someone explain how values are passed around in JavaScript.
function loadImages() {
for(var sec in images) {
theme = images[sec];
for(var tsec in theme) {
theme[tsec].img = new Image();
theme[tsec].img.src = 'images/'+theme[tsec].src+'.png';
}
}
}
Then in another functions:
function definitionToSpriteDataMapping() {
var result = {};
for(var definition in blocks) {
var sprite = blocks[definition].sprite;
for(var secnm in images) {
section = images[secnm];
for(var spritenm in section) {
if(sprite == spritenm) {
result[definition] = {};
result[definition].img = section.img;
}
}
}
}
return result;
}
I cut out some code for simplicity sake but its still quite convoluted. Basically there are 2 objects (images & blocks) which are nested key:value pairs. In the first block of code
theme = images[sec];
theme[tsec].img.src = 'images/'+theme[tsec].src+'.png';
In the second line of code there is
section = images[secnm];
result[definition] = {};
result[definition].img = section.img;
There is no .img in "images" before the first block of code where .img is added to "theme". But this seems to be reflected back into "images" as seen in the second block of code. Are all objects like pointers in JavaScript? Will "result" have the same relationship with "blocks" as "theme" has with "images"? What if I remove an element from "theme", will that be reflected in "images"?
Using theme = images[sec] you will indeed create a pointer to that object in memory. So adding img to theme object will as well add img to that image, as they are the same object. So yes, the same goes for result.
Altering, adding or removing properties of an object referenced in such a way will influence the actual object. The same goes for arrays.
If you don't like that behavior, you should clone the object. You can clone a simple object simply by copying all properties:
var original = { name: "James", age: 73, male: true };
var clone = { };
for( var k in original )
clone[ k ] = original[ k ];
But if any property of that original is an array or object itself, it will be a reference. If you don't have any objects or arrays as properties, the above snippet will do fine. Otherwise you should write a clone function and recursively clone every member of the original.
Are all objects like pointers in JavaScript?
Effectively, yes, though I believe it would be more generally stated that in JavaScript an Object is a "reference type".
If var a references an object, and a is assigned to var b, b will get a copy of the reference that a holds, so a and b will both reference the same object data in memory.
Changes made from the a reference are observable from the b reference.
Note that this is still a "by value" assignment, but the value copied is the value of the reference, not the object itself.
The reason you are experiencing this is that objects are passed by reference. There are ways to clone objects. Take a look at this other SO post How do I correctly clone a JavaScript object?
You're altering images[sec][tsec] in both cases, which refers to the very same object in memory. Just doing theme = images[sec] does not make a copy of the object.
A more trivial example of this behaviour is this:
var obj = {};
var obj2 = obj;
obj.a = 123;
obj2.a; // 123
Say I already have many objects, like obj1, obj2, .....obj30.....
Now I am trying to write a function like this:
function blar(N){
do something to objN
}
blar('4');
So far it seems that the only way to do it is
function blar(thisObj){
do something to thisObj
}
blar(obj4);
I wonder what is the right way to pass the N such that the function can use that N value to process objN.
Hope I make myself clear.
PS: I even try something like blar(obj+N) but apparently it's wrong too, as the system tries to find obj, which doesn't exist.
Use square bracket notation.
window['obj' + N];
This depends on them dangling off the window object and not being nicely scoped though.
… but if you have a bunch of objects, which are identified by being the same except for a number, then you should probably be storing them in an array in the first place. Then you would just:
myArray[N];
Use eval:
function blar(N) {
var obj = eval("obj"+N);
}
Or, if you can put those objects into an object, you can use []
function blar(N) {
var obj = tracker["obj" + N];
}
It's pretty simple:
function blar(objectNo) {
var obj = eval('obj' + objectNo);
alert(obj);
}
To give you some keywords for talking with others about this: what you want to do is to access an object by its name, in the current scope.
But note that the following doesn't work:
function main() {
var a = 1, b = 2, c = 3;
blar('a'); // doesn't work
doSomething(eval('a')); // works
}
This is because the variable a is only visible in the main function, but not in blar. That is, the eval must be called in a scope where the variable is visible.