How can I extend the scope of this so that the below works? I've tried using the .bind() function but I can't seem to get anything to work.
var myObj = {
test: "Hello",
test2: " World",
run: {
all: function() {
return this.test + this.test2;
},
part: function() {
return this.test2;
}
}
}
console.log(myObj.run.all())
// => "Hello World"
console.log(myObj.run.part())
// => " World"
The functions all and part are members of the object run and run does not have the values test and test2. They're member objects of myObj.
You can replace the this keyword with myObj.
var myObj = {
test: "Hello",
test2: " World",
run: {
all: function() {
return myObj.test + myObj.test2;
},
part: function() {
return myObj.test2;
}
}
}
console.log(myObj.run.all())
console.log(myObj.run.part())
I came across the same issue recently.
I solved by using a function
var myObj = function(){
var self = this;
this.test = "Hello";
this.test2 = " World";
this.run = {
all: function() {
return self.test + self.test2;
},
part: function() {
return self.test2;
}
}
}
console.log(myObj.run.all())
// => "Hello World"
console.log(myObj.run.part())
// => " World"
I also found out the bind does the job!
var myObj = {
test: "Hello",
test2: " World",
run: {
all: function() {
return this.test + this.test2;
},
part: function() {
return this.test2;
}
}
};
console.log( myObj.run.all.bind(myObj)() );
// => "Hello World"
console.log( myObj.run.part.bind(myObj)() );
// => "World"
Working fiddle ==> https://jsfiddle.net/sn5w7872/
Use apply
The apply() method calls a function with a given this value, and arguments provided as an array
var myObj = {
test: "Hello",
test2: " World",
run: {
all: function() {
return this.test + this.test2;
},
part: function() {
return this.test2;
}
}
}
console.log(myObj.run.all.apply(myObj,[]));
// => "Hello World"
console.log(myObj.run.part.apply(myObj,[]));
Use ES6 classes and arrow functions.
class myObj {
constructor() {
this.test = "Hello";
this.test2 = " World";
this.run = {
all: () => this.test + this.test2,
part: () => this.test2
}
}
}
var obj = new myObj();
console.log(obj.run.all())
// => "Hello World"
console.log(obj.run.part())
// => " World"
Here is the working fiddle - https://jsfiddle.net/sgsvenkatesh/vn9b1f95/
Related
var Person = {
name: "jana",
getName: function(callBack) {
callBack();
console.log("** "+this.name);
}
}
var anotherPerson = { name: "prabu"}
I have 2 objects. I need "anotherPerson" to be bound with the Person object. Also, I want to send parameter as a function.
I have tried below methods, but its not working
Person.getName.apply(anotherPerson, function(){})
Person.getName.apply(anotherPerson)(function(){})
Use call to pass an arbitrary number of arguments to your function, or apply to pass an array of arguments:
var Person = {
name: "jana",
getName: function(callBack) {
callBack();
console.log("** " + this.name);
}
}
var anotherPerson = {
name: "prabu"
}
Person.getName.call(anotherPerson, function () {})
Person.getName.apply(anotherPerson, [function () {}])
Have you tried Object.assign ? Like so
var Person = {
name: "jana",
getName: function(callBack) {
callBack();
console.log("** " + this.name);
}
}
var anotherPerson = {
name: "prabu"
}
Object.assign(Person, anotherPerson).getName(alert)
You can use arrow function and return the name parameter to assign value to getName.
var Person = {
name: "jana",
getName: (obj) =>obj.name
}
var anotherPerson = {
name: "prabu"
}
Person.getName(anotherPerson);
console.log(Person);
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>
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
I have something like this:
var yourNamespace = {
foo: function() {
.....
},
bar: function() {
function foobar() {....
}
}
};
Is there a possibility to call inside of foo, the foobar function inside of bar?
With your exact structure you cannot however you can do something like that :
var yourNamespace = {
foo: function() {
.....
yourNamespace.foobar()
},
bar: function() {
function foobar() {....}
yourNamespace.foobar = foobar;
}
};
Or nicer, (IMO) :
var yourNamespace = {
foo: function() {
.....
yourNamespace.bar.foobar()
},
bar: function() {
yourNamespace.bar.foobar = function() {....}
}
};
Please note: in both case, bar() must run before foo() otherwise foobar is undefined
This is just a simple Module pattern. What you should do is make bar it's own module, and return foobar from that module. Example:
var yourNamespace = {
foo: function() {
this.bar.foobar();
},
bar: {
abc: '',
foobar: function() {
console.log('do something');
}
}
};
Or you could do something more like this:
var yourNamespace = {
foo: function() {
var bar = this.bar();
},
bar: function() {
var abc = '';
function foobar() {
console.log('return abc or do something else');
return abc;
}
return {
foobar: foobar
}
}
};
I'm whondering how to access a specific method in a widget, which I've created.
var foo = {
init : function() {
$.bar.addEventListener('click', this.handleClick);
},
handleClick : function(e) {
console.log(this); // TiUIButton { widgetId="Ti.UI.Button:0" ...
// I want to call baz() here....How to do that?
},
baz: function() {
}
};
foo.init()
Greetings from germany and thanks for your help,
--marc
Pretty straightforward:
var foo = {
init : function() {
$.bar.addEventListener('click', this.handleClick);
},
handleClick : function(e) {
console.log(this); // TiUIButton { widgetId="Ti.UI.Button:0" ...
// I want to call baz() here....How to do that?
// Like this
foo.baz();
},
baz: function() {
}
};
foo.init()