Sorry, I don´t know the name of this.
I want to have a function and an object with properties in only one variable.
Here is how it works:
var obj = function() {
return "foo";
};
obj.prop = "bar";
obj(); // => "foo"
obj.prop; // => "bar"
This works fine, but I would like to change the order of this:
var obj = { prop: "bar" };
obj = function() {
return "foo";
};
obj(); // => "foo"
obj.prop; // => undefined
Is there a way to do this?
I want do do this because I have a lot of properties to add to the object:
var obj = function() {
return "foo";
};
obj.prop1 = "bar1";
obj.prop2 = "bar2";
obj.prop3 = "bar3";
obj.prop4 = "bar4";
obj.prop5 = "bar5";
obj.prop6 = "bar6";
obj.prop7 = "bar7";
//...
This isn't possible because when you do:
obj = function() {
return "foo";
};
...you're assigning the variable obj to the new function, so it no longer points to the original object you created ({ prop: "bar" }) at all.
So if you want to add properties to a function object, you must always create the function first, then add properties.
As an alternative, you could do something like this:
var props = {
prop1: "bar1",
prop2: "bar2"
};
var obj = function() {
return "foo";
};
for (var key in props) {
obj[key] = props[key];
}
Or if you happen to have jQuery available (and don't have Object.assign available):
jQuery.extend(obj, props);
(Of course there are shims available for Object.assign, which would allow #Pointy's answer to work in older browsers.)
If you want to do this with one statement, ES2015 (and some libraries) let you do:
var obj = Object.assign(
function() { /* ... */ },
{ "hello": "world" }
);
Which will give you obj as a function with the property "hello". Note that this is really just the same thing as the separate assignment, but it's all wrapped up as one overall expression, which is nice because it means you can do something like
return Object.assign(function() { /* whatever */ }, {
prop: whatever,
// ...
});
I also agree with Grundy, but you could do something like that:
var x = function(){
var obj = {};
return {
objToReturn: obj,
objFunction: function(){return 'foo';},
addItemsToObject: function (key, value) {
obj[decodeURIComponent(key)] = value;
}
}
};
I honestly don't know if that's what you really want, but in that case you can execute the "x" function and after you can access the
"objFunction", the "objToReturn" or the "addItemsToObject" function.
So it will be something like that:
var y = x();
for (propertie in yourProperties){
y.addItemsToObject
(propertie, yourProperties[decodeURIComponent(propertie)]);
}
And then:
y.objFunction();
'foo'
Hope that helps.
Related
Is there a way I can get a property`s name inside the property itself?
I mean something like this:
let myObj = {
myProperty: {
name: <propertyName>.toString()
}
};
console.log(myObj.myProperty.name); // Prints `myProperty`
No, there isn't. There's nothing available when the object initializer is evaluated that provides that information.
Presumably if this were a one-off, you'd just repeat the name. If it's not a one-off, you could give yourself a utility function to do it:
// Define it once...
const addProp = (obj, name, value = {}) => {
obj[name] = value;
value.name = name;
return obj;
};
// Then using it...
let myObj = {};
addProp(myObj, "myProperty");
addProp(myObj, "myOtherProperty", {foo: "bar"});
console.log(myObj.myProperty.name);
console.log(myObj.myOtherProperty.name);
Say I have an object like below:
var obj = {};
obj.test = function() { console.log(?); }
Is there anyway to print out "test", the key that this function is value of, but not know the obj name in advance?
Not really. Relationships in JS are one-way.
You could search for a match…
var obj = {};
obj.not = 1;
obj.test = function() {
var me = arguments.callee;
Object.keys(obj).forEach(function(prop) {
if (obj[prop] === me) {
console.log(prop);
}
});
};
obj.test();
But look at this:
var obj = {};
obj.not = 1;
obj.test = function() {
var me = arguments.callee;
Object.keys(obj).forEach(function(prop) {
if (obj[prop] === me) {
console.log(prop);
}
});
};
obj.test2 = obj.test;
obj.test3 = obj.test;
window.foo = obj.test;
obj.test();
The same function now exists on three different properties of the same object … and as a global.
Might be a bit of a convoluted solution, but this might be useful -
You can have a method that will add functions to your object at a specific key. Using the bind method, we can predefine the first argument to the function to be the key that was used to add it.
The function that I am adding to the key is _template, it's first argument will always be the key that it was added to.
var obj = {};
function addKey(key) {
obj[key] = _template.bind(null, key)
}
function _template(key, _params) {
console.log('Key is', key);
console.log('Params are',_params);
}
addKey('foo')
obj.foo({ some: 'data' }) // this will print "foo { some: 'data' }"
Reference - Function.prototype.bind()
try this Object.keys(this) and arguments.callee
var obj = {};
obj.test = function() {
var o = arguments.callee;
Object.values(this).map((a,b)=>{
if(a==o){
console.log(Object.keys(this)[b])
}
})
}
obj.one = "hi"
obj.test()
You can get the name of the method called with
arguments.callee.name
var a ={ runner_function : function(){ console.log(arguments.callee.name ); } };
a.runner_function() //It will return "runner_function"
Is it possible to assign a value to multiple JavaScript objects at the same time?
Obviously this can be done with a for loop etc, but I'm curious if there's something in the new version of the language that makes this possible. Similar syntax already exists in a number of other languages, I just can't find the JavaScript equivalent.
Ideally, the syntax would look something like this:
{App1, App2, App3}.foo = "bar"
App1.foo === "bar" // true
App2.foo === "bar" // true
You are effectively looking for lenses, which can abstract over such operations and also provide multiple targets. There are various JS implementations around, though I didn't find any that uses lists. With them, it would look something like
set(onList(property("foo")), [App1, App2, App3]);
But that's ugly, right? And you were asking for new ES6 features. Yes, a Proxy can help us make this a lot more beautiful indeed:
ListProxy(App1, App2, App3).foo = "bar";
Here's how you'd implement such a function:
const ListProxy = (() => {
const handler = {
set(target, property, value) {
for (const t of target)
t[property] = value;
},
get(target, property) {
if (typeof target == "function")
target = target.values;
const maybe = target.filter(x => property in Object(x));
if (maybe.length == 0) return undefined;
let values = maybe.map(x => x[property]);
if (values.every(v => typeof v == "function")) {
function fnList(...args) {
return maybe.map(v => v[property](...args));
}
fnList.values = values;
values = fnList;
}
return new Proxy(values, handler);
}
};
return function ListProxy(...args) { return new Proxy(args, handler); };
})();
The get method is not so vitally important, but it does allow for deeper chaining and even function calls instead of assignments:
ListProxy({value:"ax"}, {value:"by"}).value[0].toUpperCase(); // ["A","B"]
There is no native way to do it. However, if you are just looking for similar syntax, you can do something similar. You can create a proxy function which will do it for you.
var _ = (...args) => {
var proxy = new Proxy(args, {
set: (target, property, value) => {
target.forEach(object => object[property] = value);
}
});
return proxy;
};
var App1 = {}, App2 = {}, App3 = {};
_(App1, App2, App3).value = {
foo: 'bar'
};
_(App1, App2, App3).someOtherValue = {
foo: 'baz'
};
console.log(App1); // { value: { foo: 'bar' }, someOtherValue: { foo: 'baz' } }
console.log(App2); // { value: { foo: 'bar' }, someOtherValue: { foo: 'baz' } }
console.log(App3); // { value: { foo: 'bar' }, someOtherValue: { foo: 'baz' } }
The only way to make something like the syntax you propose work is to extend the Object prototype, whether or not one thinks that's a good idea (it's not).
const App1 = {}, App2 = {}, App3 = {};
Object.defineProperty(Object.prototype, 'values', {
set(value) {
for (let prop in this) this[prop].value = value;
}
});
({App1, App2, App3}).values = "foo";
console.log(App1.value);
You would never be able to write {App1, App2, App2}.value, because the JS parser would interpret the leading { as the beginning of a block. Hence the need to enclose it in parentheses.
You cannot use value to set all the values, since that would conflict with the value property you want to set on the individual objects. Hence we use values instead.
I don't think a special syntax is required for this, I'd rather assign it using basic ES6:
const baz = { foo: "bar" };
[App1, App2, App3].forEach(app => app.value = baz);
you can use:
App1.value = App2.value = {foo: "bar"};
Or
App1.value.foo = App2.value.foo = "bar";
I have a bunch of JSON string returned from an ajax call in a specific format and when starting to convert them all into my own Javascript object, I start to wonder if there is any easier way since we're talking Javascript here.
I'll have var manyOfThem = [ { name: 'a' }, { name: 'b' }, { name: 'c' } ];
And I'd like to easily associate each of these objects with my functions so that I can do things like:
myClass.prototype.doSomething = function() {
// do something to this.name
};
$.each(manyOfThem, function(index, item) {
item.doSomething();
});
I guess my concern is, I would not want to (because its repetitive) do this:
var myClass = function(item) {
this.name = item.name;
// do the same for the rest of item's potentially 20 properties
};
var oneOfThem = new myClass(manyOfThem[0]); // I think this is redundant....
oneOfThem.doSomething();
Anyhow, if there is also (security?) reasons why I'd just have to suck it up and do them all manually please share as well, thanks!
You mean, something like (see jsfiddle) :
var MyClass = function() {};
MyClass.prototype = {
doSomething: function() {
alert(this.name);
}
};
Then
var manyObj = $.map(manyOfThem, function(obj) {
return $.extend( new MyClass(), obj );
});
So you can call :
manyObj[0].doSomething(); // alert("a")
However, this approach will not preserve a direct copy with the manyOfThem object. (In the example above, changing manyOfThem[0].name = "foo"; will not affect manyObj[0] and a call to manyObj[0].doSomething(); will still alert "a". To preserve a direct reference to your object, do this :
var manyObj = $.map(manyOfThem, function(obj) {
function F() {};
F.constructor = MyClass;
F.prototype = obj;
$.extend(F.prototype, new MyClass());
return new F();
});
manyObj[0].doSomething(); // alert("a")
manyOfThem[0].name = "foo"; // modify the referenced object
manyObj[0].doSomething(); // alert("foo") ..also modifies the behaviour of the instance
One solution without using a class is
var manyOfThem = [ { name: 'a' }, { name: 'b' }, { name: 'c' } ];
function doSomething(){
console.log(this.name)
}
$.each(manyOfThem, function(index, item) {
doSomething.call(item);
});
Demo: Fiddle
If you want to create an instance of type MyClas then
var manyOfThem = [ { name: 'a' }, { name: 'b' }, { name: 'c' } ];
function MyClass(item){
$.extend(this, item);
}
MyClass.prototype.doSomething = function(){
console.log(this.name)
}
$.each(manyOfThem, function(index, item) {
var obj = new MyClass(item);
obj.doSomething()
});
Demo: Fiddle
You can do
var myClass = function(item){
for( i in item){
if (item.hasOwnProperty(i)){
this[i] = item[i];
}
}
};
This should reduce the repetitive assignments in myClass constructor.
I'm trying to extend Object functionality this way:
Object.prototype.get_type = function() {
if(this.constructor) {
var r = /\W*function\s+([\w\$]+)\(/;
var match = r.exec(this.constructor.toString());
return match ? match[1].toLowerCase() : undefined;
}
else {
return typeof this;
}
}
It's great, but there is a problem:
var foo = { 'bar' : 'eggs' };
for(var key in foo) {
alert(key);
}
There'll be 3 passages of cycle.
Is there any way to avoid this?
I, for one, am not completely against extending native types and ECMA-262 5th ed. solves the problems mentioned in other answers and linked articles for us in a nice manner. See these slides for a good overview.
You can extend any object and define property descriptors that control the behavior of those properties. The property can be made non enumerable meaning when you access the objects properties in a for..in loop, that property will not be included.
Here's how you can define a getType method on Object.prototype itself, and make it non enumerable:
Object.defineProperty(Object.prototype, "getType", {
enumerable: false,
writable: false,
configurable: false,
value: function() {
return typeof this;
}
});
// only logs "foo"
for(var name in { "foo": "bar" }) {
console.log(name);
}
The getType function above is mostly useless as it simply returns the typeof object which in most cases will simply be object, but it's only there for demonstration.
[].getType();
{}.getType();
(6).getType();
true.getType();
You shouldn't extend the object prototype, for that exact reason:
http://erik.eae.net/archives/2005/06/06/22.13.54/
Use a static method instead.
If you have no choice, you can use the "hasOwnProperty" method:
Object.prototype.foo = function(){ alert('x'); }
var x = { y: 'bar' };
for(var prop in x){
if(x.hasOwnProperty(prop)){
console.log(prop);
}
}
You can use the hasOwnProperty() method to check if the property belongs to the foo object:
var foo = { 'bar' : 'eggs' };
for (var key in foo) {
if (foo.hasOwnProperty(key)) {
alert(key);
}
}
Is there any way to avoid this?
Yes, don't extend native types.
Use a wrapper instead:
var wrapper = (function(){
var wrapper = function(obj) {
return new Wrapper(obj);
};
function Wrapper(o) {
this.obj = obj;
}
Wrapper.prototype = wrapper.prototype;
return wrapper;
}());
// Define your get_type method:
wrapper.prototype.get_type = function(){
if(this.obj.constructor) {
var r = /\W*function\s+([\w\$]+)\(/;
var match = r.exec(this.obj.constructor.toString());
return match ? match[1].toLowerCase() : undefined;
}
else {
return typeof this.obj;
}
};
Usage:
var obj = { 'bar' : 'eggs' };
alert(wrapper(obj).get_type());
for(var i in obj) { ... works properly }
When you loop over enumerable properties of an object, you can can determin if the current property was "inherited" or not with Object.hasOwnProperty()
for ( var key in foo )
{
if ( foo.hasOwnProperty( key ) )
{
alert(key);
}
}
But let the dangers of monkey patching be known to ye, especially on Object, as others have posted about
Create your own object instead of extending the default Object.
Also see:
http://erik.eae.net/archives/2005/06/06/22.13.54/
http://dean.edwards.name/weblog/2006/07/erlaubt/