Function that gets it's properties - javascript

How can I create a function where it gets it's property?
For example:
myfunc = function(){
alert(this.a + ":" + this.b);
};
myfunc.a = 5;
myfunc.b = 6;
The results is 5:6

There are two ways. The first, is as others have mentioned is to name the parameters in your function delcaration:
function foo(a, b) {
alert(a + ':' + b);
}
foo('hello', 'world'); // Output "hello:world"
Another way however is that a variable is available which contains all function parameters, called arguments.
function bar() {
alert(arguments[0] + ':' + arguments[1]);
}
bar('hello', 'world'); // Output "hello:world"
It should be noted that while it looks like an array, the arguments variable is not an instance of the JavaScript Array object, the only Array property available to use with arguments is .length.

This could be done with a closure:
var myFunc = (function(a, b) {
return function() {
console.log(a + ":" + b);
}
})(5, 6)
myFunc();
This can be expanded via prototype to create class like behaviour:
var myFunc = (function () {
function myFunc(a, b) {
if (a === void 0) { a = 5; }
if (b === void 0) { b = 6; }
this.a = a;
this.b = b;
}
myFunc.prototype.log = function () {
console.log(this.a + ":" + this.b);
};
return myFunc;
}());
var a = new myFunc();
a.log();
new myFunc().log();
new myFunc(1, 10).log();
//ACCESS ATTRIBUTE
console.log("ACCESSING", a.a);
//OVERWRITE ATTRIBUTE
a.a = 11;
//ACCESS ATTRIBUTE
console.log("ACCESSING", a.a);
a.log();

Try this:
myfunc = function(){
alert(this.a + ":" + this.b);
};
myfunc.call({a: 5, b: 6});
When you use the call function, the first parameter is your function's this and the second parameter is your function. The call function just call you function and assign {a: 5, b: 6} to myfunc's this.

Related

Experiment: Can a JavaScript instance be a constructor itself & have its own set of instances?

let bar;
function foo(){
this.x=x;
this.y=y;
}
bar=new foo(1,2);
/*Since all functions in javascript are objects.
Why can't an instance an object be a constructor itself?*/
!function bar(a,b){
this.a=a;
this.b=b;
}(); // (1)
let bar1=new bar(3,4);
console.log(bar1.a);
(1): Using a named IIFE, can bar be an instance and a constructor at the same time?
It's just a fun trick to exploit the language's freedom to see if it is a possibility, any other ways of doing this?
It sounds like you are looking for a constructor-function-returning function:
function makeBar(x, y) {
function Bar(a, b) {
this.a = a;
this.b = y + b;
}
Bar.x = x;
return Bar;
}
var Bar1 = makeBar("bar1", 2);
console.log(Bar1.x); // "bar1"
var myBar1 = new Bar1(1, 2); // Bar { a: 1, b: 4 }
console.log(myBar1 instanceof Bar1); // true
var Bar2 = makeBar("bar2", 0);
var myBar2 = new Bar2(3, 3); // Bar { a: 3, b: 3 }
console.log(myBar2 instanceof Bar1); // false
To make makeBar not a factory function but a constructor with a working prototype, you'd have to use
function Foo(x, y) {
function Bar(a, b) {
this.a = a;
this.b = y + b;
}
Object.setPrototypeOf(Bar, Foo.prototype);
Bar.x = x;
return Bar;
}
Foo.prototype.log = function() {
console.log("I'm "+this.name);
};
var Bar = new Foo("bar", 2);
Bar.log();
console.log(Bar instanceof Foo); // true
var myBar = new Bar(1, 2);
console.log(myBar instanceof Bar); // true
Can a JavaScript instance be a constructor itself & have its own set of instances?
Sure, a function is an instance of Function and a constructor is a function.
So you can just have
const instance1 = new Function("a", "this.a = a;");
const instance2 = new instance1("foo");
console.log(instance2.a); // "foo"
If you need instance1 to be more than a raw Function, you can even extend this constructor:
class MyFunc extends Function {
doSomethingMore(){ console.log("I'm doing more"); }
}
const instance1 = new MyFunc("a", "this.a = a;");
instance1.doSomethingMore();
const instance2 = new instance1("foo");
console.log(instance2.a); // "foo"
But I can't see a clear reason why you'd ever want to do that...
(Note that dynamically creating a function via the Function constructor is generally less "performant" than at parse time through function expression or statement.)
In your code, since bar is declared with let, it can't be re-declared as a function declaration in the same scope.
If you wanted to do this, you could have foo explicitly return a function, which could then be called with new:
function foo(x, y) {
this.x = x;
this.y = y;
return function bar(a, b) {
this.a = a;
this.b = b;
};
}
const bar = new foo(1, 2);
const bar1 = new bar(3, 4);
console.log(bar1.a);

How add methods from a class to a JSON object

I have a class defined in Javascript with some members and methods. I also have a JSON object that has the same member variables as my class but, obviously, not the methods. What is the easiest way to convert my JSON object to an instance of the class?
Below some code that explains better my case. I've tried to use Object.assign without success. Can this be done in a one liner?
function Thing(a, b){
this.a = a;
this.b = b;
this.sum = function(){ return this.a + this.b; };
this.printSum = function(){ console.log (this.sum()); };
};
// test it works
z = new Thing(4,3);
z.printSum(); // shows 7
// attempt with Object.assign
y = JSON.parse('{"a": 5, "b": 4}'); // initialize y from JSON object
console.log(y);
Object.assign(y, new Thing()); // trying to copy methods of Thing into y
console.log(y); // shows both a and b undefined (assign overwrited also a and b)
y.printSum(); // shows NaN
// trying Object.assing the other way around
y = JSON.parse('{"a": 5, "b": 4}');
Object.assign(new Thing(), y); // trying the other way around
console.log(y); // methods from thing are not present now
y.printSum(); // gives error y.printSum is not a function (obvious, as it is not present)
You rather need to change the sum function to make it return sum of this.a and this.b.
Also, instead of Object.assign, you need to change the prototype of the variable y so that the methods are available to it.
function Thing(a, b){
this.a = a;
this.b = b;
this.sum = function(){ return this.a + this.b; };
this.printSum = function(){ console.log (this.sum()); };
};
// test it works
z = new Thing(4,3);
z.printSum(); // shows 7
// attempt with Object.assign
y = JSON.parse('{"a": 5, "b": 4}'); // initialize y from JSON object
console.log(y);
y.__proto__ = new Thing(); // trying to copy methods of Thing into y
console.log(y); // shows both a and b undefined (assign overwrited also a and b)
y.printSum();
Do you mind to make some changes? Lets change Thing input params to Object. And then you can easily pass parsed json into it.
Is it suitable for you?
function Thing(obj) {
this.a = obj.a;
this.b = obj.b;
this.sum = function(){ return this.a + this.b; };
this.printSum = function(){ console.log (this.sum()); };
};
y = JSON.parse('{"a": 5, "b": 4}');
t = new Thing(y);
t.printSum();
It possible to add object as optinal param:
function Thing(a, b, obj = null) {
if (!obj) {
this.a = a;
this.b = b;
} else {
this.a = obj.a;
this.b = obj.b;
}
this.sum = function(){ return this.a + this.b; };
this.printSum = function(){ console.log (this.sum()); };
};
y = JSON.parse('{"a": 5, "b": 4}');
t = new Thing(null, null, y);
t.printSum();
tt = new Thing(5, 4);
t.printSum();

How to rewrite this IIFE into an ES6 class?

So I have this IIFE, and for the sake of consistence with other ES6 classes I rewrote for a plugin, I also want to rewrite this into using ES6 Class syntax. Can anyone show me how to do it?
Foo = (function(){
Foo.bar = function(a, b){
baz = new this(a, b);
return baz;
}
function Foo(a, b){
this.a = a;
this.b = b;
}
return Foo;
})();
It would be a simple
class Foo {
constructor(a, b) {
this.a = a;
this.b = b;
}
static bar(a, b) {
return new this(a, b);
}
}
The function created by the IIFE can be just as well created using a plain function declaration and property assignment:
function Foo(a, b) {
this.a = a;
this.b = b;
}
Foo.bar = function(a, b) {
baz = new this(a, b);
return baz;
}
var foo = new Foo('FooA', 'FooB');
console.log(foo.a + ':' + foo.b);
var baz = Foo.bar('BazA', 'BazB');
console.log(baz.a + ':' + baz.b);
Using the class syntax:
class Foo {
constructor(a, b) {
this.a = a;
this.b = b;
}
static bar(a, b){
baz = new this(a, b);
return baz;
}
}
var foo = new Foo('FooA','FooB');
console.log(foo.a + ':' + foo.b);
var baz = Foo.bar('BazA', 'BazB');
console.log(baz.a + ':' + baz.b);
Unfortunately I can't actually run this code as the site I'm currently on has SOE versions of Firefox and IE that don't recognise the class syntax. So please update if it's faulty.

Is it possible to /manipulate/ functions as it is strings?

var myString = '';
myString += 'foo';
myString += 'bar';
myString = myString.replace(/oba/, 'qux');
console.log(myString) // produces "foquxr"
Is there any way to likewise tinker around with functions, like, say, turning function(a) { a += 'b'; return a; } info function(a) { a += 'b'; console.log(a); return a + 'c'; }?
You can compose functions thus
// (compose(f, g))(x, y, ...) is the same as f(g(x, y, ...))
function compose(f, g) {
return function (var_args) {
return f.call(this, g.apply(this, arguments));
};
}
so
var f = compose(
function (x) { console.log(x); return x + 'c'; },
function (a) { a += 'b'; return a; });
lets you combine two small functions to get a function that behaves like
function(a) { a += 'b'; console.log(a); return a + 'c'; }
You could achieve this (without using eval) by getting the function's body from its declaration, manipulating it as needed, and redefining it by means of the Function() constructor:
function myFunction(a) { a += 'b'; return a; }
function changeFunction(){
var func = window['myFunction'].toString();
var body = func.substring(func.indexOf("{")+1, func.lastIndexOf("}"));
body = body.replace("return a;", "console.log(a); return a + 'c';");
window.myFunction = Function("a", body);
}​
Here's a JSFiddle

'this' context during object creation

I am trying to do something like this:
var test = {
a: 10,
b: 20,
c: (this.a+this.b)
};
but it doesn't work. How can I access the test.a from within test.c?
Is it possible?
It's not possible to reference "this" in an expression specifying an object literal. Either do it in a following line or use a constructor like this:
function myobj(a,b) {
this.a = a;
this.b = b;
this.c = this.a + this.b;
}
var test = new myobj(10,20);
In response to which method is faster, creation with the object constructor is faster. Here's a simple test case comparison. Run it yourself on JSBIN.
The results show that the object creation with a constructor vs an object literal is almost twice as fast:
0.450s : testObjectLiteral
0.506s : testObjectLiteralWithFunction
0.280s : testConstructor
Here's the test code inlined as well:
// timer function
function time(scope){
time.scope = time.scope || {};
if(time.scope[scope]) {
var duration = (new Date()).getTime()-time.scope[scope];
time.scope[scope] = null;
var results = document.getElementById("results");
results.innerHTML = results.innerHTML + '<p>'+(duration/1000).toFixed(3)+'s : '+scope+'</p>';
} else {
time.scope[scope] = (new Date()).getTime();
}
}
// object creation function with constructor
function myobj(a,b) {
this.a = a;
this.b = b;
this.c = this.a + this.b;
}
function testConstructor(iterations) {
var objs = new Array(iterations);
for(i=0;i<iterations;i++) {
objs[i] = new myobj(i,i+1);
}
return objs;
}
function testObjectLiteralWithFunction(iterations) {
var objs = new Array(iterations);
for(i=0;i<iterations;i++) {
objs[i] = {
a: i,
b: i+1,
c: function() {
return this.a + this.b;
}
};
}
return objs;
}
function testObjectLiteral(iterations) {
var objs = new Array(iterations);
for(i=0;i<iterations;i++) {
var item = {
a: i,
b: i+1
};
item.c = item.a + item.b;
objs[i] = item;
}
return objs;
}
var ITERATIONS = 1000000;
time("testObjectLiteral");
testObjectLiteral(ITERATIONS);
time("testObjectLiteral");
time("testObjectLiteralWithFunction");
testObjectLiteralWithFunction(ITERATIONS);
time("testObjectLiteralWithFunction");
time("testConstructor");
testConstructor(ITERATIONS);
time("testConstructor");
​
It's not possible within an object literal since this cannot be made to refer to an object that has not yet been created. Your best option is to assign the c property in a separate step:
var test = {
a: 10,
b: 20
};
test.c = test.a + test.b;
You simply can't do this when declaring an object literal, the closest you can do is:
var test = {
a: 10,
b: 20
};
test.c = test.a + test.b;
In your context this refers to whatever parent context you're in, not the test object...and even if it did, you can't declare members like that, for example this is also invalid:
var test = { a: 10, b: 20, test.c: test.a + test.b };
...because test, a and b aren't defined yet, since it's a single statement that hasn't completed.
Why not make c a function so that it always returns the current value of a+b?
var test = {
a: 5,
b: 1,
c: function() {
return this.a + this.b;
}
}

Categories

Resources