Use of functions between inner object literals in javascript - javascript

My issue is I have 2 inner objects in my js class and I'm trying to use the methods from one of those objects in my other object (examples of what I'm trying to do below). I understand why this doesn't work because of a the scope. I'm just wondering if there is a way to get it to work.
var Class1 = {
self : this,
Obj1 : {
Obj1Method : function () {
alert("Do something");
},
Obj1Method2 : function () {
alert("Do something else");
},
InnerObj1 : {
InnerNestObj1Method : function (val) {
alert(val + 2);
}
}
},
Class1Method2 : function () {
this.Obj1.Obj1Method2();
},
Obj2 : {
Obj2Method : function (val2) {
self.Obj1.InnerObj1.InnerNestObj1Method(val2);
},
Obj2Method2 : function () {
self.Class1Method2();
}
}
};
Class1.Obj1.InnerObj1.InnerNestObj1Method(3); //works
Class1.Class1Method2(); //works
Class1.Obj2.Obj2Method2(); //No bueno
Class1.Obj2.Obj2Method(5); //No bueno

You can fix your example by replacing self with Class1.
The line self : this, is setting Class1.self to point to the global object (this when that line is evaluated).
var Class1 = {
self : this,
Obj1 : {
Obj1Method : function () {
alert("Do something");
},
Obj1Method2 : function () {
alert("Do something else");
},
InnerObj1 : {
InnerNestObj1Method : function (val) {
alert(val + 2);
}
}
},
Class1Method2 : function () {
this.Obj1.Obj1Method2();
},
Obj2 : {
Obj2Method : function (val2) {
Class1.Obj1.InnerObj1.InnerNestObj1Method(val2);
},
Obj2Method2 : function () {
Class1.Class1Method2();
}
}
};
Class1.Obj1.InnerObj1.InnerNestObj1Method(3); //works
Class1.Class1Method2(); //works
Class1.Obj2.Obj2Method2(); //bueno
Class1.Obj2.Obj2Method(5); //bueno
What happens when you do self: this
// If this is running in non strict mode, from the global scope, `this` points
// To the global object because there was no function call setting `this`
var Class1 = {
self : this,
};
What you need to understand is that this is set by whoever called the function using this. In the example above, there is no caller, so the runtime sets this to point to the global object.
Here's how you could you could make your object a bit more reusable and give yourself a reference to the outer object:
function createClass() {
var self = {
Obj1: {
Obj1Method: function() {
alert("Do something");
},
Obj1Method2: function() {
alert("Do something else");
},
InnerObj1: {
InnerNestObj1Method: function(val) {
alert(val + 2);
}
}
},
Class1Method2: function() {
self.Obj1.Obj1Method2();
},
Obj2: {
Obj2Method: function(val2) {
self.Obj1.InnerObj1.InnerNestObj1Method(val2);
},
Obj2Method2: function() {
self.Class1Method2();
}
}
};
return self;
}
var Class1 = createClass();
Class1.Obj1.InnerObj1.InnerNestObj1Method(3); //works
Class1.Class1Method2(); //works
Class1.Obj2.Obj2Method2(); //works
Class1.Obj2.Obj2Method(5); //works

You can do it with Classes:
"use strict"
class Class1 {
constructor() {
this.Obj1 = {
Obj1Method: function() {
alert("Do something");
},
Obj1Method2: function() {
alert("Do something else");
},
InnerObj1: {
InnerNestObj1Method: function(val) {
alert(val + 2);
}
}
};
var self = this;
this.Obj2 = {
Obj2Method: function(val2) {
self.Obj1.InnerObj1.InnerNestObj1Method(val2);
},
Obj2Method2: function() {
self.Class1Method2();
}
};
}
Class1Method2() {
this.Obj1.Obj1Method2();
}
};
var c1 = new Class1();
c1.Obj1.InnerObj1.InnerNestObj1Method(3); //works
c1.Class1Method2(); //works
c1.Obj2.Obj2Method(3); //works
c1.Obj2.Obj2Method2(); //works

Related

Angularjs retain local variable

I have a factory like this:
TestFactory= function () {
var objectName=null;
return {
SetName:function(name) {
objectName = name;
},
GetName:function() {
return objectName;
},
Init:function() {
return angular.copy(this);
}
}
}
A controller like:
TestController = function($scope) {
$scope.TestClick = function () {
var tstA = TestFactory.Init();
var tstB = TestFactory.Init();
tstA.SetName('test A')
tstB.SetName('test B')
console.log('A', tstA.GetName());
console.log('B', tstB.GetName());
}
}
In the console I get Test B for both objects.
How can I make a proper instance of this object?
I would like to use the objectName value in other functions of the factory.
Take into account that in Angular, Factories are singletons, so the instance is always the same.
You can do the following:
TestFactory= function () {
var objectName={};
return {
SetName:function(property,name) {
objectName[property] = name;
},
GetName:function(property) {
return objectName[property];
},
Clear:function(property) {
delete objectName[property]
}
}
}
Then in your controller:
TestController = function($scope, TestFactory) {
$scope.TestClick = function () {
TestFactory.SetName('a','test A')
TestFactory.SetName('b','test B')
console.log('A', TestFactory.GetName('a')); // test A
console.log('B', TestFactory.GetName('b')); // test B
}
}
Couple of issues. First your returning an object rather than a function from your factory.
app.factory('TestFactory', function() {
return function() {
var objectName = null;
var setName = function(name) {
objectName = name;
};
var getName = function() {
return objectName;
};
return {
SetName: setName,
GetName: getName
};
};
});
Then you can just instantiate like this:
var tstA = new TestFactory();
var tstB = new TestFactory();
Services and factories are singletons so I think you can achieve what you want with a more appropriate use of the factory by providing an Init function that returns the common code and unique name like so:
angular.module('app')
.factory('ServiceFactory', serviceFactory);
function serviceFactory() {
return {
Init: function (name) {
return {
objectName: name,
setName: function (name) {
this.objectName = name;
},
getName: function () {
return this.objectName;
}
};
}
};
}
This leaves the possibility to use it as a factory that can initialize many types.
You basically need to create a simple getter/setter.
angular.module('app', [])
.controller('TestController', testController)
.service('serviceFactory', serviceFactory);
testController.$inject = ['serviceFactory'];
function testController(serviceFactory) {
serviceFactory.set('A', {
name: 'test A'
});
serviceFactory.set('B', {
name: 'test B'
});
console.log(serviceFactory.getAll());
console.log(serviceFactory.get('A'));
console.log(serviceFactory.get('B'));
}
function serviceFactory() {
var
_model = {
name: ""
},
_data = {};
return {
set: function(key, data) {
_data[key] = angular.extend({}, _model, data);
},
get: function(key) {
return _data[key];
},
getAll: function() {
return _data;
}
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<body ng-app="app" ng-controller="testController"></body>

How to prevent object properties to not be extended in javascript

Im trying to seal an object property .
My question is ,here i have given Object.seal(personObject),this particular object is sealed and does not allow to configure or make any extensions in this object,but as i did not mention on personObject_2 it does allow to extend or configure
How can i make it on prototype .I mean like any class of type person should have/respect this seal.Can we achieve such behaviour
"use strict";
var personModule=(function (module) {
var person=function (fname,lname) {
Object.defineProperty(this,'firstName',{
get:function () {
return fname;
}
,set:function (newValue) {
fname=newValue;
},
configurable:true
});
Object.defineProperty(this,'lastName',{
get:function () {
return lname;
}
,set:function (newValue) {
lname=newValue;
},
configurable:true
});
Object.defineProperty(this,'fullName',{
get:function () {
return fname+lname;
},
configurable:true
});
}
module.person=person;
return module;
})(personModule || {});
var personObject=new personModule.person( "Raju","Rani");
console.log(personObject.fullName);
Object.seal(personObject);
//delete personObject.firstName;-->It throws error here
var personObject2=new personModule.person( "Shiva","Kumar");
delete personObject2.firstName;
console.log(personObject2.firstName);
Thanks
Here is Proxy version in case you do not prefer adding Object.seal on constructor
"use strict";
var personModule=(function (module) {
var person=function (fname,lname) {
Object.defineProperty(this,'firstName',{
get:function () {
return fname;
}
,set:function (newValue) {
fname=newValue;
},
configurable:true
});
Object.defineProperty(this,'lastName',{
get:function () {
return lname;
}
,set:function (newValue) {
lname=newValue;
},
configurable:true
});
Object.defineProperty(this,'fullName',{
get:function () {
return fname+lname;
},
configurable:true
});
}
module.person=new Proxy(person, {
construct(target, args){
args.unshift(null);
let ctor = target.bind.apply(target, args);
let result = new ctor();
Object.seal(result);
return result;
}
});
return module;
})(personModule || {});
var personObject=new personModule.person( "Raju","Rani");
console.log(personObject.fullName);
Object.seal(personObject);
//delete personObject.firstName;-->It throws error here
var personObject2=new personModule.person( "Shiva","Kumar");
delete personObject2.firstName;
console.log(personObject2.firstName);
Did you tried - immutable-js
var personObject = new personModule.person("Raju", "Rani");
var sealed = Immutable.Map(personObject);

Calling object literal function with this returning TypeError

I am having a scoping issue. I have a simply object literal function, with a number of methods. I am trying to call method4(), from method1()
var myObjectFunc = function() {
return {
method1: function() {
// call method4 here and pass value
},
method2: function() {
},
method3: function() {
},
method4: function() {
}
}
}
I have tried numerous ways with 'this':
Attempt one:
var myObjectFunc = function() {
var that = this;
return {
method1: function() {
// call method4 here and pass value
var myName = 'Peter';
that.method4(myName);
},
method2: function() {
},
method3: function() {
},
method4: function(val) {
console.log(val);
}
}
}
Attempt two:
var myObjectFunc = function() {
return {
method1: function() {
// call method4 here and pass value
var myName = 'Peter';
this.method4(myName);
},
method2: function() {
},
method3: function() {
},
method4: function(val) {
console.log(val);
}
}
}
Both of which return the error:
TypeError: that.method4 is not a function
try this:
var myObjectFunc = function() {
var ret = {
method1: function() {
// call method4 here and pass value
var myName = 'Peter';
ret.method4(myName);
},
method2: function() {
},
method3: function() {
},
method4: function(val) {
console.log(val);
}
}
return ret;
}
Try this:
const myObjectFunc = () => ({
method1() {
// call method4 here and pass value
const myName = 'Peter'
this.method4(myName)
},
method2() {
},
method3() {
},
method4(val) {
console.log(val)
}
})
Then:
myObjectFunc().method1()
logs 'Peter'.

Javascript - Calling object's method within object giving error: 'Object has no method getStartPoint'

How to call getStartPoint() in startPoint, in the below code?
var obj = (function () {
return {
defaults: {
prop: {
getStartPoint: function () {
// more login ...
},
getEndPoint: function () {
// more login ...
},
startPoint: this.getStartPoint(),
endPoint: this.getEndPoint(),
}
}
};
})();
I am getting error
Uncaught TypeError: Object ... has no method 'getStartPoint'
in all these: getStartPoint(), this.getStartPoint(), obj.defaults.prop.getStartPoint()
One possible solution:
var obj = (function () {
function getStartPoint() {
console.log("getStartPoint");
}
function getEndPoint() {
console.log("getEndPoint");
}
return {
defaults: {
prop: {
getStartPoint: getStartPoint,
getEndPoint: getEndPoint,
startPoint: getStartPoint(),
endPoint: getEndPoint()
}
}
};
})();
Another:
function Obj() {
if (!(this instanceof Obj)) return new Obj();
this.defaults = {
prop: {
startPoint: this.defaults.prop.getStartPoint(),
endPoint: this.defaults.prop.getEndPoint()
}
};
}
Obj.prototype = {
defaults: {
prop: {
getStartPoint: function () {
console.log("getStartPoint");
},
getEndPoint: function () {
console.log("getEndPoint");
}
}
}
};
var obj = new Obj();

Javascript object created from objectss always references last element

This is a kind of weird problem. Given the javascript below, I'm expecting the newFunctions object to contain functions that wrap an original object, however it's only running the last action that occurs in the loop. Shouldn't var actionToCall copy a reference to what currentAction is currently looking at, and not change when the loops iterate? I'm stumped here.
var typeArray = {
type1: {
function1: function() {
console.log("this is function 1");
},
function2: function() {
console.log("this is function 2");
}
},
type2: {
somefunction: function() {
console.log("this is some function")
}
},
type3: {
blah: function() {
return;
},
moreBlah: function(something) {
console.log(something);
},
evenMore: function() {
console.log("I'm last!");
}
}
},
index,
typeIndex,
currentType,
actionIndex,
currentAction,
newFunctions = {};
for(typeIndex in typeArray) {
currentType = typeArray[typeIndex];
for(actionIndex in currentType) {
currentAction = currentType[actionIndex];
console.log(currentAction.toString());
newFunctions[actionIndex] = function() {
var actionToCall = currentAction;
console.log("about to run action");
actionToCall.call(this);
console.log("action has been called");
}
}
}
console.log(newFunctions);
for(index in newFunctions) {
(newFunctions[index])();
}
It's because actionToCall is being assigned to currentAction.
Since currentAction is global it's value keeps changing as the loop iterates.
When the loop ends, currentAction is assigned to evenMore.
Here's the fix using a self execution function to induce scope.
var typeArray = {
type1: {
function1: function() {
console.log("this is function 1");
},
function2: function() {
console.log("this is function 2");
}
},
type2: {
somefunction: function() {
console.log("this is some function")
}
},
type3: {
blah: function() {
return;
},
moreBlah: function(something) {
console.log(something);
},
evenMore: function() {
console.log("I'm last!");
}
}
},
index,
typeIndex,
currentType,
actionIndex,
currentAction,
newFunctions = {};
for(typeIndex in typeArray) {
currentType = typeArray[typeIndex];
for(actionIndex in currentType) {
currentAction = currentType[actionIndex];
console.log(currentAction.toString());
//induce scope here so actionToCall keeps the current value of currentAction.
(function(){
var actionToCall = currentAction;
newFunctions[actionIndex] = function() {
console.log("about to run action");
actionToCall.call(this);
console.log("action has been called");
}
})();
}
}
console.log(newFunctions);
for(index in newFunctions) {
(newFunctions[index])();
}

Categories