Assigning defined function to an object attribute in javascript - javascript

i have a object in javascript and some already defined functions. but how can i assign those functions to the object attributes. i tried different ways. but no hope.. the snippet is given below
// object
var func = {
a : '',
b : ''
};
// methods
var test1 = function(i) { console.log(i); }
var test2 = function(i) { console.log(i*100); }
i need to assign the test1 to a and test2 to b. i tried like this.
var func = {
a : test1(i),
b : test2(i)
};
obviously the errors i not defined is throwing.. is ther any solution other than the below give sinppet.
var func = {
a : function(i) { test1(i); },
b : function(i) { test2(i); }
};

This does what you're asking:
var test1 = function(i) { console.log(i); }
var test2 = function(i) { console.log(i*100); }
var func = {
a: test1,
b: test2
}
But isn't very good style.
This might be better:
function exampleClass () {}
exampleClass.prototype.a = function(i) { console.log(i); };
exampleClass.prototype.b = function(i) { console.log(i*100); };
var exampleObject = new exampleClass();

Related

Object should keep its status

I am trying to figure out how to put an object to a function and return that
object with its original values.
It's part from my "framework"...
Here an simplified example:
var _objectToFunction = function (obj) {
var F = function () { }
F.prototype = obj
return F
}
var myclass = {
a:"abc",
print: function(){
console.log("i am a func")
},
config: {
path: "c:/bla"
}
}
var fo = _objectToFunction(myclass)
var of = new fo()
of.config.path = "c:/ofpath"
of.z = "zzz"
of.a ="aaa"
console.log(of)
var fo2 = _objectToFunction(myclass)
var of2 = new fo2()
console.log(of2.z)
console.log(of2.a)
console.log(of2.config.path)
The output from console.log(of2.config.path) should "c:/bla", but is "c:/ofpath".
How can I do this right?
You may want to add a constructor (a function that is called, when an instance was created):
var _objectToFunction = function (obj) {
var F = function (...values) {
if( this.constructor) this.constructor(...values);
}
F.prototype = obj
return F
}
So you can create a new config Object for each instance:
var myclass = {
constructor:function(addconf){
this.config=Object.create(this.config);
if(addconf) Object.assign(this.config,addconf);
},
a:"abc",
print: function(){
console.log("i am a func")
},
config: {
path: "c:/bla"
}
}
Now it behaves as wanted.
var parent=_objectToFunction(myclass);
var instance=new parent({ path:"changed"});
Or with standard object funcs:
var instance=Object.create(myclass);
instance.constructor({path:"changed"});

Merging given objects

I am just learning javascript and I need to know how I will go about doing this please:
Task: Merge the given objects into var C
var a = {
name: "Danny"
};
var b = {
getName: function () {
return this.name;
}
};
Output should be danny
var solve = function () {
var C;
var instance = new C();
console.log("Name: "+ instance.getName());
};
solve();
You can use Object.assign() to merge existing objects into any other object. The syntax is:
Object.assign(target, src1, src2, ....);
And, here it is working with your code:
var a = {
name: "Danny"
};
var b = {
getName: function () {
return this.name;
}
};
var C = function() {
Object.assign(this, a, b);
}
var instance = new C();
console.log("Name: "+ instance.getName());

JavaScript: Prevent Array.push()

I have a sealed object with an array member on which I want to prevent direct pushes.
var myModule = (function () {
"use strict";
var a = (function () {
var _b = {},
_c = _c = "",
_d = [];
Object.defineProperty(_b, "c", {
get: function () { return _c; }
});
Object.defineProperty(_b, "d", {
get { return _d; }
});
_b.addD = function (newD) {
_d.push(newD);
};
Object.seal(_b);
return _b;
}());
var _something = { B: _b };
return {
Something: _something,
AddD: _b.addD
};
}());
myModule.Something.c = "blah"; // doesn't update = WIN!!
myModule.AddD({}); // pushed = WIN!
myModule.Something.d.push({}); // pushed = sadness
How can I prevent the push?
UPDATE:
Thanks for all the thoughts. I eventually need the JSON to send to the server. It looks like I might need to use an object for the array then figure out a way to generate and return the JSON needed, or change _something to use .slice(). Will play and report.
you could override the push method:
var _d = [];
_d.__proto__.push = function() { return this.length; }
and when you need to use it in your module, call Array.prototype.push:
_b.addD = function (newD) {
Array.prototype.push.call(_d, newD);
};
I haven't done any performance tests on this, but this certainly helps to protect your array.
(function(undefined) {
var protectedArrays = [];
protectArray = function protectArray(arr) {
protectedArrays.push(arr);
return getPrivateUpdater(arr);
}
var isProtected = function(arr) {
return protectedArrays.indexOf(arr)>-1;
}
var getPrivateUpdater = function(arr) {
var ret = {};
Object.keys(funcBackups).forEach(function(funcName) {
ret[funcName] = funcBackups[funcName].bind(arr);
});
return ret;
}
var returnsNewArray = ['Array.prototype.splice'];
var returnsOriginalArray = ['Array.prototype.fill','Array.prototype.reverse','Array.prototype.copyWithin','Array.prototype.sort'];
var returnsLength = ['Array.prototype.push','Array.prototype.unshift'];
var returnsValue = ['Array.prototype.shift','Array.prototype.pop'];
var funcBackups = {};
overwriteFuncs(returnsNewArray, function() { return []; });
overwriteFuncs(returnsOriginalArray, function() { return this; });
overwriteFuncs(returnsLength, function() { return this.length; });
overwriteFuncs(returnsValue, function() { return undefined; });
function overwriteFuncs(funcs, ret) {
for(var i=0,c=funcs.length;i<c;i++)
{
var func = funcs[i];
var funcParts = func.split('.');
var obj = window;
for(var j=0,l=funcParts.length;j<l;j++)
{
(function() {
var part = funcParts[j];
if(j!=l-1) obj = obj[part];
else if(typeof obj[part] === "function")
{
var funcBk = obj[part];
funcBackups[funcBk.name] = funcBk;
obj[part] = renameFunction(funcBk.name, function() {
if(isProtected(this)) return ret.apply(this, arguments);
else return funcBk.apply(this,arguments);
});
}
})();
}
}
}
function renameFunction(name, fn) {
return (new Function("return function (call) { return function " + name +
" () { return call(this, arguments) }; };")())(Function.apply.bind(fn));
};
})();
You would use it like so:
var myArr = [];
var myArrInterface = protectArray(myArr);
myArr.push(5); //Doesn't work, but returns length as expected
myArrInterface.push(5); //Works as normal
This way, you can internally keep a copy of the interface that isn't made global to allow your helper funcs to modify the array as normal, but any attempt to use .push .splice etc will fail, either directly, or using the .bind(myArr,arg) method.
It's still not completely watertight, but a pretty good protector. You could potentially use the Object.defineProperty method to generate protected properties for the first 900 indexes, but I'm not sure of the implications of this. There is also the method Object.preventExtensions() but I'm unaware of a way to undo this effect when you need to change it yourself
Thank you, dandavis!
I used the slice method:
var myModule = (function () {
"use strict";
var a = (function () {
var _b = {},
_c = _c = "",
_d = [];
Object.defineProperty(_b, "c", {
get: function () { return _c; }
});
Object.defineProperty(_b, "d", {
get { return _d.slice(); } // UPDATED
});
_b.updateC = function (newValue) {
_c = newValue;
};
_b.addD = function (newD) {
_d.push(newD);
};
Object.seal(_b);
return _b;
}());
var _something = { B: _b };
return {
Something: _something,
AddD: _b.addD
};
}());
myModule.Something.c = "blah"; // doesn't update = WIN!!
myModule.AddD({}); // pushed = WIN!
myModule.Something.d.push({}); // no more update = happiness
This allows me to protect from direct push calls enforcing some logic.

Javascript: Run a function defined outside this closure as if it were defined inside this closure

I want to have a function A that accepts another function B as an argument, and then runs B as it were defined within the closure scope of A, i.e. has access to all the local variables.
For example, simplistically:
var A = function(B){
var localC = "hi";
B();
}
var B = function(){
console.log(localC);
}
A(B); // to log 'hi'
The only way I have found is to use eval. Does ec6 give any better options maybe?
One solution is to pass localC as argument in function B:
var A = function(B) {
var localC = "hi";
B(localC);
}
var B = function(localC) {
console.log(localC);
}
A(B); // outputs hi
Alternative using arguments:
var A = function(B) {
var localC = "hi";
B(localC, "test");
}
var B = function() {
var i = 0;
for (i; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
A(B); // outputs hi, test
You can make the context explicit and pass it to B:
var A = function(B){
var context = {
localC: "hi"
};
B(context);
}
var B = function(context){
console.log(context.localC);
}
A(B); // hi
You can also use this with new and prototype:
var A = function() {
this.localC = "hi";
}
A.prototype.b = function(context){
console.log(this.localC);
}
var a = new A();
a.b(); // hi
or without the prototype:
var A = function() {
this.localC = "hi";
}
var a = new A();
a.b = function(context){
console.log(this.localC);
};
a.b(); // hi
You can use this with bind:
var a = {
localC: "hi"
};
function B(foo) {
console.log(this.localC, foo);
}
B.bind(a)("foo"); // hi foo
// .call:
B.call(a, "foo"); // hi foo
bind sets the context for this. call takes the context as it's first argument.
This one is not good:
var A = function(B){
var localC = "hi";
B.bind(this)(); // this is the global object, you need `new` to create a new scope
}
var B = function(){
console.log(this.localC);
}
A(B); // undefined
var A = function(B){
var self = this;
self.localC = "hi";
self.localD = "hello";
B();
};
var B = function(){
var self=this;
alert(self.localD);
}
A(B); // to log 'hi'

inheritance namespace javascript

How can I inherit an objects variables within namespace(scope)?
var f2 = {
a: 'test'
}
f2.history = {
load: function(){ alert(this.a); }
}
// Turns out Undefined
f2.history.load();
There is no link between f2.history and f2. More generally there is no link between a property value and its holder.
You could call it like this :
f2.history.load.call(f2);
Or you could declare your objects with a factory :
var f2 = (function(){
var self = {
a: 'test'
};
self.history = {
load: function(){ alert(self.a); }
};
return self;
})();
This would allow
f2.history.load();
Another variant would let you define the submodules in a more separated way :
var f2 = {
a: 'test'
};
(function(f){
f.history = {
load: function(){ alert(f.a); }
}
})(f2);
The advantage of this last construct is that it's easy to declare sub-modules in different files.
use the namespace, f2, not this.
load: function(){ alert(f2.a); }
works
var f2 = {
a : 'test',
init: function(a) {
if (a) this.a = a; //set a, if a is defined
},
};
function history(a) {
function F() {};
F.prototype = f2;
var f = new F();
f.init(a);
load = function() {
alert(f.a);
}
return this;
}
var h1 = history();
h1.load(); //alerts "test"
var h2 = history('history');
h2.load(); //alerts "history"
//but now h1 also holds history
h1.load();

Categories