I'm trying to understand the fundamentals of object literals
window.Test = ({
attribute1:'This is',
attribute2:'a test',
function1: function(){
alert(this.attribute1 + ' ' + this.attribute2);
}
});
//TEST 1
Test.function1(); // "This is a test"
//TEST 2
var tester = new Test(); //ERROR: Object is not a function
tester.function1();
If I understand correctly window.Test = creates a global variable in the window object.
It would be the same as var Test = . Therefore it's logical that TEST1 works.
In TEST2 I try to instantiate the literal but this is not possible because it's a variable. I got the idea from Backbone.js where the following code does work:
window.Product = Backbone.Model.extend({});
var p = new Product();
I would expect Product to be a variable here as well, so no way to instantiate it.
Can anyone explain the difference between the Backbone example and my example? It seems I'm missing out on some fundamental understanding of literals.
First of all, this has nothing to do with JSON. That is a text format for representing objects. What you have is an object literal in Javascript. The JSON format is based on the Javascript syntax, but it's not the same thing.
You can't instantiate an object literal, because it is already an instance.
What the backbone extend method does is that it creates a function that will create an object. The extend method will return a function that you can use to create an instance because it will copy everything from the Model object into its own object.
yes it is not a function, it is a js object and to clone it use this :
window.Test = ({
attribute1:'This is',
attribute2:'a test',
function1: function(){
alert(this.attribute1 + ' ' + this.attribute2);
}
});
//TEST 1
Test.function1(); // "This is a test"
//TEST 2
var tester = $.extend(true,{}, Test);
tester.function1();
Reference : here
Fiddle : here
object literals are already an instantiated object
var a = {}
is in this regard equivalent to:
var a = new Object()
so new {} is equivalent to new (new Object())
the new-keyword instantiates object from constructors. You can't instantiate something from an object that already is an instance.
Related
Consider how JavaScript's Date constructor creates an object that returns a default string when referenced directly:
var date = new Date();
document.write(date); // Outputs string: Mon May 23 2016 08:48:14 GMT-0400 (EDT)
// Expected output: [object Object]
document.write('<br/>', date.getFullYear()); // Can call methods as expected.
document.write('<br/>', date.toString());
According to MDN documentation:
If no arguments are provided, the constructor creates a JavaScript Date object for the current date and time according to system settings.
(emphasis mine)
The Date constructor returns an object, yet when that object is referenced directly, it returns a string representing the current date and time instead of a representation of the methods and properties as expected.
How can I achieve the same behavior with an object constructor of my own creation?
For example:
// My CoolObj constructor function
var CoolObj = function () {
var self = this;
var i = 0;
this.coolMethod = function () {
i += 1;
return self.coolProperty + ' and increment ' + i;
};
this.coolProperty = 'My cool string';
}
var myCoolObj = new CoolObj(); // Instantiate new object from constructor;
// Just like `var date = new Date();` above.
document.write(myCoolObj); // Outputs [object Object];
// I want to output a string, like Date does.
// For example: 'My cool direct-reference string.'
document.write('<br/>', myCoolObj.coolProperty); // Can call properties...
document.write('<br/>', myCoolObj.coolMethod()); // ...and methods as expected.
I'd like it to return a string of some kind when it is referenced directly, while providing the ability to call its methods and properties as normal.
UPDATE:
The linked question does provide the answer:
Is it possible to override JavaScript's toString() function to provide meaningful output for debugging?
tl;dr: Define CoolObj.prototype.toString which will get called by functions like console.log and document.write that attempt to cast objects to a string before output.
// My CoolObj constructor function
var CoolObj = function () {
var self = this;
var i = 0;
this.coolMethod = function () {
i += 1;
return self.coolProperty + ' and increment ' + i;
};
this.coolProperty = 'My cool string';
}
// Define a custom `toString` method on the constructor prototype
CoolObj.prototype.toString = function () {
return 'My cool direct-reference string.';
}
var myCoolObj = new CoolObj(); // Instantiate new object from constructor;
// Just like `var date = new Date();` above.
document.write(myCoolObj); // Outputs [object Object];
// I want to output a string, like Date does.
// For example: 'My cool direct-reference string.'
document.write('<br/>', myCoolObj.coolProperty); // Can call properties...
document.write('<br/>', myCoolObj.coolMethod()); // ...and methods as expected.
I am not seeking help for specifying string format for objects in console.
But that's the behaviour you are seeing. There is no such thing as a "default return statement for objects".
Consider how JavaScript's Date constructor creates an object that returns a default string when referenced directly
It doesn't. It just creates an object. A special native Date object maybe, but there's nothing about "default strings".
It really is only the console (console.log) that formats these native Date instances special.
There is nothing you can do to achieve that yourself for arbitrary objects, what you are asking for is impossible.
In this simple example, why do new and Object.create behave differently?
var test=function(name){
this.name=name
};
var test1= new test("AAA");
test1.name;//AAA
var test2=Object.create(test);
test2.name="AAA";
typeof(test2);//Object
test2.name;//"" (empty string).
Why is test2.name empty?
Object.create expects an Object as it's first argument for the prototype chain, not a function (or constructor in your case).
It won't complain if you pass a function, but it means that certain extra things will be inherited by your created Object, for example, the non-writability of function names.
The reason you're getting an empty string is because test is an anonymous function, so test.name is "". As I said above, this is non-writable, so
test.name = 'foo';
test.name; // still ""
If you had used a named function expression for test, this would have been more obvious.
var test = function foobar() {},
ex = Object.create(test);
ex.name; // "foobar"
EDIT a function that behaves like new for test using Object.create would look like this
function myNew() {
var o = Object.create(test.prototype); // set up prototype inheritance
test.apply(o, arguments); // then construct
return o;
}
// and using it
var test3 = myNew('AAA');
test3.name; // "AAA"
test3.name = 'BBB';
test3.name; // "BBB"
This pattern is not guaranteed to work with DOM constructors.
The word "name" is "almost reserved" in JavaScript. If you try a normal attribute name, it should work. For example,
var test=function(name){this.name=name};
var test1= new test("AAA");
test1.name;//AAA
var test2=Object.create(test);
test2.name2="AAA";
typeof(test2);//Object
console.log(test2.name2);//"AAA"
For difference between the two ways of creating objects, this page shows some examples with explanation.
I understand that there are two ways of creating classes in JavaScript
var MyObj = function(val)
{
this.vari = val;
}
Where val will be a non static member.
Whereas,
var MyObj = new Object();
MyObj.vari = "";
This is a single object so members of it here will act like static members. My question is that how do we have both static as well as non static content in same class?
There are no classes in JavaScript, only objects.
When you create a new object you are "extending" from the function's prototype, not the function itself. In order to make a variable or function appear to be static you would have to attach it to the function used to create the object, and not its prototype.
js> var Foo = function(){ this.member = "member"; };
js> Foo.staticMember = "staticMember";
js> var f = new Foo();
js> Foo.member;
undefined
js> Foo.staticMember;
"staticMember"
js> f.member;
"member"
js> f.staticMember;
undefined
Using your first example:
var MyObj = function(val) {
this.vari = val;
};
MyObj.var2=value;
Will create a new "static" property callable as:
var o = MyObj.var2;
The first one initializes the MyObj variable with the anonymous function - it does not create the class. The MyObj may be later used as the object constructor that initializes one object field - vari. There is nothing "statis" in OOP meaning.
The second one creates the object of the Object type and initializes its property. Again, there is nothing static.
In OOP "statis" means the member of the class, e.g. variables and objects that belong to class definition. For example, the following schema demonstrates this concept:
function MyClass() {
this.objectProperty = "I'm object property";
// the following demonstrates initialization of
// the object property from class (static) property:
this.varFromStatic = MyClass.classProperty;
}
MyClass.classProperty = "I'm class (static) property";
var obj = new MyClass();
// now obj.varFromStatic contains "I'm class (static) property"
I've got a feeling this might not be possible, but I would like to determine the original variable name of a variable which has been passed to a function in javascript. I don't know how to explain it any better than that, so see if this example makes sense.
function getVariableName(unknownVariable){
return unknownVariable.originalName;
}
getVariableName(foo); //returns string "foo";
getVariableName(bar); //returns string "bar";
This is for a jquery plugin i'm working on, and i would like to be able to display the name of the variable which is passed to a "debug" function.
You're right, this is very much impossible in any sane way, since only the value gets passed into the function.
This is now somehow possible thanks to ES6:
function getVariableName(unknownVariableInAHash){
return Object.keys(unknownVariableInAHash)[0]
}
const foo = 42
const bar = 'baz'
console.log(getVariableName({foo})) //returns string "foo"
console.log(getVariableName({bar})) //returns string "bar"
The only (small) catch is that you have to wrap your unknown variable between {}, which is no big deal.
As you want debugging (show name of var and value of var),
I've been looking for it too, and just want to share my finding.
It is not by retrieving the name of the var from the var but the other way around : retrieve the value of the var from the name (as string) of the var.
It is possible to do it without eval, and with very simple code, at the condition you pass your var into the function with quotes around it, and you declare the variable globally :
foo = 'bar';
debug('foo');
function debug(Variable) {
var Value = this[Variable]; // in that occurrence, it is equivalent to
// this['foo'] which is the syntax to call the global variable foo
console.log(Variable + " is " + Value); // print "foo is bar"
}
Well, all the global variables are properties of global object (this or window), aren't they?
So when I wanted to find out the name of my variables, I made following function:
var getName = function(variable) {
for (var prop in window) {
if (variable === window[prop]) {
return prop;
}
}
}
var helloWorld = "Hello World!";
console.log(getName(helloWorld)); // "helloWorld"
Sometimes doesn't work, for example, if 2 strings are created without new operator and have the same value.
Global w/string method
Here is a technique that you can use to keep the name and the value of the variable.
// Set up a global variable called g
var g = {};
// All other variables should be defined as properties of this global object
g.foo = 'hello';
g.bar = 'world';
// Setup function
function doStuff(str) {
if (str in g) {
var name = str;
var value = g[str];
// Do stuff with the variable name and the variable value here
// For this example, simply print to console
console.log(name, value);
} else {
console.error('Oh snap! That variable does not exist!');
}
}
// Call the function
doStuff('foo'); // log: foo hello
doStuff('bar'); // log: bar world
doStuff('fakeVariable'); // error: Oh snap! That variable does not exist!
This is effectively creating a dictionary that maps variable names to their value. This probably won't work for your existing code without refactoring every variable. But using this style, you can achieve a solution for this type of problem.
ES6 object method
In ES6/ES2015, you are able to initialize an object with name and value which can almost achieve what you are trying to do.
function getVariableName(unknownVariable) {
return Object.keys(unknownVariable)[0];
}
var foo = 'hello';
var output = getVariableName({ foo }); // Note the curly brackets
console.log(output);
This works because you created a new object with key foo and value the same as the variable foo, in this case hello. Then our helper method gets the first key as a string.
Credit goes to this tweet.
Converting a set of unique variable into one JSON object for which I wrote this function
function makeJSON(){ //Pass the variable names as string parameters [not by reference]
ret={};
for(i=0; i<arguments.length; i++){
eval("ret."+arguments[i]+"="+arguments[i]);
}
return ret;
}
Example:
a=b=c=3;
console.log(makeJSON('a','b','c'));
Perhaps this is the reason for this query
I think you can use
getVariableName({foo});
Use a 2D reference array with .filter()
Note: I now feel that #Offermo's answer above is the best one to use. Leaving up my answer for reference, though I mostly wouldn't recommend using it.
Here is what I came up with independently, which requires explicit declaration of variable names and only works with unique values. (But will work if those two conditions are met.)
// Initialize some variables
let var1 = "stick"
let var2 = "goo"
let var3 = "hello"
let var4 = "asdf"
// Create a 2D array of variable names
const varNames = [
[var1, "var1"],
[var2, "var2"],
[var3, "var3"]
]
// Return either name of variable or `undefined` if no match
const getName = v => varNames.filter(name => name[0] === v).length
? varNames.filter(name => name[0] === v)[0][1]
: undefined
// Use `getName` with OP's original function
function getVariableName(unknownVariable){
return getName(unknownVariable)
}
This is my take for logging the name of an input and its value at the same time:
function logVariableAndName(unknownVariable) {
const variableName = Object.keys(unknownVariable)[0];
const value = unknownVariable[variableName];
console.log(variableName);
console.log(value);
}
Then you can use it like logVariableAndName({ someVariable })
This may not be possible (or might be dead easy! :) ) so here it is...
I want to be able to create objects of a type that is dependant on a variable set, without the need for a big switch statement.
I think it is possible in PHP to do something like...
$objectType = "myNewClass";
$newObject = new $objectType();
where the $newObject variable will hold an instance of the Class "myNewClass".
Is this (or any similar technique) possible with Javascript?
Thanks
Stuart
If your constructor functions are defined in the global scope, you can access it trough the bracket notation (window[fnName]):
function ObjectType1(){ // example constructor function
this.type = 1;
}
var objectType = 'ObjectType1'; // string containing the constructor function name
var obj = new window[objectType](); // creating a new instance using the string
// variable to call the constructor
See: Member Operators
CMS's answer is good, but in EXT you're probably dealing with namespaces.
I create an object map that holds any dynamic classes:
// within a namespace:
var ns = {
Thinger: function(){}
};
// globals:
var Zinger = function(){}
// map:
var classes = {
zinger:Zinger,
thinger:ns.Thinger
};
var type = "thinger";
var myClass = new classes[type](props, type, etc);
Should be doable using eval():
var obj = eval("new " + objectType + "()");