Is there a way to retrieve the names/values of all global variables on a page?
I would like to write a javascript function to do the following:
Find all global variables prefixed with 'xxx_' and stick them in an array (for e.g.)
build a query string using the name value pairs as follows:
xxx_glob_var1=value1&xxx_glob_var2=value2 etc
How do I do this?
Or you could simply run;
Object.keys(window);
It will show a few extra globals (~5), but far fewer than the for (var i in window) answer.
Object.keys is available in Chrome 5+, Firefox 4+, IE 9+, and Opera 12, ty #rink.attendant.6
Something like this:
function getGlobalProperties(prefix) {
var keyValues = [], global = window; // window for browser environments
for (var prop in global) {
if (prop.indexOf(prefix) == 0) // check the prefix
keyValues.push(prop + "=" + global[prop]);
}
return keyValues.join('&'); // build the string
}
A test usage:
var xxx_foo = "foo";
xxx_bar = "bar";
window.xxx_baz = "baz";
var test = getGlobalProperties('xxx_');
// test contains "xxx_baz=baz&xxx_bar=bar&xxx_foo=foo"
In some cases you may want to find non-enumerable properties; therefore for..in won't work (spec, about chrome) and neither would Object.keys as both only use enumerable keys. Notice that for..in is different to in but we can't use this to iterate.
Here is a solution using Object.getOwnPropertyNames (compatibility is IE9+). I've also added support for when you do only want enumerable properties or if you want to search another in context (not global).
function findPrefixed(prefix, context, enumerableOnly) {
var i = prefix.length;
context = context || window;
if (enumerableOnly) return Object.keys(context).filter( function (e) {return e.slice(0,i) === prefix;} );
else return Object.getOwnPropertyNames(context).filter( function (e) {return e.slice(0,i) === prefix;} );
}
findPrefixed('webkit');
// ["webkitAudioContext", "webkitRTCPeerConnection", "webkitMediaStream", etc..
Then if you want to join e.g.
findPrefixed('webkit').map(function (e) {return e+'='+window[e];}).join('&');
// "webkitAudioContext=function AudioContext() { [native code] }&webkitRTCPeerConnection=function RTCPeerConnection() etc..
You could do something like this:
for (var i in window) {
// i is the variable name
// window[i] is the value of the variable
}
Though with this, you'll get a bunch of extra DOM properties attached to window.
In my case, the two top answers didn't work, thus I am adding another answer, to highlight the comment of Dan Dascalescu:
Object.keys(window);
When I executed it, it gave:
top,location,document,window,external,chrome,$,jQuery,matchMedia,jQuery1113010234049730934203,match_exists,player_exists,add_me,isLetter,create_match,delete_me,waiting,unsure,refresh,delete_match,jsfunction,check,set_global,autoheight,updateTextbox,update_match,update_player,alertify,swal,sweetAlert,save_match,$body,value_or_null,player,position,ability,obj_need_save,xxx_saves,previousActiveElement
where the player, positon, ability, obj_need_save, xx_saves are my actual global variables.
I just saw that there exists a similar answer to another question.
Related
In Chrome Developer Tools, in the console, if I type window and hit enter, I get a long list of global variables that are properties of the window object. Is there any way to filter this down to those that are added by the user and not already built into the window object?
// setTimeout is needed and is being used here just if the property adding and the checking will be done in sequence. To avoid getting the same reference values on the current time lapse. Check the answer code
// Get current window Properties;
var windowInitProperties = Object.getOwnPropertyNames(window);
setTimeout(() => window.newProperty = 'newProperty', 0)
setTimeout(() => {
// List new Properties;
console.log(
Object.getOwnPropertyNames(window).filter(property => {
return windowInitProperties.indexOf(property) < 0;
})
);
}, 0)
// Get current window Properties;
var windowInitProperties = Object.getOwnPropertyNames(window);
// New property added to window
var newProperty = 'newProperty';
// List new Properties;
console.log(
Object.getOwnPropertyNames(window).filter(property => {
return windowInitProperties.indexOf(property) < 0;
})
);
Mind that Object.getOwnPropertyNames instead of Object.keys is needed to get even the properties that are enumerable: false.
Before adding your global variable cache the core/predefined variable names. After adding your new global variable - you can compare the new list with old one and print the new global variables.
var predefined_variables = Object.keys(window);
window.newone = 'test';
window.xyz = 'testXYZ';
var new_variables = Object.keys(window).filter(function(key){
return predefined_variables.indexOf(key)<0;
});
console.log(new_variables);
//["newone", "xyz"]
I think it's not possible, and even if it's was possible.it's a bad practise.
Instead, you can create a namespace on window object like following:
window.myApp=window.myApp || {};
myApp.variable1=value1;
...
myApp.variableN=valueN;
Unless the chrome team builds something in for this particular case, then the answer is no.
The window is simply an object. The properties added doesnt keep any information or metadata about who added it, when, etc.
If you want (and probably should), prefix properties you're adding to the window. This will prevent collisions with other libraries making use of window, and then you could write a simple for-in loop to grab only the properties/values that use your prefix.
This question just got upvoted so can update question with what I did
I solved it by iterating over the window object (or user specified object root) and when I found the correct instance I backtracked and got the name from the index. The final solution can be found here
https://github.com/AndersMalmgren/Knockout.BindingConventions
Update end
I'm planning on writing a convention over configuration template source engine for KnockoutJS / MVC.
I'm started with a little client side POC and ran into a show stopper right away
My plan is use this syntax or something similar
MyApp.EditCustomersViewModel = function() {
ko.templates.loadView(this);
};
When doing this it will check the tamplate cache or fetch the templates from server using the object name as key.
The problem is I cant get the name of the prototype object, i tried this
Object.prototype.getName = function() {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec((this).constructor.toString());
return (results && results.length > 1) ? results[1] : "";
};
If works for objects defined like this
function MyClass() {
}
If you add a prototype to the above object it will not work, or if you define it like this
MyApp = {};
MyApp.MyClass = function() {
};
Prototype and scoping is two musts so this is a showstopper, any ideas?
Fiddle: http://jsfiddle.net/aRWLA/
edit: The background for this is like this.
On the server you have structure like this
Templates\ [ViewName]\index.html
Templates\ [ViewName]\sub-model-template.html
on the client you will do
MyApp.EditCustomersViewModel = function() {
ko.templates.loadView(this);
};
which will generate a ajax request with the objects name as key, which will fetch all the templates for the view in question
Only hoisted functions (function someFunc() {) have a retrievable name.
Assigned functions do not, because you are not technically naming the function but creating an anonymous function and assigning a reference to it (in the memory) to a named variable.
So it's the var, not the function, that is named.
This makes the very idea of retrieving function names pretty much a none-starter, since in any vaguely mature pattern you'll be writing methods, not hoisted functions - and methods of course are assigned functions.
Named expressions (see other answers) are a partial workaround but these have other issues - not least lack of support in older IEs.
(Sidenote: I've long expected browser vendors to build around this such that the names of assigned functions became retrievable, but no joy yet AFAIK.)
I think you problem in improper replacing function prototype: if you replace function prototype object then you must preserve constructor member in prototype:
function Test1() {
}
Test1.prototype={
constructor: Test1
};
MyApp={};
MyApp.MyClass=function MyClass(){
};
MyApp.MyClass.prototype={
constructor: MyApp.MyClass
};
Your example: http://jsfiddle.net/aRWLA/1/
Modified example: http://jsfiddle.net/aRWLA/2/
You can make use of named function expressions:
MyApp.MyClass = function MyClass() { ... };
But note that (suprise) they don't work correctly in all versions of IE.
See: http://kangax.github.com/nfe/
THIS DOES NOT ANSWER THE QUESTION
However, the code might be useful to other people, so I'm leaving it here, just in case. I don't expect upvotes, but please don't abuse it for downvoting either. Thanks.
I don't know your use case, as such I think you've got a design issue - the problem you describe shouldn't happen in practice.
But let's say you do need to have this working. An easy way to do what you need would be something like:
function findNamed(obj, fn){
for(var p in obj)
if(obj[p] === fn)
return p;
return false;
}
var m = {};
m.MyClass = function() {};
console.log(findNamed(m, m.MyClass));
Of course, the solution could be made into a more appropriate OOP form, but this is just to give an idea.
To replicate your use case, it would look like:
m.MyClass = function() {
findNamed(this, arguments.callee);
};
So, the final code is:
Object.prototype.getNameOfCall = function(fn) {
for(var p in this)
if(this[p] === fn)
return p;
throw "Callback not in object.";
};
var m = {};
m.MyClass = function() {
console.log(this.getNameOfCall(arguments.callee)); // MyClass
};
m.MyClass(); // test it out
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
}
Because jQuery is a widely used and mature collaborative effort, I can't help but to look at its source for guidance in writing better Javascript. I use the jQuery library all the time along with my PHP applications, but when I look under the hood of this rather sophisticated library I realize just how much I still don't understand about Javascript. Lo, I have a few questions for the SO community. First of all, consider the following code...
$('#element').attr('alt', 'Ivan is SUPER hungry! lolz');
vs
$('#element').attr({'alt': 'Ivan is an ugly monster! omfgz'});
Now, is this to say that the attr() method was designed to accept EITHER an attribute name, an attribute name and a value, or a pair-value map? Can someone give me a short explanation of what a map actually is and the important ways that it differs from an array in Javascript?
Moving on, the whole library is wrapped in this business...
(function(window, undefined) { /* jQuery */ })(window);
I get that the wrapped parentheses cause a behavior similar to body onLoad="function();", but what is this practice called and is it any different than using the onLoad event handler? Also, I can't make heads or tails of the (window) bit there at the end. What exactly is happening with the window object here?
Am I wrong in the assessment that objects are no different than functions in Javascript? Please correct me if I'm wrong on this but $() is the all encompassing jQuery object, but it looks just like a method. Here's another quick question with a code example...
$('#element').attr('alt', 'Adopt a Phantom Cougar from Your Local ASPCA');
... Should look something like this on the inside (maybe I'm wrong about this)...
function $(var element = null) {
if (element != null) {
function attr(var attribute = null, var value = null) {
/* stuff that does things */
}
}
}
Is this the standing procedure for defining objects and their child methods and properties in Javascript? Comparing Javascript to PHP, do you use a period . the same way you would use -> to retrieve a method from an object?
I apologize for this being a bit lengthy, but answers to these questions will reveal a great deal to me about jQuery and Javascript in general. Thanks!
1. Method overloading
$('#element').attr('alt', 'Ivan is SUPER hungry! lolz');
vs
$('#element').attr({'alt': 'Ivan is an ugly monster! omfgz'});
var attr = function (key, value) {
// is first argument an object / map ?
if (typeof key === "object") {
// for each key value pair
for (var k in key) {
// recursively call it.
attr(k, key[k]);
}
} else {
// do magic with key and value
}
}
2. Closures
(function(window, undefined) { /* jQuery */ })(window);
Is not used as an onload handler. It's simply creating new scope inside a function.
This means that var foo is a local variable rather then a global one. It's also creating a real undefined variable to use since Parameters that are not specified passes in undefined
This gaurds againts window.undefined = true which is valid / allowed.
the (window) bit there at the end. What exactly is happening with the window object here?
It's micro optimising window access by making it local. Local variable access is about 0.01% faster then global variable access
Am I wrong in the assessment that objects are no different than functions in Javascript?
Yes and no. All functions are objects. $() just returns a new jQuery object because internally it calls return new jQuery.fn.init();
3. Your snippet
function $(var element = null) {
Javascript does not support default parameter values or optional parameters. Standard practice to emulate this is as follows
function f(o) {
o != null || (o = "default");
}
Comparing Javascript to PHP, do you use a period . the same way you would use -> to retrieve a method from an object?
You can access properties on an object using foo.property or foo["property"] a property can be any type including functions / methods.
4. Miscellanous Questions hidden in your question
Can someone give me a short explanation of what a map actually is and the important ways that it differs from an array in Javascript?
An array is created using var a = [] it simply contains a list of key value pairs where all the keys are positive numbers. It also has all the Array methods. Arrays are also objects.
A map is just an object. An object is simply a bag of key value pairs. You assign some data under a key on the object. This data can be of any type.
For attr, if you give an object instead of a key value pair it will loop on each property.
Look for attr: in jQuery's code, then you'll see it use access. Then look for access: and you will see there is a check on the type of key if it is an object, start a loop.
The wrapping in a function, is to prevent all the code inside to be accessed from outside, and cause unwanted problems. The only parameters that are passed are window that allow to set globals and access the DOM. The undefined I guess it is to make the check on this special value quicker.
I read sometimes jQuery but I didn't start with it, may be you should get some good books to make you an idea first of what some advanced features Javascript has, and then apply your knowledge to the specifics of jQuery.
1 - Yes attr can accept a attribute name for getting a value, a name and a value for setting one value or a map of attribute names and values for settings more than one attribute
2 - A map is basically a JavaScript object e.g:
var map = {
'key1' : 'value1',
'key2' : 'value2'
};
3 - (function(window, undefined) { /* jQuery */ })(window); is something called an anonymous function as it doesn't have a name. In this case it also executes straight away.
A simple example would be:
function test(){
...
}
test();
//As an anonymous function it would be:
(function(){
...
}();
//And it you wanted to pass variables:
function test(abc){
...
}
test(abc);
//As an anonymous function it would be:
(function(abc){
...
}(abc);
this would make it different to the load event, as it is a function not an event.
4 - window is passed as a variable, as it is used internally within jQuery
5 - Objects and functions the same, as everything in JavaScript is an object. jQuery does something like this:
var obj = {
"init" : function(){
}
}
6 - Yes you can use . to retrieve a value on an object but you can also use [] e.g:
var map = {
"test" : 1
}
map.test //1
map["test"] //1
I hope this answers your many questions, let me know if I've missed anything out.
jQuery 1.6.1
The test is typeof key === "object"
if that is true, then you passed a { .... }
jQuery.fn.extend({
attr: function( name, value ) {
return jQuery.access( this, name, value, true, jQuery.attr );
},
// Mutifunctional method to get and set values to a collection
// The value/s can be optionally by executed if its a function
access: function( elems, key, value, exec, fn, pass ) {
var length = elems.length;
// Setting many attributes
if ( typeof key === "object" ) {
for ( var k in key ) {
jQuery.access( elems, k, key[k], exec, fn, value );
}
return elems;
}
// Setting one attribute
if ( value !== undefined ) {
// Optionally, function values get executed if exec is true
exec = !pass && exec && jQuery.isFunction(value);
for ( var i = 0; i < length; i++ ) {
fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
}
return elems;
}
// Getting an attribute
return length ? fn( elems[0], key ) : undefined;
},
This question already has answers here:
Are there constants in JavaScript?
(33 answers)
Closed 6 years ago.
I want to declare string constants in JavaScript.
Is there is a way to do that?
Many browsers' implementations (and Node) have constants, used with const.
const SOME_VALUE = "Your string";
This const means that you can't reassign it to any other value.
Check the compatibility notes to see if your targeted browsers are supported.
Alternatively, you could also modify the first example, using defineProperty() or its friends and make the writable property false. This will mean the variable's contents can not be changed, like a constant.
Are you using JQuery? Do you want to use the constants in multiple javascript files? Then read on. (This is my answer for a related JQuery question)
There is a handy jQuery method called 'getScript'. Make sure you use the same relative path that you would if accessing the file from your html/jsp/etc files (i.e. the path is NOT relative to where you place the getScript method, but instead relative to your domain path). For example, for an app at localhost:8080/myDomain:
$(document).ready(function() {
$.getScript('/myDomain/myScriptsDir/constants.js');
...
then, if you have this in a file called constants.js:
var jsEnum = { //not really an enum, just an object that serves a similar purpose
FOO : "foofoo",
BAR : "barbar",
}
You can now print out 'foofoo' with
jsEnum.FOO
There's no constants in JavaScript, but to declare a literal all you have to do is:
var myString = "Hello World";
I'm not sure what you mean by store them in a resource file; that's not a JavaScript concept.
Of course, this wasn't an option when the OP submitted the question, but ECMAScript 6 now also allows for constants by way of the "const" keyword:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
You can see ECMAScript 6 adoption here.
Standard freeze function of built-in Object can be used to freeze an object containing constants.
var obj = {
constant_1 : 'value_1'
};
Object.freeze(obj);
obj.constant_1 = 'value_2'; //Silently does nothing
obj.constant_2 = 'value_3'; //Silently does nothing
In strict mode, setting values on immutable object throws TypeError. For more details, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
Well, you can do it like so:
(function() {
var localByaka;
Object.defineProperty(window, 'Byaka', {
get: function() {
return localByaka;
},
set: function(val) {
localByaka = window.Byaka || val;
}
});
}());
window.Byaka = "foo"; //set constant
window.Byaka = "bar"; // try resetting it for shits and giggles
window.Byaka; // will allways return foo!
If you do this as above in global scope this will be a true constant, because you cannot overwrite the window object.
I've created a library to create constants and immutable objects in javascript. Its still version 0.2 but it does the trick nicely. http://beckafly.github.io/insulatejs
Starting ECMAScript 2015 (a.k.a ES6), you can use const
const constantString = 'Hello';
But not all browsers/servers support this yet. In order to support this, use a polyfill library like Babel.
So many ways to skin this cat. You can do this in a closure. This code will give you a read-only , namespaced way to have constants. Just declare them in the Public area.
//Namespaced Constants
var MyAppName;
//MyAppName Namespace
(function (MyAppName) {
//MyAppName.Constants Namespace
(function (Constants) {
//Private
function createConstant(name, val) {
Object.defineProperty(MyAppName.Constants, name, {
value: val,
writable: false
});
}
//Public
Constants.FOO = createConstant("FOO", 1);
Constants.FOO2 = createConstant("FOO2", 1);
MyAppName.Constants = Constants;
})(MyAppName.Constants || (MyAppName.Constants = {}));
})(MyAppName || (MyAppName = {}));
Usage:
console.log(MyAppName.Constants.FOO); //prints 1
MyAppName.Constants.FOO = 2;
console.log(MyAppName.Constants.FOO); //does not change - still prints 1
You can use freeze method of Object to create a constant. For example:
var configObj ={timeOut :36000};
Object.freeze(configObj);
In this way you can not alter the configObj.
Use global namespace or global object like Constants.
var Constants = {};
And using defineObject write function which will add all properties to that object and assign value to it.
function createConstant (prop, value) {
Object.defineProperty(Constants , prop, {
value: value,
writable: false
});
};
Just declare variable outside of scope of any js function. Such variables will be global.