I'm new to javascript and struggling with a problem below.
Let's think about this situation.
First, there is an object like this.
var bar = {
'name' : 'bob',
'comments' : []
}
However because of some reasons, we have only one variable that named 'foo' and this is exactly same with bar.comments.
Second, because we need to reference the object bar, there must exist method in foo, named callParent. If we satisfy all these condition, we can get object bar using foo.callParent().
To implement like above, first of all, I define a constructor name Custom.
function Custom(param){
this.callParent = function(){
console.log(param);
}
}
and then, to use instance of Custom like array, inherit Array.
Custom.prototype = Array.prototype;
after that, I want to define object bar as like below.
var bar = {
'name':'bob',
'comments':new Custom(this)
}
In that implementation, because I thought this means bar itself, I expected the result foo.callParent() will be bar but it was window. I think it's because in the context of calling foo.callParent(), this no longer means bar.
Finally, I solve this problem like this.
var bar = {
'name':'bob',
'comments':undefined,
'init':function(){
this.comments = new Custom(this);
return this;
}
}.init();
Qeustion: Is there any way to solve this situation without help of other method like bar.init? I want to solve this only with changes of constructor Custom! Is it related with IIFE?
Try this:
var bar = {
'name':'bob'
};
bar.comments = new Custom(bar);
Related
I have a Angular service and in it I have variables like this:
export class MyService {
someVariableA = 1;
someParams = {
someVariableB,
otherVariable: this.someVariableA
};
}
and in a component I set the 'someVariableA' to 3
this.myService.someVariableA = 3;
and I want 'otherVariable' to get that value 3 as well, but it doesn't. It remains 1 when I go to get the value.
let v = this.myService.someParams.otherVariable;
Is it possible to set 'otherVariable' this way or any other way via 'someVariableA'?
As #Zulwarnain answered, 1 is a number or a primitive data type. Primitive data types in javascript are passed by value, not by reference which you seem to be expecting here.
An easy fix for this is to assign a function to otherVariable instead. Now just invoke the function someParams.otherVariable() and it will return the value of someVariableA. No need to make this complicated.
export class SingletonService {
public someVariableA = 1;
public someParams = {
otherVariable: () => this.someVariableA
};
}
This is basic javascript with multiple sources covering the subject.
https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0
I concur with this answer that you will have a better time if you use a reference type like an object/array instead of a primitive value type like a number. By adding one layer of indirection (e.g., someVar = 123 becomes someVar = {value: 123}) you could very easily get similar functionality to what you're seeking.
If, however, your use case requires an object's property to directly act like a reference to a primitive value type stored somewhere else, you can get this behavior by implementing the property as a getter and setter pair. It's more complicated, but it acts the way you want.
Here's an example:
class MyService {
someVariableA = 1;
someParams: {
someVariableB: number;
otherVariable: number;
};
constructor() {
this.someVariableA = 1;
const that = this;
this.someParams = {
someVariableB: 2,
get otherVariable() {
return that.someVariableA
},
set otherVariable(val: number) {
that.someVariableA = val;
}
}
}
}
Note that in order for the otherVariable getter and setter to be able to access the right context, I had to move the code into the constructor and copy this into a new variable I called that. The this context of a getter/setter refers to the object it's a member of, and not some this from an outer scope.
Let's make sure it works:
const ms = new MyService();
ms.someVariableA = 100;
console.log(ms.someParams.otherVariable); // 100
ms.someParams.otherVariable = -5;
console.log(ms.someVariableA); // -5
Looks good; changes to ms.someVariableA are immediately reflected in ms.someParams.otherVariable, and vice versa. All right, hope that helps; good luck!
Playground link to code
You are assigning the value type this will not work like you want. you need to assign reference type
obj ={someVariableA : 1};
someParams = {
otherVariable: this.obj
};
in the above code, if you change the value of obj.someVariableA it will also change the value of someParams.otherVariable
I am expexting that you have knowledge about reference type and value types variables
click here for demo
I don't think you want to do that. I believe you are getting a new instance of the service each time you call it, so the variables get reset.
you might want to set that variable in localStorage instead, and then have the service retrieve it from localStorage. That way it will always be getting whatever it was last set to.
or just pass that variable into your service call, instead of trying to use a local service variable.
Is it possible to keep an object reference without using an holder object in javascript?
Currently when an object gets overridden I sometimes lose the reference to the "current" object state illustrated in the snippet below;
Is there a way to put a "pointer" in an array or not?
EDIT
To the questions asked:
What I have in the objects I have are references to form fields. Some of these are text fields, some of them are textareas, some of them checkboxes.
I wish to keep a map next to the direct referene of what type they are.
basicaly it would be
obj {
this.text1 = createTextField();
this.text1.datepicker();
this.text2 = createTextField();
this.area1 = createArea();
this.check = createCheck();
this.datefields = [this.text1];
this.checkboxes = [this.check];
}
So I can use the datefields/checkboxes array as a checkpoint to validate against which type a field is/should behave.
Currently I use
function datefields() { return [this.text1]; };
But I'd like to know if there's a better way to do this than to intantiate a new array when I need to check it.
I know there is a way with observers to mimic pointer behaviour, and i've fiddled with those and have some good results with that, i'm just curious if there are other ways i'm not aware of.
function myObject() {
this.myvalue = null;
this.arr = [this.myvalue];
}
myObject.prototype.alter = function() {
this.myvalue = "hello";
}
var x = new myObject();
var elem = document.getElementById('results');
function log(message) {
elem.appendChild(document.createTextNode(message));
elem.appendChild(document.createElement('br'));
}
log("x.myvalue = "+x.myvalue);
log("x.arr[0] = "+x.arr[0]);
log("calling alter");
x.alter();
log("x.myvalue = "+x.myvalue);
log("x.arr[0] = "+x.arr[0]);
<div id="results"></div>
Simple answer: Only objects (including all subtypes) are passed by reference in JS. All other simple values are copied.
For a bit more detail I would recommend reading You Don't Know JS: Types & Grammer but specifically the section Value vs Reference in Chapter 2:
In JavaScript, there are no pointers, and references work a bit differently. You cannot have a reference from one JS variable to another variable. That's just not possible.
Quoting further on:
Simple values (aka scalar primitives) are always assigned/passed by value-copy: null, undefined, string, number, boolean, and ES6's symbol.
Compound values -- objects (including arrays, and all boxed object wrappers -- see Chapter 3) and functions -- always create a copy of the reference on assignment or passing.
There are plenty of examples included to show these points. I would highly recommend reading through to get a better understanding of how values/references work in JS.
There is no pointers in Javascript, though you could cheat a little using a wrapper object. Here is a minimal implementation of such an object:
var Wrapper = function (value) {
this.value = value;
};
Wrapper.prototype.valueOf = function () {
return this.value;
};
Then you may use it in place of the original value:
function myObject() {
this.myvalue = new Wrapper(null); // wrapper
this.arr = [this.myvalue];
}
myObject.prototype.alter = function() {
this.myvalue.value = "hello"; // notice the ".value"
}
The rest of your code needs no tweaks.
Been trying to instantiate an object (called "isSize" below) and assign it to another existing variable (called "sizeObject"), here is the first object ("isSize") within a function:
function Size(isSize) {
this.isSize = 80;
setSize(this.isSize);
}
And here's the second variable of which I want to assign the previous variable to:
var sizeObject;
I've been trying various ways such as the following:
function createSize(isSize){
var isSize = new sizeObject();
}
Anyone got any ideas? Many thanks
If I understand your comment correctly, here is what you are looking for:
// this is the constructor of the `Size` class
function Size() {
this.isSize = 80;
}
function createSize() {
// add this line:
var sizeObject = new Size();
}
It's very hard to understand quite what you're asking, but this:
var sizeObject = new Size(20);
...will create a new object with a isSize property on it with the value 20 if you change Size to:
function Size(initialSize) {
this.isSize = initialSize;
}
(E.g., so it actually uses the argument you give it, rather than using an hardcoded 80.)
Size in the above is a constructor function. You use constructor functions via new.
Which is the best way between:
var myClass = function() {
this.myContainer = function(){ return $(".container");}
this.mySubContainer = function(){ return this.myContainer().find(".sub"); }
}
AND
var myClass = function() {
this.myContainer = $(".container");
this.mySubContainer = this.myContainer.find(".sub");
}
Is there any concrete differences?
The memory problem arose when I have seen that my web page, that has enough javascript ( about 150KB of mine + libs ) takes more then 300-400MB of RAM. I'm trying to find out the problem and I don't know if this could be one of them.
function myClass{
this.myContainer = function(){ return $(".container");}
this.mySubContainer = function(){ return this.myContainer().find(".sub"); }
}
Here you will need to call it something like myClassInstance.myContainer() and that means jquery will search for .container element(s) any time you are using that function. Plus, it will create 2 additional closures any time you will create new instance of your class. And that will take some additional memory.
function myClass{
this.myContainer = $(".container");
this.mySubContainer = this.myContainer.find(".sub");
}
Here you will have myContainer pointing to an object which already contains all links to DOM nodes. jQuery will not search DOM any time you use myClassInstance.myContainer
So, second approach is better if you do not want to slow down your app. But first approach could be usefull if your DOM is frequently modified. But I do not beleave you have it modified so frequently that you may need to use second approach.
If there is a single variable you are trying to assign , then the second approach looks cleaner..
Yes they are different.
MODEL 1:
In the first model, myContainer is a function variable.It does not contain the jQuery object.You cannot call any of jQuery's methods on the objet. To actually get the jQuery object you will have to say
var obj = this.myContainer() or this.myContainer.call()
MODEL 2:
The second model stores the actual jQuery object.
try alerting this.myContainer in both models, u will seee the difference.
Yes this is different. after you fix your syntax error :
function myClass(){... // the parentheses
1st
When you create a new object var obj = new myClass(), you are creating two functions, and the jquery object is not returned until you call it
var container = obj.myContainer();
2nd
As soon as the object is initialized the dom is accessed and you have your objects cached for later use;
var container = obj.myContainer;
I've seen something similar to this code in the Google API JavaScript, I mean the r=Array part. Here is an example of what they have done:
var r = Array;
var t = new r('sdsd' , 'sdsd');
alert(t[0]);
Few questions about this:
Is it legal to write like this and won't cause any problems?
I can do something similar with other keywords like ´For´ loop or with the ´this´ keyword?
Can I have article about this JavaScript official keyword shortcuts etc..?
Thank you in advance.
That works because Array is an object. You can do that with any object. For example, the Date object:
var d = Date;
console.log((new d()).getTime()); //Prints time
You cannot do that for keywords such as for or while because they are language constructs that will be recognised by the interpreter.
You can do it with this:
document.getElementById("b").onclick = function() {
var x = this; //this holds a reference to the DOM element that was clicked
x.value = "Clicked!";
}
In fact, that can be very useful sometimes (to keep a reference to this so you can access it from an anonymous inner function for example). This also works because, to put it simply, this will be a reference to an object.
Yes
for - no. this - yes.
You can store references to any JavaScript object in a variable. String, Array, Object, etc. are JavaScript objects that are built-in to the language. for, if, while, etc. are are JavaScript statements, and cannot be stored or referenced any other way.
You can do it the other way around as well (and really mess yourself up in the process):
Array = 0;
var myArray = new Array("a", "b", "c"); // throws error
This is easily undone like this:
Array = [].constructor;
Edit: Being able to assign the value of this to a variable is essential when nesting functions that will execute in a different scope:
function Widget() {
var that = this;
this.IsThis = function() {
return isThis();
};
function isThis() {
return that == this;
}
}
new Widget().IsThis(); // false!
Maybe not the best example, but illustrates losing scope.
You cannot reassign the value of this:
function doSomething() {
this = 0; // throws error
}