Firstly and most importantly I'm trying to detect the end call of a method chain. I would also like to devise a way to detect how many methods "in" or "down" an object chain I am within my method calls in a method chain.
For instance, in the plugin I'm writing:
var result = $("#someDiv").myPlugin.foo().bar()._foo()._bar();
Say the method is currently executing in .bar() I would like to know that I'm 2 methods down the chain.
The reason I need to abstract this information in some manner is so when I reach the last method in the chain I can return a result instead of the plugin object thus breaking the chain at that point for the sake of gaining access to our data in the 'result' variable.
Here's an example pulled from your project:
var strLenA = parseInt( P.strlen('some string').data );
var strLenB = parseInt( P.strlen('another string').data );
var totalStrLen = strLenA + strLenB;
console.log(strLenA, strLenB, totalStrLen);
From this I can see why our answers aren't really adequate - and why you want to get rid of .data. Happily, your .data always returns a string, anyway. So, you can use the mystical .toString override to have your methods still return a copy of the parent method - but also allow for them to be treated like strings.
Here's an example: [with a fiddle]
var stringMagic = function() {
var chain = "",
self = this;
self.toString = function () { return chain; }; // Where the real magic happens.
self.add = function(str) {
chain += str + " ";
return self;
};
};
var magi = new stringMagic();
alert(magi.add("hello").add("world")); // Alerts, "hello world"
magi.add("and").add("thanks").add("for").add("all").add("the").add("fish");
alert(magi); // Alerts, "hello world and thanks for all the fish"
In your case, probably all you'd have to do is change .data in P to .toString and wrap it in a function.
In the future when you add support for other data types such as numbers and booleans, you can use valueOf in the same way you use toString. In fact, you should also continue to include toString when the return value is not a string for when they're treating that number as a string - like in console.log or $.fn.text. Here's the example above, but with numbers: http://jsfiddle.net/emqVe/1/
For the sake of completeness. Yet another alternative is to pass a an object that will get updated as the chain progress. That would let you access the result value whenever suits you (instead of having to add it at the end of the chain).
Instead of a syntax like this:
var result = chainableFunction.doThis().doThat().result;
You would then have:
chainableFunction.update(variableToUpdate).doThis().doThat();
var result = variableToUpdate.result;
The logic is very much the same as the solution proposed by others. Which one to use probably depends on your use cases. A possible issue with having to end the chain with .result is that nothing prevents you from using it this way:
var chainedUp = chainableFunction.doThis().doThat();
doSomething(chainedUp.result);
...
chainedUp.doOneMoreThing()
...
doSomething(chainedUp.result); // oups, .result changed!
With the variableToUpdate option, the result value is not affected by future function calls. Again, that could be desirable in some contexts, not in others.
Full example below
#!/usr/bin/env node
var ChainUp = {};
(function(Class) {
// Pure functions have no access to state and no side effects
var Pure = {};
Pure.isFunction = function(fn) {
return fn && {}.toString.call(fn) === '[object Function]';
};
Class.instance = function() {
var instance = {};
var result;
var updateRef;
function callBack(fn) {
// returning a clone, not a reference.
if(updateRef) { updateRef.r = (result || []).slice(0); }
if(Pure.isFunction(fn)) { fn(result); }
}
instance.update = function(obj) {
updateRef = obj;
return instance;
};
instance.one = function(cb) {
result = (result || []); result.push("one");
callBack(cb);
return instance;
};
instance.two = function(cb) {
result = (result || []); result.push("two");
callBack(cb);
return instance;
};
instance.three = function(cb) {
result = (result || []); result.push("three");
callBack(cb);
return instance;
};
instance.result = function() {
return result;
};
return instance;
};
}(ChainUp));
var result1 = {};
var chain = ChainUp.instance().update(result1);
var one = chain.one(console.log); // [ 'one' ]
console.log(one.result()); // [ 'one' ]
console.log(result1.r); // [ 'one' ]
var oneTwo = chain.two();
console.log(oneTwo.result()); // [ 'one', 'two' ]
console.log(result1.r); // [ 'one', 'two' ]
var result2 = {};
var oneTwoThree = chain.update(result2).three();
console.log(oneTwoThree.result()); // [ 'one', 'two', 'three' ]
console.log(result2.r); // [ 'one', 'two', 'three' ]
console.log(result1.r); // [ 'one', 'two' ]
Note. The Class and instance keywords are probably unfamiliar. That's a convention that I use when using closures instead of prototypical inheritance to construct instances from a prototype. You could replace instance with self (and self = this instead of instance = {})..
It isn't possible to determine if a call is the last instance in a chain when determining the return value, and here is why:
var result = $("#someDiv").myPlugin.foo().bar()._foo()._bar();
foo returns myPlugin on which bar is called which returns myPlugin on which _foo is called which returns myPlugin on which _bar is called.
So effectively, when _foo returns its value (myPlugin), it is before that value is utilized. Unless _foo is psychic, it can't know what will happen next.
As pointed out in your comments, your best bet is to have some "end" method, like results().
Another suggestion would be to pass a handler in to myPlugin that gets called to set the value using setTimeout(..., 0). Have a value in myPlugin that foo, bar, _foo, and _bar all set. Let's call it returnValue. Modify myPlugin to accept a method as it's only parameter. Let's call that handler. This method's first argument will contain the value. Inside of myPlugin, before your return, do:
window.setTimeout(function () {
handler(returnValue);
}, 0);
Since setTimeout's function parameter will not be called until execution is finished, it will contain the last value set for returnValue - effectively the value set by the last call in the chain. I'd consider this the closest option to what you are trying to achieve, since the developer doesn't have to worry about which of his methods are called last.
There are no (legal or easy or nice) way to find out inside a method what happens with the result outside, after it returns with it. You should use a "chain end mark" method.
Think again, are you looking for the last method applied on an object, or do you want to detect something more explicite thing? Maybe you lose a possibility to apply methods on a decision (with fake silly method names):
obj.turnLeft().pushUp().makeBig().makeSilent;
if (colorSupport) {
obj.paintRed();
} else {
obj.paintStripes();
}
obj.makeShine().lastMethodCallSoObjectIsNowInFinalState();
There is no native way, however, you can add a parameter to the method meant to be chained as you want. And determine if the current call is the latest by setting it to true, as in:
var AlertText = {
text: "",
chainEntry: function(textToAdd, isTheLastOne) {
this.text += textToAdd;
// Perform only if this is told to be the last call in the chain:
if (isTheLastOne) {
alert(this.text);
this.text = "";
}
//
return this;
}
};
AlertText
.chainEntry("Hi, ")
.chainEntry("how ")
.chainEntry("are ")
.chainEntry("you?", true); // alert("Hi, how are you?");
Related
I am trying to create a property within a constructor function which is immutable except through a prototype function. I am trying to go off MDN documentation of this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties. But there does not seem to be a way to make a property completely immutable. Consider a simple example:
function Test(){
Object.defineProperties(this,{
elems : { value : [] }
})
}
Test.prototype.addElem = function(newElem){
if (this.elems.indexOf(newElem) == -1){
this.elems.push(newElem);
}
};
which works fine in most cases (not assignable):
>a = new Test()
Object { , 1 more… }
>a.elems
Array [ ]
>a.elems = 10
10
>a.elems
Array [ ]
Unfortunately, it is still mutable. Consider:
>a.elems.push(10)
1
>a.elems
Array [ 10 ]
I am sure they are other functions (array or object methods?) that will change the value of a non-writeable & non-settable property. Push was just the one I ran into. Is there a way to accomplish this? I know that one possible solution is :
function Test(){
var elems = [];
this.addElem = function(newElem){
if (elems.indexOf(newElem) == -1){
elems.push(newElem);
}
}
}
But I have read this is memory-inefficient especially when there are many instances of the "class". Also, what I am working on may have many methods like this, so I am even more worried about memory considerations.
Any ideas? I am not super knowledgeable about all the intricacies of JS prototyping.
In JavaScript, objects are extensible by default, but if you're able to take advantage of ES5, you should be able to use the Object.seal() or Object.freeze() methods to get immutable properties.
The MDN docs for Object.freeze() have an example that shows how to recursively freeze ("deepFreeze") all of the properties of an object, effectively making it completely immutable.
Here's a proof of concept that combines the code in the question with the code from the docs:
function Test() {
Object.defineProperties(this, {
elems : { value : [] }
})
}
Test.prototype.addElem = function(newElem) {
if (this.elems.indexOf(newElem) == -1) {
this.elems.push(newElem);
}
};
function deepFreeze(obj) {
// Retrieve the property names defined on obj
var propNames = Object.getOwnPropertyNames(obj);
// Freeze properties before freezing self
propNames.forEach(function(name) {
var prop = obj[name];
// Freeze prop if it is an object
if (typeof prop == 'object' && prop !== null)
deepFreeze(prop);
});
// Freeze self (no-op if already frozen)
return Object.freeze(obj);
}
a = new Test();
a.elems.push(1);
console.log(a.elems); // [1]
deepFreeze(a);
a.elems.push(2);
console.log(a.elems); // Error
In FireBug, the a.elems.push() after the object is "deep frozen" returns a TypeError exception, indicating the property is not writable;
TypeError: can't define array index property past the end of an array
with non-writable length
The Safari inspector also returns a TypeError exception:
TypeError: Attempted to assign to readonly property.
You can largely accomplish this with the help of a closure. This is how you achieve privacy in JavaScript.
In a nutshell you create a variable inside of a function and have that function return an object that contains setters/getters.
In my example the foo function contains a _foo variable that can only be set by the methods in the object returned from function foo. You are effectively creating an API to the var held withing the function foo's scope.
var foo = function(config){
if (!config) {
config = {};
}
//enclosed variable
var _foo = {
bar: []
};
if (config.bar) {//All item to be initialized with data
_foo.bar = config.bar;
}
var fooAPI = {
addBarItem: function(val){
_foo.bar.push(val);
return _foo.bar.length - 1;//return idenx of item added
},
removeBarItem: function(index) {
return _foo.bar.slice(index, 1);//return the removed item
},
getBarItem: function(index) {
return _foo.bar[index];//return the removed item
},
emptyBarItems: function() {
return _foo.bar.slice(0, _foo.bar.length);//return all removed
},
getBarItems: function(){
//clone bar do not return reference to it in order to keep private
var newBar = [];
_foo.bar.forEach(function(item){
newBar.push(item);
});
return newBar;
}
};
return fooAPI;
};
var myFoo = new foo({bar: ['alpha', 'beta', 'gamma']});
console.log(myFoo.getBarItems());
I want to create a new object with parameters from 'arguments', but I don't know
how to or even possible to convert it directly without cloning. Here's how it is possible using a clone:
function theClass(name, whatever) {
this.name = name;
this.whatever = whatever;
}
// I need to use the arguments passed from this function but without using clone
// as shown.
function doSomething()
{
function clone(args) {
theClass.apply(this, args);
}
clone.prototype = theClass.prototype;
return new clone(arguments);
}
// Usage expectation.
var myNewObject = doSomething("Honda", "motorbike");
console.log(myNewObject.name);
However, this suffers on performance because each time you call doSomething, you have to create a clone just to pass that arguments to be applied in it from theClass.
Now I want to pass that arguments without passing to a cloned object, but I don't know
how to convert it directly.
Any idea?
Note: As clarified by kaminari, the parameters passed are not strictly 'name' and 'whatever', but could be anything depends on the object I want to create. 'theClass' in the code is merely an example.
Thanks.
EDIT: In light of the intended use of these functions:
Probably your best option on maintaining your intended behavior is to implement your function in the following way:
function theClass(options){
this.name = options.name || ''; //or some other default value
this.whatever = options.whatever || '';
};
function doSomething(options){
options = options || {};
return new theClass(options);
};
With this implementation in mind, the code you supplied in "usage expectation" would look like this:
var myNewObject = doSomething({name: "honda", whatever: "motorbike"});
console.log(myNewObject.name);
In this manner, theClass can support as many or as few parameters as need be (only depends on what's supplied in the object and what you choose to extract from it) and similarly, the wrapper doSomething can be given as many or as few options as desired.
this suffers on performance because each time you call doSomething, you have to create a clone just to pass that arguments to be applied in it from theClass.
Simply define the clone function outside of doSomething, and it won't get recreated every time:
function theClass(name, whatever) {
this.name = name;
this.whatever = whatever;
}
function clone(args) {
theClass.apply(this, args);
}
clone.prototype = theClass.prototype;
function doSomething() {
return new clone(arguments);
}
I want to implement setter and getter on local
javascript variable. Here is an example function:
function someThing() {
var someLocalvariable = '';
}
// with this function I want to
// return value of someLocalvariable
// also if it is possible to implement
// setter in this way.
someThing.prototype.getLocalVar = function() {
}
I want variable to be 'realy' private. I don't wont
to use something like this:
someThing.prototype.someLocalvariable =
or
function someThing() {
this.someLocalvariable = '';
}
or attaching function inside someThing() like this:
function someThing() {
var someLocalvariable = '';
this.getLocalvariable = function() {
return someLocalvariable;
}
}
I would be very grateful for any guidance and assistance.
Your last example of what you don't want to do won't work (it has syntax errors), (it's been fixed) but I think you may have meant the usual way of doing this, which is to make the getter and setter closures within the constructor function (below).
Unfortunately, if you want truly private variables, this is just about your only option. There is no other way to get truly private, instance-specific variables. However, see "hack" below.
Here's the correct version of the usual way of doing this (which I think you said you don't want, but for completeness):
function SomeThing() {
var privateVar;
this.setPrivateVar = function(val) {
privateVar = val;
};
this.getPrivateVar = function() {
return privateVar;
};
}
// use:
var t = new Something();
t.setPrivateVar("foo");
console.log(t.getPrivateVar()); // "foo"
Like most, I first read of this pattern on Douglas Crockford's site.
This option does carry a downside: Every instance created via the SomeThing constructor function gets its own two functions. They cannot be shared between instances. So if there are going to be hundreds or thousands of SomeThing instances in your app, that's something to be considered from a memory perspective. If there are going to be a couple of hundred or fewer, it probably doesn't matter. (Those numbers are pulled out of a hat and you should not trust them, you'll have to review your code's memory use when/if there's some kind of issue; but you get the idea.)
The hack: If your instances will already have some kind of unique identifier on them as public data (or you're willing to add one, again it will be public), and if you're willing to add a fair bit of complication into the use of the instances, you can have a private cache that holds the data for all of your instances that only your code can access, and key into that cache via the unique identifier of the object. Like this (in this example, I'm allocating the id values, but you can use existing unique IDs if you have them):
var SomeThing = (function() {
var cache = {}, idAllocator = 0;
function SomeThing() {
this.id = ++idAllocator; // The unique identifier, can be a string if desired
cache[this.id] = {};
}
SomeThing.prototype.getPrivateVar = function() {
var data = cache[this.id];
return data && data.privateVar;
};
SomeThing.prototype.setPrivateVar = function(value) {
cache[this.id].privateVar = value;
};
SomeThing.prototype.destroy = function() {
delete cache[this.id];
};
return SomeThing;
})();
Here's how that works: All of the functions are closures over the cache local variable in the outer scoping function. We index into that using the unique ID of the object, which gives us an object on which we put our private data members. When the code using the instance is done using it, that code must call destroy (which is a major downside to this pattern) so we remove the private data object from cache by deleting the property for our id.
Caveats and costs:
You still have a public piece of data that is the key to your private data (id in the above)
Users of the instances created by SomeThing must call destroy on those instances when they're done with them. This is anathema to the way JavaScript's garbage handling works, but it's a requirement of the pattern above because otherwise you end up with cruft building up in the cache object.
(I wouldn't worry about this one) Eventually, if you're using the automatic id values above, you'll run out of them, if your app creates and destroys a lot of these instances. But JavaScript numbers go very high up indeed, and if that's an issue just find a different way to allocate IDs rather than the simplistic always-increasing system above.
I haven't had to use the pattern above in my work yet, but I expect there are use-cases for it involving thousands of SomeThing instances and thus the desire not to have per-instance functions.
Side note: In the above, I changed someThing to SomeThing. In JavaScript, the standard practice is for the names of normal functions to start with a lower-case letter, and for the names of constructor functions (ones you use with new) to start with a capital letter. Since SomeThing is meant to be used with new, I capped it. This is only convention, but it's an overwhelmingly popular one and, of course, it's used within the language definition itself (Date is a constructor, setHours is a function).
Use Object.defineProperty() in the function constructor in order to define your getter and setter more info here..
To make truly private (not visible to the outside) some values use a Closure,
more info can be found here.
In the following example we define a getter and setter for property temperature, where the inner "private" value is stored in a variable var temperature.
var temperature will never be visible/accessibly from the outside of Archiver() has it is a Closure.
Please note that this pattern works on ES5 as Object.defineProperty() it is not supported on ES3.
function Archiver() {
var temperature = null;
var archive = [];
Object.defineProperty(this, 'temperature', {
get: function () {
console.log('get!');
return temperature;
},
set: function (value) {
temperature = value;
archive.push({ val: temperature });
}
});
this.getArchive = function () {
return archive;
};
}
var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]
Something like this:
function Field(val){
var value = val;
this.getValue = function(){
return value;
};
this.setValue = function(val){
value = val;
};
}
var field = new Field("test");
field.value
// => undefined
field.setValue("test2")
field.getValue()
Check ref: http://ejohn.org/blog/javascript-getters-and-setters/
Douglas Crockford has written this on implementing private members in JavaScript
That's not possible. If you have a local variable in someThing(), the function you attach to the prototype can't read its value (it's private, remember?). Your last example is the normal solution to this problem, why isn't this good enough for you?
Try these two ways to achieve setter and getter
var address = {
street : "No street",
city : "No city",
state : "No state",
get getAddress()
{
return (this.street+","+this.city+","+this.state);
},
set setAddress(theAddress)
{
var part = theAddress.toString().split(", ");
this.street = part[0] || "";
this.city = part[1] || "";
this.state = part[2] || "";
}
};
address.setAddress = "27 Sus Road, Pune, MH";
console.log(address.getAddress);
//Other setter and getter
function Square(side)
{
this._side = side;
};
Square.prototype = {
set setSide(side){
this._side = side;
},
get getSide(){
return this._side;
},
get getArea(){
return (this._side * this._side);
}
};
var mySquare = new Square(10);
mySquare.setSide = 15;
console.log("Area of square is "+mySquare.getArea+" with side "+mySquare.getSide);
First method
var address = {
street : "No street",
city : "No city",
state : "No state",
get getAddress()
{
return (this.street+","+this.city+","+this.state);
},
set setAddress(theAddress)
{
var part = theAddress.toString().split(", ");
this.street = part[0] || "";
this.city = part[1] || "";
this.state = part[2] || "";
}
};
address.setAddress = "27 Sus Road, Pune, MH";
console.log(address.getAddress);
Second method
function Square(side)
{
this._side = side;
};
Square.prototype = {
set setSide(side){
this._side = side;
},
get getSide(){
return this._side;
},
get getArea(){
return (this._side * this._side);
}
};
var mySquare = new Square(10);
mySquare.setSide = 15;
console.log("Area of square is "+mySquare.getArea+" with side "+mySquare.getSide);
This is something which has been bugging me with the Google Chrome debugger and I was wondering if there was a way to solve it.
I'm working on a large Javascript application, using a lot of object oriented JS (using the Joose framework), and when I debug my code, all my classes are given a non-sensical initial display value. To see what I mean, try this in the Chrome console:
var F = function () {};
var myObj = new F();
console.log(myObj);
The output should be a single line which you can expand to see all the properties of myObj, but the first thing you see is just ▶ F.
My issue is that because of my OO framework, every single object instantiated gets the same 'name'. The code which it looks is responsible for this is like so:
getMutableCopy : function (object) {
var f = function () {};
f.prototype = object;
return new f();
}
Which means that in the debugger, the initial view is always ▶ f.
Now, I really don't want to be changing anything about how Joose instantiates objects (getMutableCopy...?), but if there was something I could add to this so that I could provide my own name, that would be great.
Some things that I've looked at, but couldn't get anywhere with:
> function foo {}
> foo.name
"foo"
> foo.name = "bar"
"bar"
> foo.name
"foo" // <-- looks like it is read only
Object.defineProperty(fn, "name", { value: "New Name" });
Will do the trick and is the most performant solution. No eval either.
I've been playing around with this for the last 3 hours and finally got it at least somewhat elegant using new Function as suggested on other threads:
/**
* JavaScript Rename Function
* #author Nate Ferrero
* #license Public Domain
* #date Apr 5th, 2014
*/
var renameFunction = function (name, fn) {
return (new Function("return function (call) { return function " + name +
" () { return call(this, arguments) }; };")())(Function.apply.bind(fn));
};
/**
* Test Code
*/
var cls = renameFunction('Book', function (title) {
this.title = title;
});
new cls('One Flew to Kill a Mockingbird');
If you run the above code, you should see the following output to your console:
Book {title: "One Flew to Kill a Mockingbird"}
Combine usage of computed property name to dynamically name a property, and inferred function naming to give our anonymous function that computed property name:
const name = "aDynamicName"
const tmp = {
[name]: function(){
return 42
}
}
const myFunction= tmp[name]
console.log(myFunction) //=> [Function: aDynamicName]
console.log(myFunction.name) //=> 'aDynamicName'
One could use whatever they want for 'name' here, to create a function with whatever name they want.
If this isn't clear, let's break down the two pieces of this technique separately:
Computed Property Names
const name = "myProperty"
const o = {
[name]: 42
}
console.log(o) //=> { myProperty: 42 }
We can see that the property name assigned on o was myProperty, by way of computed property naming. The []'s here cause JS to lookup the value inside the bracket, and to use that for the property name.
Inferred Function Naming
const o = {
myFunction: function(){ return 42 }
}
console.log(o.myFunction) //=> [Function: myFunction]
console.log(o.myFunction.name) //=> 'myFunction'
Here we use inferred function naming. The language looks at the name of wherever the function is being assigned to, & gives the function that inferred name.
We can combine these two techniques, as shown in the beginning. We create an anonymous function, which gets it's name via inferred function naming, from a computed property name, which is the dynamic name we wanted to create. Then we have to extract the newly created function from the object it is embedded inside of.
Example Using Stack Trace
Naming a supplied anonymous function
// Check the error stack trace to see the given name
function runAnonFnWithName(newName, fn) {
const hack = { [newName]: fn };
hack[newName]();
}
runAnonFnWithName("MyNewFunctionName", () => {
throw new Error("Fire!");
});
Although it is ugly, you could cheat via eval():
function copy(parent, name){
name = typeof name==='undefined'?'Foobar':name;
var f = eval('function '+name+'(){};'+name);
f.prototype = parent;
return new f();
}
var parent = {a:50};
var child = copy(parent, 'MyName');
console.log(child); // Shows 'MyName' in Chrome console.
Beware: You can only use names which would be valid as function names!
Addendum: To avoid evaling on every object instantiation, use a cache:
function Cache(fallback){
var cache = {};
this.get = function(id){
if (!cache.hasOwnProperty(id)){
cache[id] = fallback.apply(null, Array.prototype.slice.call(arguments, 1));
}
return cache[id];
}
}
var copy = (function(){
var cache = new Cache(createPrototypedFunction);
function createPrototypedFunction(parent, name){
var f = eval('function '+name+'(){};'+name);
f.prototype = parent;
return f;
}
return function(parent, name){
return new (cache.get(name, parent, typeof name==='undefined'?'Foobar':name));
};
})();
This won't totally solve your problem, but I would suggest overriding the toString method on the class's prototype. For instance:
my_class = function () {}
my_class.prototype.toString = function () { return 'Name of Class'; }
You'll still see the original class name if you enter an instance of my_class directly in the console (I don't think it's possible to do anything about this), but you'll get the nice name in error messages, which I find very helpful. For instance:
a = new my_class()
a.does_not_exist()
Will give the error message: "TypeError: Object Name of Class has no method 'does_not_exist'"
If you want to dynamically create a named function. You can use new Function to create your named function.
function getMutableCopy(fnName,proto) {
var f = new Function(`function ${fnName}(){}; return ${fnName}`)()
f.prototype = proto;
return new f();
}
getMutableCopy("bar",{})
// ▶ bar{}
Similar to #Piercey4 answer, but I had to set the name for the instance as well:
function generateConstructor(newName) {
function F() {
// This is important:
this.name = newName;
};
Object.defineProperty(F, 'name', {
value: newName,
writable: false
});
return F;
}
const MyFunc = generateConstructor('MyFunc');
const instance = new MyFunc();
console.log(MyFunc.name); // prints 'MyFunc'
console.log(instance.name); // prints 'MyFunc'
normally you use window[name] like
var name ="bar";
window["foo"+name] = "bam!";
foobar; // "bam!"
which would lead you to a function like:
function getmc (object, name) {
window[name] = function () {};
window[name].prototype = object;
return new window[name]();
}
but then
foo = function(){};
foobar = getmc(foo, "bar");
foobar; // ▶ window
foobar.name; // foo
x = new bar; x.name; // foo .. not even nija'ing the parameter works
and since you can't eval a return statement (eval("return new name()");), I think you're stuck
I think this is the best way to dynamically set the name of a function :
Function.prototype.setName = function (newName) {
Object.defineProperty(this,'name', {
get : function () {
return newName;
}
});
}
Now you just need to call the setName method
function foo () { }
foo.name; // returns 'foo'
foo.setName('bar');
foo.name; // returns 'bar'
foo.name = 'something else';
foo.name; // returns 'bar'
foo.setName({bar : 123});
foo.name; // returns {bar : 123}
Based on the answer of #josh, this prints in a console REPL, shows in console.log and shows in the debugger tooltip:
var fn = function() {
return 1917;
};
fn.oldToString = fn.toString;
fn.toString = function() {
return "That fine function I wrote recently: " + this.oldToString();
};
var that = fn;
console.log(that);
Inclusion of fn.oldToString() is a magic which makes it work. If I exclude it, nothing works any more.
With ECMAScript2015 (ES2015, ES6) language specification, it is possible to dynamically set a function name without the use of slow and unsafe eval function and without Object.defineProperty method which both corrupts function object and does not work in some crucial aspects anyway.
See, for example, this nameAndSelfBind function that is able to both name anonymous functions and renaming named functions, as well as binding their own bodies to themselves as this and storing references to processed functions to be used in an outer scope (JSFiddle):
(function()
{
// an optional constant to store references to all named and bound functions:
const arrayOfFormerlyAnonymousFunctions = [],
removeEventListenerAfterDelay = 3000; // an auxiliary variable for setTimeout
// this function both names argument function and makes it self-aware,
// binding it to itself; useful e.g. for event listeners which then will be able
// self-remove from within an anonymous functions they use as callbacks:
function nameAndSelfBind(functionToNameAndSelfBind,
name = 'namedAndBoundFunction', // optional
outerScopeReference) // optional
{
const functionAsObject = {
[name]()
{
return binder(...arguments);
}
},
namedAndBoundFunction = functionAsObject[name];
// if no arbitrary-naming functionality is required, then the constants above are
// not needed, and the following function should be just "var namedAndBoundFunction = ":
var binder = function()
{
return functionToNameAndSelfBind.bind(namedAndBoundFunction, ...arguments)();
}
// this optional functionality allows to assign the function to a outer scope variable
// if can not be done otherwise; useful for example for the ability to remove event
// listeners from the outer scope:
if (typeof outerScopeReference !== 'undefined')
{
if (outerScopeReference instanceof Array)
{
outerScopeReference.push(namedAndBoundFunction);
}
else
{
outerScopeReference = namedAndBoundFunction;
}
}
return namedAndBoundFunction;
}
// removeEventListener callback can not remove the listener if the callback is an anonymous
// function, but thanks to the nameAndSelfBind function it is now possible; this listener
// removes itself right after the first time being triggered:
document.addEventListener("visibilitychange", nameAndSelfBind(function(e)
{
e.target.removeEventListener('visibilitychange', this, false);
console.log('\nEvent listener 1 triggered:', e, '\nthis: ', this,
'\n\nremoveEventListener 1 was called; if "this" value was correct, "'
+ e.type + '"" event will not listened to any more');
}, undefined, arrayOfFormerlyAnonymousFunctions), false);
// to prove that deanonymized functions -- even when they have the same 'namedAndBoundFunction'
// name -- belong to different scopes and hence removing one does not mean removing another,
// a different event listener is added:
document.addEventListener("visibilitychange", nameAndSelfBind(function(e)
{
console.log('\nEvent listener 2 triggered:', e, '\nthis: ', this);
}, undefined, arrayOfFormerlyAnonymousFunctions), false);
// to check that arrayOfFormerlyAnonymousFunctions constant does keep a valid reference to
// formerly anonymous callback function of one of the event listeners, an attempt to remove
// it is made:
setTimeout(function(delay)
{
document.removeEventListener('visibilitychange',
arrayOfFormerlyAnonymousFunctions[arrayOfFormerlyAnonymousFunctions.length - 1],
false);
console.log('\nAfter ' + delay + 'ms, an event listener 2 was removed; if reference in '
+ 'arrayOfFormerlyAnonymousFunctions value was correct, the event will not '
+ 'be listened to any more', arrayOfFormerlyAnonymousFunctions);
}, removeEventListenerAfterDelay, removeEventListenerAfterDelay);
})();
I have not seen anyone mention the use of ES6 Proxies. Which in my opinion solve this problem beautifully. So here it is.
function shadow(object, secondObject) {
return new Proxy(object, {
get(target, prop, receiver) {
if (secondObject.hasOwnProperty(prop)) return secondObject[prop];
return Reflect.get(...arguments);
}
})
}
let t=function namedFunction(a,b,c){return a+b+c;}
console.log(t.name)//read only property
let f=shadow(t,{name:"addition"})
console.log(f.name)
Please look at my required JavaScript.
var someVariable = new SomeDataType();
// I can directly access value of its property.
someVariable.someProperty = "test";
alert(someVariable.someProperty); // <- this command must should "test"
// However, I have some methods in above property
// I want to validate all rule in this property.
someVariable.someProperty.isValid(); // <- this method will return true/false
Is it possible for doing this in current version of JavaScript?
UPDATE
Please look as my answer!
Yes, you can assign Javascript functions as properties like this:
someVariable.someProperty = function (arg1, arg2) {
// function code goes here
};
This is the method using function literals.
Another method is to use function instances like this:
someVariable.someProperty = new Function (arg1, arg2, code);
Note that in the second method, the code goes in as the last parameter and the Function keyword has a capitalized 'F' as against method 1 where the 'f' is small.
Further, creating a function instance inside a loop etc. will create an entire new instance to assign which is inefficient in memory. This problem does not arise while using the function literal method.
You can't (and probably shouldn't) treat objects like that in JavaScript. As someone else mentioned, you can override the toString() method to get half of the functionality (the read portion), but you cannot use the assignment operator on an object like that without overwriting the object.
You should choose a different approach, like using nested objects (as CMS suggested).
Its possible, but with the below change in your code
function SomeDataType(){
var localProperty="";
this.someProperty = function(txt){
if (arguments.length==0)
return localProperty;
else
localProperty=txt;
}
this.someProperty.isValid = function(){
return (localProperty!="") ? true : false;
};
}
instead of defining someProperty as a property, define this as function which sets value to the local property if any value is passed or it ll return that property value if no argument is given.
var someVariable = new SomeDataType();
someVariable.someProperty("test");
alert(someVariable.someProperty());
var isValid = someVariable.someProperty.isValid();
this is how you need to access the SomeDataType object.
someVariable.someProperty = [ test, anotherFunc, yetAnotherFunc];
someVariable.somePropertyAllValid= function() {
for(var prop in someVariable.someProperty) {
if(!prop()) return false;
}
return true;
};
someVariable.somePropertyAllValid();
I just found the answer. It's very simple & clean.
function createProperty(value, defaultValue, ruleCollection)
{
this.value = value;
this.defaultValue = defaultValue;
this.ruleCollection = ruleCollection;
}
createProperty.prototype.toString = function()
{
return this.value;
};
var someVariable =
{
someProperty: new createProperty
(
'currentValue',
'defaultValue',
null
)
};
For testing, you can use something like my following code.
var test = ">>" + someVariable.someProperty + "<<";
// this alert must shows ">> currentValue <<"
alert(test);
someVariable =
{
someProperty: new createProperty
(
7,
5,
null
)
};
test = someVariable.someProperty + 3;
// This alert must shows "10"
alert(test);
I just test it on FF 3.5 & IE 8. It works fine!
Update
Oops! I forget it. Because this technique returns object reference for this property. So, it's impossible to directly set property data. It isn't my final answer.
Perhaps this would be of help:
var SomeVar = {
someProperty : {
value : 7,
add : function (val) {
this.value += parseInt(val, 10);
return this;
},
toString : function () {
return this.value;
}
}
}
alert(SomeVar.someProperty.add(3));