Below code doesn't work, but my idea is to wrap functions into one function, and call the parent function with param. The param will be used by their children function.
_abc(elem){
a(elem){
return elem + 'a';
}
b(elem){
return elem + 'b';
}
}
_abc(elem).b() // doesn't work?
You need to mark your functions as functions, remove the inner elem parameters, and return an object containing the functions:
function _abc(elem){
function a(){
return elem + 'a';
}
function b(){
return elem + 'b';
}
return { a:a, b:b };
}
console.log(_abc('hello').b());
Another way to write this this without repeating the function names multiple times:
function _abc(elem){
return {
a: function () {
return elem + 'a';
},
b: function () {
return elem + 'b';
}
};
}
console.log(_abc('hello').b());
And one more, as suggested by #4castle. This one is only supported by JavaScript environments that support EcmaScript 6:
function _abc(elem){
return {
a() {
return elem + 'a';
},
b() {
return elem + 'b';
}
};
}
console.log(_abc('hello').b());
You might me looking for a Java-oriented object, like so:
function _abc(elem)
{
this.elem = elem;
this.a = function()
{
return this.elem + 'a';
}
this.b = function()
{
return this.elem + 'b';
}
}
console.log(new _abc('Hey ').a());
Related
Why this is working:
var a = () => {
var print = function(i) { console.log(i); return this; }
var print2 = function(i) { console.log(i); return this; }
return { print:print , print2:print2 }
}
a().print(5).print2(5);
this is also working:
var b = () => {
var print = (i) => { console.log(i); return this; }
return { print:print}
}
b().print('Arrow function works');
while this is not working:
var b = () => {
var print = (i) => { console.log(i); return this; }
var print2 = function(i) { console.log(i); return this; }
return { print:print , print2:print2 }
}
b().print(5).print2(5);
https://jsfiddle.net/Imabot/1gt2kxfh/14/
It's all due to arrow functions behavior(docs)
Step by step explanation:
var b = () => {
// 1
var print = (i) => { console.log(i); return this; }
var print2 = function(i) { console.log(i); return this; }
return { print:print , print2:print2 }
}
const res = b()
// 2
const secondRes = res.print(5)
// 3
secondRes.print2(5);
here print function saves this reference from the outer scope, so this can't be reassigned anymore
now print function is not using this reference that comes from res variable, because this has already been attached to print function above
as a result secondRes is not going to reference to the object that was returned by b function. But it will use this reference that is attached to print function. And finally because secondRes doesn't have print2 property - it throws
Hope it helps <3
In a non-arrow function, the value of this depends on how the function is called. If the function is called as a member of an object, this refers to this object:
someObj.myFunction() // inside myFunction this will point to someObj
In contrast, the arrow functions do not affect this. So whithin an arrow function the value of this is whatever it is in the enclosing scope.
The answer from Lex82 gives the why. If you want to return the functions, so you can use function chaining:
var b = () => {
var print = (i) => { console.log(i); return { print:print , print2:print2 }; }
var print2 = function(i) { console.log(i); return this; }
return { print:print , print2:print2 }
}
b().print(5).print2(5);
Good day. I need to eval expression in some object context, but the only solution I found is to create stubs for every object function:
var c = {
a : function () {
return 'a';
},
b : function () {
return 'b';
}
};
function evalInObj(c, js) {
function a() {
return c.a();
}
function b() {
return c.b();
}
return eval(js);
};
console.log(evalInObj(c, 'a() + b()'));
Show me the right way, please. Can I do it with prototype?
var C = function(id) {
this.id = id;
}
C.prototype.a = function () {
return 'a' + this.id;
}
C.prototype.b = function () {
return 'b' + this.id;
}
function evalCtx(js) {
console.log(this); // C {id: 1}
return eval(js);
}
var c1 = new C(1);
evalCtx.call(c1, 'a() + b()'); // error: a is not defined
For late-comers who are still looking for the solution of the issue (or the similar). Instead of using eval(), we can create anonymous function dynamically and evaluate the expression in the object context:
function evaluate(expression, context = {}) {
try {
// console.debug("[DEBUG] Dynamic anonymous function to be defined:\n%s", `function(${[...Object.keys(context)].join()}) {\n'use strict'; return (${expression})\n}`)
const fun = Function(...Object.keys(context), `'use strict'; return (${expression})`)
// console.debug("[DEBUG] Dynamically defined anonymous function:\n%o", fun)
const result = fun(...Object.values(context))
// console.debug("[DEBUG] Evaluation result: %o", result)
return result
} catch(error) {
if(error.message === `Unexpected token ')'`) throw SyntaxError('Unexpected token, likely at the end of expression.')
else throw error
}
}
To assert:
console.assert(evaluate('a===1 && b===2', {a: 1, b: 2}) === true)
console.assert(evaluate('a===1 && b===3', {a: 1, b: 2}) === false)
console.assert(evaluate('f()', {a: 1, f: ()=>11}) === 11)
(() =>
{
// 'use strict';
function run(expression, context = {})
{
return function ()
{
return eval(expression);
}.call(context);
}
let context = {a:{b:'Bb'}};
console.log(run('this', context)); // {a:{b:'Bb'}}
console.log(run('this.a', context)); // {b:'Bb'}
console.log(run('this.a.b', context)); // 'Bb'
console.log(run('a.b', context)); // ReferenceError: a is not defined
})();
The most notable advantage of this technique is that it work without the with keyword,
Thus even in strict mode
+function()
{
// jsut pollyfills for backward browsers...
Object.prototype.keys || (Object.defineProperty(Object.prototype, 'keys', {value: function ()
{
var result = []; for (var key in this) result.push(key); return result;
}}));
Object.prototype.entries || (Object.defineProperty(Object.prototype, 'entries', {value: function ()
{
var result = []; for (var key in this) result.push([key, this[key]]); return result;
}}));
// here the magic...
function run(expression, context)
{
var variables = {};
(context instanceof Object) && context.entries().forEach(function(entry)
{
entry[0].match(/^[a-z_$][a-z0-9_$]*$/) && (variables[entry[0]] = entry[1]);
});
return (new Function('return function(' + variables.keys().join(', ') + ') { return ' + expression + '; }'))()// first get the synthetic function
.apply(context, variables.entries().map(function(entry) { return entry[1]; }));
}
var output = run("a + '#' + b", {a: 'Aa', b: 'Bb', 0: 'Zero'});
console.log(output); // Aa#Bb
}();
function runScript(ctx, js){ with(ctx){ return eval(js); }}
closed. thanks all
function modifyFunction(f) {
return function () {
var returnValue = f.apply(this, arguments);
console.log(returnValue);
if (returnValue == undefined) {
return this;
} else {
return returnValue;
}
};
}
function modifyMethod(o, m) {
if (o.hasOwnProperty(m)) {
if (o[m] instanceof Function) {
o[m] = modifyFunction(m);
}
}
}
var o = {
num: 0,
add: function (x) {
return this.num += x;
},
sub: function (x) {
return this.num -= x;
}
};
modifyMethod(o, "add");
o.add(2).add(4);
console.log(o.num); // o.num = 6
modifyMethod(o, "sub");
o.sub(1).add(3).sub(5);
console.log(o.num); // o.num = 3
How would I make it so that in modifyMethod function inside of the "if(o[m] instanceof Function)" would be equal to what returns by the modifyFunction function, when sending it o[m]? I am trying to make it so that it is chainable, yet I am having a very difficult time getting my head around this.
To make o.add(2).add(4); equal to o.add(2); o.add(4); We can observe that what o.add(2) returns should be o. So your modifyFunction should return a function that :
call the passed in function with given parameters.
Return the caller.
So instead of return that returnValue(which is o.num, a number), you should always return this.
Another point is that in your modifyMethod, after you checked if o[m] is a function, you should pass in that function, not m which is just the key. So it should be o[m] = modifyFunction(o[m]);
function modifyFunction(f) {
return function () {
var returnValue = f.apply(this, arguments);
// Return the object that call this function,
// so it becomes chainable.
return this;
};
}
function modifyMethod(o, m) {
if (o.hasOwnProperty(m)) {
if (o[m] instanceof Function) {
// Pass o[m], not m, m is a string.
o[m] = modifyFunction(o[m]);
}
}
}
var o = {
num: 0,
add: function (x) {
return this.num += x;
},
sub: function (x) {
return this.num -= x;
}
};
modifyMethod(o, "add");
o.add(2).add(4);
console.log(o.num); // o.num = 6
modifyMethod(o, "sub");
o.sub(1).add(3).sub(5);
console.log(o.num); // o.num = 3
I'm keeping a record of each time various functions are called. I have a function called
record_activity( function_name );
I really don't want to have to write this at the top of every function I want to track. Currently there are lots of functions in the format:
Object.Key.Func = function() { ... }
I've written this, which seems to work but I'm really not sure about it's implications:
function sub ( variable, func ) {
var temp_func = function ( args ) {
record_activity( variable );
return func.apply(this,arguments);
}
eval( variable + ' = ' + temp_func );
}
sub( 'Object.Key.Func', function (name) { alert('hi ' + name) } );
Object.Key.Func('test');
If there is a way of doing this without an eval I'd be much happier.
Thanks
I think you can create a wrapper func for each func that you want to track. Hope the following code will help you:
var counter = {};
// assume this is what record_activity has to do.
function record_activity (f, func_name, args) {
counter[func_name] = counter[func_name]===undefined ? 1 : counter[func_name]+1;
}
// assume that you want to keep track of functional call obj.foo and obj.bar
var obj = {
a: 3,
foo: function () {
console.log("foo");
},
bar: function (b) {
console.log("bar", this.a, b);
}
};
function create_func (f, func_name) {
return function () {
record_activity(f, func_name, arguments);
f.apply(obj, arguments);
};
}
for(var prop in obj) {
if (typeof obj[prop] === 'function') {
// create the wrapper func
obj[prop] = create_func(obj[prop], prop);
}
};
// test
for (var i = 0; i < 3; i++) {
obj.foo();
};
for (var i = 0; i < 10; i++) {
obj.bar(i);
};
console.log(counter);
Very simply put, I have lots of classes that share variables and have their own variables. So I created a super class called Resource and many subclasses. The problem is that I want to be able to set and get any value. I simplified the code, but this is what i can't do. Keep in mind that there are many many variables in each class, icluding the superclass and I dont want to redefine the class each time.
var MySuperClass = Class.create({
initialize:function () {
var a;
var b;
var c;
//Getters
this.getA=function () {
return a;
};
this.getB=function () {
return b;
};
this.getC=function () {
return c;
};
//Setters
this.setA=function (val) {
a = val;
};
this.setB=function (val) {
b = val;
};
this.setC=function (val) {
c = val;
};
//end Setters
},
sub:function () {
return this.getA()-this.getB()-this.getC();
}
});
var MyClass = Class.create(MySuperClass, {
initialize:function () {
var d;
var e;
//Getters
this.getD=function () {
return d;
};
this.getE=function () {
return b;
};
this.getC=function () {
return c;
};
//Setters
this.setA=function (val) {
a = val;
};
this.setB=function (val) {
b = val;
};
this.setC=function (val) {
c = val;
};
//end Setters
},
add:function () {
return this.getA()+this.getB()+this.getC()+this.getD()+this.getE();
}
});
function test() {
myclass=new MyClass();
myclass.setA(1);
myclass.setB(0);
myclass.setC(3);
myclass.setD(2);
myclass.setE(3);
var result=myclass.add();
var result2=myclass.sub();
alert(result+' '+result2);
}
Of course the subclass is overriding the superclass initialize so the values cannot be accessed. How can I initialize subclass variables and superclass variables so that they can both be accessed from the test function?
As always, thank you for your help
You are initializing var variables , that means it will be available only inside the initialize function. Make those variable as class level variable by initializing like the following
initialize:function () {
this.a;
this.b;
this.c;
},
getA:function () {
return this.a;
}
This way all these variable will be available in base class as well as super class.