This is some sort of question from curiossity.
The question is:
How does these Client-side frameworks work, let me explain.
I am working with javascript for more than 5 years. And I don't understand one thing. How do they know when the variable (for example title) variable value changes???.
I would do it like this:
function onTitleChange(title) { //do some stuff }
let title = "This is some title"
let lastTitle = title;
setInterval(() => {
if(lastTitle !== title) {
onTitleChange(title);
lastTitle = title
}
}, 10);
Is this how they all work? Is this how the Vue.js knows when the variable value changes? If not, what sort of magic do they use to know when a variable value changes??
I'm gonna try to explain it in very simple words, step by step:
make a <h2>Hi</h2> element on a simple HTML page
open browser console and store DOM element in a variable:
var h2 = document.getElemntsByTagName('h2')[0];
make two other variables first var obj = {}; and second var text = '';
this is the part that you are looking for:
instead of simply assigning obj.text = text we declare getter setter's for obj.text attribute so that whenever we set new value to obj.text the corresponding DOM element changes too.
Object.defineProperty(obj, 'text', {
get: function () {
return text;
},
set: function (newvalue) {
text = newvalue;
h2.innerHTML = text;
}
});
now go on and change obj.text value : obj.text = "Hello again"
for more information check this page out.
all the codes available at : JSfiddle
There is no magic, Angular for example uses zone.js, I recommend you have a read about it.
Little about React - its not actually listen to changes of the js objects, because of it only call render methods of components, if shouldComponentUpdate() (default it use reference equality of the component state) return true, and check if returned VirtualDOM is equal to the real DOM.
Because of it - its much more faster then Angular, which use many of listeners and equality checkers for watching updates.
Related
Is it possible to convert a var to a const?
Say in a scenario like this:
var appname = ''
function setAppName(name) {
appname = name // can I convert this to const now?
}
Basically, this is for a parameter level. Parameter needs to be accessible throughout the file and I want to make it const after first assignment. Is this possible?
To add: If there is any other way besides creating an object with to contain this parameter, it would be better (for a more straightforward solution). I will be working on multiple parameters like this and freezing an object will cause the entire object to freeze. I am hoping to do this on the parameter level.
So either change the parameter to become const. OR (this one I dont think is possible) change the scope of the paramter to global:
function setAppName(name) {
const appname = name // can I change the scope and make this global?
}
Thanks.
Put your app name in an object and freeze it.
let appSettings = { name: "" };
function setAppName(name) {
appSettings.name = name;
Object.freeze(appSettings);
}
Freezing prevents adding, removing and modifying the values of the properties in your object so you should call Object.freeze only once after all other settings (if there are more variables you want to make constant) have been set.
You can do this using a object.
const globals = {
appname: ''
}
function setAppName(name) {
globals.appname = name;
Object.freeze(globals)
// After this point, value of appname cannot be modified
}
Thank you for all your inputs.
I was able to find a workaround for what I was trying to achieve.
var appname = ''
function setAppName(name) {
if (appname === '') {
appname = name // can I convert this to const now?
}
}
Although this doesnt convert it to const, I just added a guard on the setter and it will not be able to overwrite the value now (unless otherwise I am going to initialize again to an empty string).
It is not fool-proof, but this will address my need.
Thanks all!
Working with multiple closures has me all turned around. It seems that you define a variable in one closure then return it publicly so it can be accessed. Returning it requires giving it a public name. Then you pull it into another closure by defining it as a new variable with yet a third name?
My head is spinning a bit.
Here's a code snippet. It obviously doesn't work (obvious to you maybe, I had to struggle to get this far) Where am I breaking down? AM I making this too difficult on myself? Is there a simpler way or merely a 'best practice' way?
If this is the correct course... I'll commit to it. I'm not looking for an easy answer, but I am looking to truly grasp what I'm doing rather than regurgitate structures I've seen somewhere already. Thanks in advance.
//CREATES A PRIVATE CLOSURE TO GRAB DOM CLASS & ASSOCIATED VALUE
var createUI = (function(){
//Stores a class from DOM into VARIABLE
var buttonClass = ".add__btn";
//RETURNS...
return {
// THE VALUE FOUND IN THE DOM ELEMENT OF THE STORED CLASS ABOVE
classPublicValue : function(){
return {
value: document.querySelector(buttonClass).value
}
},
// RETURNS THE CLASS ITSELF FOR FUTURE SHORTHAND USAGE. A GOOD PRACTICE I'M TOLD??
theClass : function() {
return buttonClass;
}
}
})();
//CREATES A SECOND PRIVATE CLOSURE TO PERFORM ACTION ON CLICK THAT USING STRUCTURES FROM FIRST CLOSURE.
var clickToHappen = (function() {
//PULLS IN THE CLASS ".add__Btn" as a string.
var myClass = createUI.theClass();
//POINTS TO THE VALUE OF THE ELEMENT CONTAINING THE PULLED IN CLASS.
var myValue = createUI.classPublicValue();
//RETURNS...
return{
clickMe : function(){
//A CLICK LISTENER ON DOM ELEMENT WITH CLASS CHOSEN IN FIRST PRIVATE CLOSURE.
document.querySelector(myClass).addEventListener('click', function() {
//STORES CURRENT VALUE INTO VARIABLE
var value = createUI.classPublicValue();
//PRINTS THAT VALUE TO CONSOLE
console.log(value);
});
}
}
})();
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.
I was just doing a small test to see how Javascript would respond to changing a child object's value within a parent object. I wanted to see if the parent referenced the child and would keep up to date with the new values, or if it would only keep the initial state of the child that it was instantiated with.
I have the little module coords.js
var NS = NS || {};
NS.Coords = function(){
var __parentArray = {};
var __childArray = {};
addToParent = function(){
__childArray['value'] = "Initial";
__parentArray['child'] = __childArray;
},
showParent = function(){
console.log("Parent: ",__parentArray);
console.log("Child within parent: ",__parentArray['child']);
},
changeChild = function(){
__childArray['value'] = "Changed";
},
showChild = function(){
console.log("Child: ",__childArray]);
};
return {
addToParent: addToParent,
showParent: showParent,
changeChild: changeChild,
showChild: showChild
};
}();
And in main.js
var NS = NS || {};
// #codekit-prepend "Coords.js"
console.log("=============================");
console.log("Startpoint point");
console.log("=============================");
var coords = NS.Coords;
coords.addToParent();
coords.showChild();
coords.showParent();
console.log("=============================");
console.log("Changed child value");
console.log("=============================");
coords.changeChild();
coords.showChild();
coords.showParent();
If you run this, you see in the console that when shown directly, the child shows the expected "Initial" and then "Changed" values.
The parent, however, always shows the "Changed" value of the child object it references. Even before changeChild() is called. No idea why. Without even changing the value it shows that it's been changed. Am I missing something super simple, or am I misunderstanding what's going on here?
The first problem is you are probably using GOOGLE CHROME, i mean this isn't a problem, but don't forget that if you change a property, the console updates it AUTOMAGICALLY too. (Magical isn't it?)
If you change this console.log("Child within parent: ",__parentArray['child']); to console.log("Child within parent: ",__parentArray['child']['value']); then you can see that your script is working correctly.
Here is the fiddle: http://jsfiddle.net/M4Cd8/
There are some syntax errors in your code, but once those are fixed, the behavior you're describing does not occur. Some browsers' consoles provide an inline reference to objects, that is updated when the object changes. The answer is to observe the value string rather than the whole object:
console.log("Child within parent: ",__parentArray['child'].value);
console.log("Child: ",__childArray.value);
http://jsfiddle.net/pNtJJ/
But to clear up the question you were originally trying to figure out, yes, if you change an object that another object is referencing, then the change is refelcted no matter how you go about observing that, because a reference is precisely that - a link from one object to another.
As a side note, your variable names have the word "array" in them, but those are not arrays that you are working with, but objects. Arrays are typically created with square brackets [1, 2, 3, 4] and contain just values, not key-value pairs.
I'm looking for patterns which have been found acceptable when working with instances of js objects on the same page. (If there is a thread already covering this, a link will be appreciated.)
The issue is one of reference. After an object/feature is instantiated, it has to be referenced at some point later.
I've seen jQuery people store a reference to the object on the target DOM element using data(). However, I'm interested in a framework agnostic option if possible.
This could be accomplished if there was a clean, viable way to generate an unique id for a DOM element. Alas, I have not found one yet.
So my question is: What is the best way to store reference to an object, via a DOM element, so that you can reference it at a future arbitrary time?
Hopefully this makes sense, and I'm not just rambling. :)
Thanks.
There is nothing stopping you from maintaining your own cache:
var cache = [];
function locate(el) {
// search for the element within our cache.
for (var i=0;i<cache.length;i++) {
if (cache[i].elem === el) {
return cache[i].data;
};
};
// if we get this far, it isn't in the cache: add it and return it.
return cache[cache.push({
elem: el,
data: {}
}) - 1].data;
};
// used to add data to an element and store it in our cache.
function storeData(el, data) {
var store = locate(el);
for (var x in data) {
store[x] = data[x];
};
};
// used to retrieve all data stored about the target element.
function getData(el) {
return locate(el);
};
and then use as follows:
storeData(document.getElementById("foo"), {
something: 4,
else: "bar"
});
var data = getData(document.getElementById("foo"));
alert(data.something); // "4";
Objects in JavaScript (unlike classical OOP languages) can be augmented. There's nothing wrong with that; that's the way JavaScript was designed to be used:
Write:
document.getElementById( 'foo' ).customAttribute = 5;
Read:
alert( document.getElementById( 'foo' ).customAttribute );
If you don't want to alter the original object, the only way to point at it is using a dictionary as pointed out in one of the previous answers; however, you don't need to do a linear search to find the object: it can be done in logarithmic time providing you use an ID per element (potentially not its HTML ID but a custom one)