I'm trying to find a generic way of getting the name of Constructors. My goal is to create a Convention over configuration framework for KnockoutJS
My idea is to iterate over all objects in the window and when I find the contructor i'm looking for then I can use the index to get the name of the contructor
The code sofar
(function() {
constructors = {};
window.findConstructorName = function(instance) {
var constructor = instance.constructor;
var name = constructors[constructor];
if(name !== undefined) {
return name;
}
var traversed = [];
var nestedFind = function(root) {
if(typeof root == "function" || traversed[root]) {
return
}
traversed[root] = true;
for(var index in root) {
if(root[index] == constructor) {
return index;
}
var found = nestedFind(root[index]);
if(found !== undefined) {
return found;
}
}
}
name = nestedFind(window);
constructors[constructor] = name;
return name;
}
})();
var MyApp = {};
MyApp.Foo = function() {
};
var instance = new MyApp.Foo();
console.log(findConstructorName(instance));
The problem is that I get a Permission denied to access property 'toString' Exception, and i cant even try catch so see which object is causing the problem
Fiddle http://jsfiddle.net/4ZwaV/
Final version in this fiddle
http://jsfiddle.net/2Uvd5/8/
Check here for the embryo of my Convention over configuration plugin
https://github.com/AndersMalmgren/Knockout.BindingConventions
Edit2:
JSFiddle
This solves everything except for one thing: var MyApp = {}; doesn't add it to the window-object. Changing that to window.MyApp = {}; makes it completely working (even within an IFrame).
Edit1:
JSFiddle
Adding to the array by setting the key name requires the key name to be a string so Javascript will automatically call. toString() on your suggested keyname which will fail for certain objects. Instead use .push() to add elements of any type to an array and then .indexOf() to check if it already exists.
Do note that the jsFiddle still breaks because of being placed in an iframe. Opening it in a new tab solves that.
My previous answer (which proved to be invalid when I tried to verify it in your jsFiddle):
You need to check if the constructor is an exact Object. If it is then calling .toString() on it will cause a security exception which I found to be kinda hard to debug. Here's a function I use to get the type of an object in a var-dumper I use.
function GetTypeOfObject(obj) {
if (obj.constructor === window.Object)
return '[object]';
else
return obj.constructor.toString();
}
Related
I have a program in which I wish to prevent anyone from accessing String object or any of its prototypes and I can't seem to find how to do that.
Tried Object.seal, Object.freeze and they both obviously don't work (since they don't prevent you from accessing properties already present, so feeling a little lost on how to do that.
Tried looking it up on internet but after half an hour, all I have got is different way to access properties and 3 ways of adding new stuff and locking but 0 ways to make it be inaccessible
I tried to delete as well but that one was.....
You can use a symbol as a key and store your object in that object. So It will be accessible just in scope you defined the symbol.
function addPrivateKey(a, value) {
let sym1 = Symbol()
a[sym1] = value
console.log(a)
console.log(a[sym1])
}
let a = {};
addPrivateKey(a, 2)
console.log(Object.keys(a))
Define a private scope and store your keys there. The values are accessible just with their hints!
class PrivateScope {
glob = {};
#keyToSym = {};
counter = 0;
get(hint) {
return this.glob[this.#keyToSym[hint]]
}
set(value) {
let sym1 = Symbol()
this.glob[sym1] = value
this.#keyToSym[this.counter] = sym1;
return this.counter ++;
}
}
const myPrivateScope = new PrivateScope();
let hint = myPrivateScope.set(2)
console.log(
myPrivateScope.get(hint)
)
console.log(myPrivateScope.glob)
I have for some time wondered if there is any quicker way to instantiate a chain of objects in in javascript.
Lets say that we for instance have the following "chain of objects"
window.myobject1.myobject2.myobject3 = {}
This will ofcourse not work.. since object1 and object2 are not instantiated..
however.. to get this to work.. I would have to do something like:
window.myobject1 = {}
window.myobject1.myobject2 = {}
window.myobject1.myobject2.myobject3 = {}
Which simply just seems silly.. in a more realistic case.. lets say we have
window.server.responses.currentuser.id
where server,responses and currentuser simply act as "namespaces"/empty enities..
Would there be any way where I can tell javascript to instantiate the whole chain as objects?.. so I don't need to instantiate each part of the chain on a new line?
This might be a bad example but I guess you get it..
for instance I might also have:
window.server.responses.currentuser.id
window.server.responses.theotherusers.personone.id
window.server.responses.labels.personname
etc..
Thanks in advance!
I've answered this question before but can't seem to find it so can't mark this as duplicate (hehe). Anyway, you can basically do it with a function:
function deep_set (obj,path,value) {
var name = path.shift();
if (path.length) {
if (typeof obj[name] == undefined) {
obj[name] = {};
}
if (typeof obj[name] == 'string' || typeof obj[name] == 'number') {
throw new Error('attempted to access string or number as object');
}
deep_set(obj[name],path,value);
}
else {
obj[name] = value;
}
}
So you can now do:
deep_set(window,['server','responses','currentuser','id'],3);
without having to manually test typeof == undefined at each step.
With a little change you can have the API look any way you want:
window.deep_set(['server','responses','currentuser','id'],3);
// or
deep_set(window,'server','responses','currentuser','id',3);
// or
deep_set(window,'server.responses.currentuser.id',3);
This is such a fundamental question, that I'm sure it's a duplicate, so I apologize in advance, but is this how I write an object such that I use by saying:
myApplication.myFirstMethod(x);
x = myApplication.myFirstMethod();
Here's the code:
myApplication = {};
(function() {
myApplication.myFirstMethod = function() {
var local = {};
if (arguments.length) {
local.result = arguments[0];
}
return local.result;
}
myApplication.mySecondMethod = function() {
var local = {};
if (arguments.length) {
local.result = arguments[0];
}
return local.result;
}
})();
jsFiddle Demo
A more object oriented approach would be to use instantiation and prototype.
Setup
var Application = function(){
this.local = {};
};
Application.prototype.Value = function(){
if (arguments.length) {
this.local.result = arguments[0];
}else{
return this.local.result;
}
};
Used
var app = new Application();
app.Value(6);
alert(app.Value());//6
From a jQuery point of view, they will first screen to see if there are arguments, this code is direct from their source for the val function:
val: function( value ) {
if ( !arguments.length ) {
var elem = this[0];
...
It then goes on to use the element's native API and some other metrics to get the value for the element (In general, the only type of elements which will return a value from val are going to be elements such as input, select, etc. - form elements basically).
At the end of the if block it attempts to return various results based on if it found a value attached to the element (or set of elements). This guarantees that the clause of "setting" never executes when a "get" is encountered. If the case is that "set" is being used it goes through a slightly complex set of code to properly set a value to the element.
The reason that the code shows val: function() is because it is part of an object which is being used to "extend" the jQuery prototype using jQuery's extend functionality.
This is the exact code in a jsfiddle of jQuery's val function
There are many patterns for creating objects like this and everyone has their favorites. Addy Osmani does an excellent job of summarizing the most popular patterns in his Javascript Design Patterns "book". Specifically, this section:
http://addyosmani.com/resources/essentialjsdesignpatterns/book/#designpatternsjavascript
I reread this semi-annualy just to make sure I'm keeping all the patterns in my quiver.
I have a class in JS with field
Widget = function ()
{
this.Attributes = []; // key=value
}
and another class iherited from Widget
BusinessStatisticWidget = function ()
{
// some code
};
BusinessStatisticWidget.prototype = new Widget();
At initialization stage I have assigned this Attributes field with values (only once) and at some point Atttibutes field becomes empty:
BusinessStatisticWidget.prototype.SetEventsOnControls = function ()
{
var dropDown = document.getElementById(this.DropDownName + this.type + "Id");
var _this = this; // **Not empty here**
dropDown.addEventListener("change", function (event)
{
// **Not empty even here**
_this.CalculateAndSetTimeRangeForTimeSpan(event.target.value);
}, false);
}
BusinessStatisticWidget.prototype.CalculateAndSetTimeRangeForTimeSpan = function (val)
{
// **Empty here**
if (this.Attributes["fromDate"].value != '' && this.Attributes["toDate"].value != '')
{}
}
The code above works fine in Chrome and IE10 (I mean that array is not empty) but dont work in Firefox(20.0.1)
As array is empty I get TypeError: this.Attributes.fromDate is undefined.
And I dont know why it is empty and how to fix this.
There are multiple problems with your code:
Don't use arrays for arbitrary key, value pairs. Use only numerical keys for arrays.
Each instance will share the same Attributes array. This is usually not the desired behaviour.
Solutions:
Use an object instead.
Setup inheritance properly and call the parent constructor in the child constructor.
Code:
Widget = function () {
this.Attributes = {}; // use an pbject
};
var BusinessStatisticWidget = function () {
// call parent constructor
Widget.call(this);
// some code
};
// set up inheritance
BusinessStatisticWidget.prototype = Object.create(Widget.prototype);
More information (and polyfill) about Object.create.
Now, I don't know if that fixes your problem, but it makes your code at least more correct so that finding the issue becomes easier. I recommend to learn how to debug JavaScript.
I am posting this in hopes that someone might have dealt with a similar problem.
I am using a javascript object that encapsulates paramaters to intialize greater objects in my code, like so :
function MyObject(setup)
{
this.mysetup = setup;
if(typeof this.mysetup == "undefined") { this.mysetup = {} }
if(typeof this.mysetup.stringParameter == "undefined")
{
this.mysetup.stringParameter="string default value"
}
if(typeof this.mysetup.objParameter == "undefined")
{
this.mysetup.objParameter == {}
}
else
{
if(typeof this.mysetup.objParameter.member1 == "undefined")
{
this.mysetup.objParameter.member1 = "member1 default value"
}
}
// ...and so on
}
This way I can make sure not every parameter needs to be in setup, and still MyObject can resort to default values for what is missing.
However, this is a tedious thing to write and quite error prone. So I thought I'd try for a solution that checks the setup against a setupPrototype:
function MyObject(setup)
{
this.setupPrototype = {
stringParameter : "string default value",
objectParameter : { member1 : "member default value"}
}
}
and try to compare the setup against this.setupPrototype.
The function I'm putting together for this purpose looks like
parseSetup = function (obj, objPrototype)
{
var returnedObj = {};
var hasMembers = false;
if(typeof obj=="undefined")
{
returnedObj = objPrototype;
return returnedObj;
}
for(member in objPrototype)
{
hasMembers = true;
//if prototype member is not part of initialization object
if (typeof obj[member]=="undefined")
{
returnedObj[member] = objPrototype[member];
}
else
{
if(objPrototype[member] instanceof Object)
{
if(objPrototype[member] instanceof Array)
{
returnedObj[member]=[];
for(var i=0; i<objPrototype[member].length; i++)
{
returnedObj[member].push(parseSetup(obj[member][i], objPrototype[member][i]))
}
}
else{
returnedObj[member] = parseSetup(obj[member], objPrototype[member])
}
}
else
returnedObj[member] = obj[member];
}
}
if(!hasMembers)
{
if (typeof obj == "undefined")
{
returnedObj = objPrototype;
}
else
returnedObj = obj;
}
return returnedObj;
}
This however is still not up to par.
An additional issue, which I'm debating is whether the original 'setup' should retain any of its own initial properties, or just have whatever is in the prototype. Also, it would be pointless to require that the prototype itself be aware of every possible value the setup might contain, especially for deep nested objects.
So my question is, are you aware of any proper way to solve this problem and end up with a setup object that, where its parameters are missing, can get default values from the prototype, but also not lose its own where they somehow need to be kept?
Many thanks
I would recommend using jQuery and then taking advantage of the $.extend() function, as described on the jQuery plugins page. Basically, you define your default parameters as an object within the constructor method, and then use $.extend() to overwrite only the properties that are supplied in the parameter to your function.
So you might end up with something like:
var MyObject = function (options) {
this.defaultOptions = {
stringParameter: "string default value",
objParameter: {}
};
this.options = $.extend(true, this.defaultOptions, options);
};
To instantiate with the default parameters:
var obj1 = new MyObject({});
To instantiate with an overridden stringParameter:
var obj2 = new MyObject({stringParameter: 'overridden value'});
You can see a demo of this in action here.