This question already has answers here:
Breakpoint on property change
(8 answers)
Closed 5 years ago.
I have a JavaScript variable called
var someProperty;
on line, let's say 10000 (its a huge js file), I have a function
function updateTime() {
console.log(someProperty.time); //i actually get an value here
}
I want to find out the function that is changing the value of the property I tried setting breakpoint using Chrome dev tools directly on that var someProperty but received a value of "undefined" - which makes me believe a function is setting this variable. How can I find out or watch where this someProperty.time property is being set?
This is a possible solution
var someProp = {
time: 'give me'
};
Object.defineProperty(someProp, 'time', {
set: function(time) {
this.__time = time
console.log('Method1: Getting time from:',arguments.callee.caller)
},
get: function() {
return this.__time;
}
});
(function ILikeChanges() {
someProp.time = 'changes';
})()
Another modern solution would be to use a Proxy object to wrap your object, that will give you the ability to add listeners to updates to your object.
In the set function we are using console.trace to print a full stack trace which will direct you to the calling function.
MDN Proxy
const watchObject = obj => new Proxy(obj, {
set(target, key, value) {
console.trace('set', { key, value })
return target[key] = value
}
});
// wrap the object with our proxy
const someProperty = watchObject({ time: new Date })
function setTime() {
someProperty.time = new Date
}
// call the function that changes the state
setTime()
// look in your console for the call stack
Related
This question already has answers here:
Where do the parameters in a javascript callback function come from?
(3 answers)
Closed 1 year ago.
I want to understand how the variable "window" which has the attribute MetaWindow can be used in different functions and vars while not being explicitly defined such as let app = this._tracker.get_window_app(window); and then passed on to other functions through a callback. Reference code here: windowAttentionHandler.js
Like here:
var WindowAttentionHandler = class {
constructor() {
this._tracker = Shell.WindowTracker.get_default();
this._windowDemandsAttentionId = global.display.connect('window-demands-attention',
this._onWindowDemandsAttention.bind(this));
this._windowMarkedUrgentId = global.display.connect('window-marked-urgent',
this._onWindowDemandsAttention.bind(this));
}
_getTitleAndBanner(app, window) {
let title = app.get_name();
let banner = _("ā%sā is ready").format(window.get_title());
return [title, banner];
}
_onWindowDemandsAttention(display, window) {
// We don't want to show the notification when the window is already focused,
// because this is rather pointless.
// Some apps (like GIMP) do things like setting the urgency hint on the
// toolbar windows which would result into a notification even though GIMP itself is
// focused.
// We are just ignoring the hint on skip_taskbar windows for now.
// (Which is the same behaviour as with metacity + panel)
if (!window || window.has_focus() || window.is_skip_taskbar())
return;
let app = this._tracker.get_window_app(window);
let source = new WindowAttentionSource(app, window);
Main.messageTray.add(source);
let [title, banner] = this._getTitleAndBanner(app, window);
let notification = new MessageTray.Notification(source, title, banner);
notification.connect('activated', () => {
source.open();
});
notification.setForFeedback(true);
source.showNotification(notification);
source.signalIDs.push(window.connect('notify::title', () => {
[title, banner] = this._getTitleAndBanner(app, window);
notification.update(title, banner);
}));
}
};
The variable window is not defined as MetaWindow in the suggested code because it borrows such status using the method .bind from the listening signal window-demands-attention in the module global.display. The method .bind is responsible for sending the type MetaWindow as this allowing it to be used in other functions with reference to the window which triggered the function _onWindowDemandsAttention in the first place:
global.display.connect('window-demands-attention', this._onWindowDemandsAttention.bind(this));
The bind() method allows an object to borrow a method from
another object without making a copy of that method. This is known as
function borrowing in JavaScript.
Here is an example based on the suggested code for getting the focus when the window demands the attention:
var GetFocus = class {
constructor() {
this.focusID = global.display.connect('window-demands-attention', this._onWindowDemandsAttention.bind(this));
}
_onWindowDemandsAttention(display, window) {
Main.activateWindow(window);
}
_destroy() {
global.display.disconnect(this.focusID);
}
}
The function was not working before because I was missing the .bind.
Hy I wrote a quick and dirty list ui in js and html that can be filtered:
https://jsfiddle.net/maxbit89/2jab4fa4/
So the usage of this looks like this (Fiddle line: 96):
var list = new ui_list(document.body, 200, 300, "Test");
var encoder = function(dom, value) {
console.log("begin encoding");
console.log(value)
dom.innerHTML = value.n;
}
list.add({'n': 1}, function() {
this.value.n++;
console.log(this.value.n);
// this.value = this.value;
}, encoder);
So what this basicaly does is create a List and adds a Element to it that has an Object: {'n': 1} as a value and a onClickHandler(second parameter on list.add) wich should increase the value by 1 (fiddle line: 104)
But it won't do this untill you uncomment the line 106 in the fiddle.
(Tested with FireFox 50.1.0, and Edge Browser)
Has any body an idea why js behaves like this?
In a much simplier example this works just fine:
var myObj= {
'onvalueChange' : function() {
console.log('value changed');
},
'print' : function() {
console.log('value:');
console.log(this.value);
console.log(this.value.n);
}
};
Object.defineProperty(myObj, "value", {
get: function() { return this._value; },
set: function(value) {
this.onvalueChange();
this._value = value;
}
});
myObj.value = {'n' : 1};
myObj.value.n++;
myObj.print();
First you have the setter defined like this:
set: function (value) {
this.encoder(this, value);
this._value = value;
}
that means that every time the value is set, the encoder will be called with the new value to update the equivalent DOM element.
But then inside the event listener function you have:
function() {
this.value.n++;
console.log(this.value.n);
//this.value = this.value;
}
where you think that this.value.n++ is setting the value (means it calls the setter which means the encoder will be called to update the DOM element). But it's not true. this.value.n++ is actually calling the getter. To explain more this:
this.value.n++;
is the same as:
var t = this.value; // call the getter
t.n++; // neither call the getter nor the setter. It just uses the reference (to the object) returned by the getter to set n
So, when you uncomment the line this.value = this.value;, the setter gets called, and the encoder gets called to update the DOM element.
So to fix the issue you have to either:
Make a call inside the getter to the encoder as you did for the setter (but this solution is very hacky as it will update the DOM element on every getter call even if nothing is being set).
Change this this.value.n++; to actually call the setter like: this.value = {n: this.value.n + 1}; (but this is hacky too as if value has a lot of key-value pairs then you have to enlist them all here just to set n).
Call the encoder inside the event listener which will be the best way to do it (or if you don't want to pass the parameters to it make another function (for example this.callEncoder()) that will call it and [you] call the new function instead inside the event listener).
if i have the below code , how can i change the isHTML property at any time while the application running ,i have tried the below and tried many javascript access ways and it fails also.
obj = new ss({
something: {
ishtml: myfunction(true),
},
});
document.getElementbyId("#id").onclick = function() {
myfunction(false);
}
function myfunction(bool) {
return bool;
}
after all of that when i use the application again it uses the intial values i send via the function
I was just going through the source of transit.js and came across the following fucntion ::
$.cssHooks['transit:transform'] = {
// The getter returns a `Transform` object.
get: function(elem) {
return $(elem).data('transform') || new Transform();
},
// The setter accepts a `Transform` object or a string.
set: function(elem, v) {
var value = v;
if (!(value instanceof Transform)) {
value = new Transform(value);
}
// We've seen the 3D version of Scale() not work in Chrome when the
// element being scaled extends outside of the viewport. Thus, we're
// forcing Chrome to not use the 3d transforms as well. Not sure if
// translate is affectede, but not risking it. Detection code from
// http://davidwalsh.name/detecting-google-chrome-javascript
if (support.transform === 'WebkitTransform' && !isChrome) {
elem.style[support.transform] = value.toString(true);
} else {
elem.style[support.transform] = value.toString();
}
$(elem).data('transform', value);
}
};
I understand the latter part of the function, but its really hard to understand the initial part of the function, the function can be found on git too , HERE .
Initially I see this, $.cssHooks['transit:transform'] what is that line really saying?
After that we have the below line of code I.E. the getter and setter method,
set: function(elem, v) {
But who is passing the elem and v inside the function, I don't see anything being passed?
Read about cssHooks at jQuery cssHooks
Look at the source code (search for hooks.get and hooks.set)
.cssHooks is an array of objects that contains getter and setters tha will be executed by .css(). Thats all.
$.cssHooks['transit:transform'] = {set: function(elem,value){}, get: function(elem){}}
equal:
$.cssHooks['transit:transform'] = {};
$.cssHooks['transit:transform'].set = function(elem, value){};
$.cssHooks['transit:transform'].get = function(elem){};
$(element).css('transit:transform',value)
comes to:
$.cssHooks['transit:transform'].set(element,value)
$(element).css('transit:transform')
comes to:
$.cssHooks['transit:transform'].get(element)
$.cssHooks['transit:transform'] = {set:function(){}, get: function(){} }
{...} is an object creation.get and set not executed at this moment.
They created {set:function(){}, get: function(){} }
So. Simply: .css() will execute set and get functions for hooked property.
If you want to know how real getters and setters works:
Object.defineProperty()
In Javascript, you can add/access to a property with this syntax :
myObject.myProperty
or with this syntax :
myObject['myProperty']
This is the same result
So your line
$.cssHooks['transit:transform']
just mean that we want to store an object (code between {} in your original post) inside the 'transit:transform' property which is inside the cssHooks property which is inside the $ object
This is the same things :
$['cssHooks']['transit:transform']
The reason why they use the [''] syntax is that transit:transform contains the ':' char which is not allowed if you want to access it this way :
$.cssHooks.transit:transform //doesn't work
EDIT:
To answer to your second question, i don't know...the code you are showing is just the 'description' of the "transit:transform' property
So, I have a large object called con in that object, I have many variables, numbered sort of like an excel sheet, b19, b20, b21, etc.
I am trying to return a value from each one, but when I do a console log, It logs the entire function, not just the return.
Here's how the object is set up:
var con = {
b13: function(){
return 12600.535*Math.sqrt((con.b14+459.4)/459.4)
},
b14: function(){
return 20;
}
}
$(document).ready(function(){
console.log(con.b13);
});
This outputs this into the console:
function(){
return 12600.535*Math.sqrt((con.b14+459.4)/459.4)
}
So how do I format this so that it outputs the actual number in the equation?
You need to make b13 and b14 properties with a getter function:
var con = {};
Object.defineProperty(con, "b13", {
get: function() {
return 12600.535*Math.sqrt((con.b14+459.4)/459.4);
}
});
Object.defineProperty(con, "b14", {
get: function() { return 20; }
});
This will cause con.b13 and con.b14 to call the given functions, returning whatever the functions return.
Try console.log(con.b13()); . You are logging the function definition not executing it.
you don't define the properties as functions...
var con = {
b13: 239487,
b12: 923748
};
edit: if some properties need to be functions you have to call them e.g. con.b14(), not con.b14 as a property
You can simply use es5 getters/setters.
var con = {
get b13() {
return 12600.535*Math.sqrt((con.b14+459.4)/459.4);
},
get b14() {
return 20;
}
};
The problem is that your object's properties are functions, but you are trying to call them as if they were values.
For example, if you wanted correctly log con.b13's value to the console, you would need to change the command to:
console.log(con.b13());
What this does is get what con.b13 returns rather than what it is.
If you don't want to go through the hassle of adding a () next to every reference, you can modify the object and define getters like this:
var con = {
get b13() {
return 12600.535 * Math.sqrt((con.b14 + 459.4) / 459.4)
},
get b14() {
return 20;
}
}
If you define the object like this, your original command console.log(con.b13) will work as intended.