Access to function through this - javascript

var Application;
(function (Application, PhotonSdk) {
(function(Photon) {
Photon.PeerManager = (function () {
var $this;
function PeerManager() {
$this = this;
this.currentStatus = PhotonSdk.PhotonPeer.StatusCodes.connectClosed;
this.peer = new PhotonSdk.PhotonPeer("ws://localhost:9090");
this.peer.addPeerStatusListener(PhotonSdk.PhotonPeer.StatusCodes.connecting, this._onConnecting);
this.peer.addPeerStatusListener(PhotonSdk.PhotonPeer.StatusCodes.connect, this._onConnect);
}
PeerManager.prototype.establishConnection = function() {
this.peer.connect();
console.log("Photon is establishing connection.");
};
PeerManager.prototype._onConnecting = function() {
this.currentStatus = PhotonSdk.PhotonPeer.StatusCodes.connecting;
PeerManager.prototype._logConnectionState(this.currentStatus); //It work
};
PeerManager.prototype._onConnect = function () {
this.currentStatus = PhotonSdk.PhotonPeer.StatusCodes.connect;
this._logConnectionState(this.currentStatus); //It isn't work :(
};
PeerManager.prototype._logConnectionState = function (state) {
console.log("Photon connection is " + state + ". " + new Date().toTimeString());
};
return PeerManager;
})();
})(Application.Photon || (Application.Photon = {}));
})(Application || (Application = {}), Photon);
If i use this._logConnectionState(this.currentStatus);
i get this._logConnectionState is not a function error, but
PeerManager.prototype._logConnectionState(this.currentStatus);
or
$this._logConnectionState(this.currentStatus);
is work. Why it's happened and how i can do that access through this well doing?

My suggestion is that events _onConnecting and _onConnect are dispatching by PhotonSdk.PhotonPeer instance. Since you have added listeners here:
this.peer.addPeerStatusListener(PhotonSdk.PhotonPeer.StatusCodes.connecting, this._onConnecting);
this.peer.addPeerStatusListener(PhotonSdk.PhotonPeer.StatusCodes.connect, this._onConnect);
So functions are called with wrong this.
Try this:
function PeerManager() {
$this = this;
this.currentStatus = PhotonSdk.PhotonPeer.StatusCodes.connectClosed;
this.peer = new PhotonSdk.PhotonPeer("ws://localhost:9090");
this.peer.addPeerStatusListener(PhotonSdk.PhotonPeer.StatusCodes.connecting, this._onConnecting.bind(this));
this.peer.addPeerStatusListener(PhotonSdk.PhotonPeer.StatusCodes.connect, this._onConnect.bind(this));
}

PeerManager.prototype._onConnect = function () {
this.currentStatus = PhotonSdk.PhotonPeer.StatusCodes.connect;
this._logConnectionState(this.currentStatus); //It isn't work :(
};
Your reference you used
_logConnectionState(this.currentStatus);
on seems to be this:
PeerManager.prototype._onConnect
and not that:
Peer Manager.prototype
basicly this refers to
PeerManager.prototype._onConnect
and
this._logConnectionState
is the same as
PeerManager.prototype._onConnect._logConnectionState
wich is undefined because there is no local value /function for that reference.
As you see "this" only has a local context always being bound to the first object/function it can find while climbing up the scopes.

Related

Sinon stub not working when trying to mock out an instance of an object

I am trying to mock out every instance that is created with the new keyword for an object.
Here is the Object I am trying to mock out:
var SharedWhiteboardView = function(moduleEl, domService) {
'use strict';
var self;
var sharedWhiteboardProblemImage;
var whiteboardController;
var caller = false;
var toolbarController;
return {
initWhiteboard : function()
{
self = this;
sharedWhiteboardProblemImage = domService.find(moduleEl, '#sharedWhiteboardModule-sharedWhiteboardProblemImage');
var toolbarEL = $('#sharedWhiteboard-toolbar');
toolbarController = new ToolbarController(WhiteboardConstants.SHARED_WHITEBOARD_ID, toolbarEL, null);
toolbarController.init(false);
whiteboardController = toolbarController.getWhiteboardController();
},
enableWhiteboardEdition : function(enabled)
{
if(self.getWhiteboardObject() && self.getWhiteboardObject.hasOwnProperty('enableEdition')) self.getWhiteboardObject().enableEdition(enabled);
whiteboardController.setEnabled(enabled);
}
};
}
This is the file which I am trying to test and it creates a new instance of the above object
Box.Application.addModule('SharedWhiteboardModule', function(context) {
'use strict';
var self;
var moduleEl;
var domService;
var sharedWhiteboardView;
var modal;
var assignmentTimer = 3000;
var sharing = false;
var assignmentImageData = '';
return {
/**
* Initializes the module and caches the module element
* #returns {void}
*/
init: function() {
self = this;
domService = context.getService('DomService');
moduleEl = context.getElement();
sharedWhiteboardView = new SharedWhiteboardView(moduleEl, domService);
sharedWhiteboardView.initWhiteboard();
sharedWhiteboardView.enableWhiteboardEdition(false);
};
}
I am trying to write a unit test to test that the sharedWhiteboardView.enableWhiteboardEdition method is called with 'false'
However I am failing to attach a spy or stub that method out. I have tried these solutions and they did not work
//First Attempt
sinon.stub(SharedWhiteboardView, "enableWhiteboardEdition", function() {return 0})
// Second Attempt
sinon.stub(SharedWhiteboardView.prototype, "enableWhiteboardEdition").returns(0);
//Third Attempt
sandbox.stub(SharedWhiteboardView.prototype, 'enableWhiteboardEdition', checkEnableWhiteboardEdition());
//Fourth Attempt Trying the answer provided by chrmod
it.only('when type is "SharedWhiteboardModule-setEditable" should call sharedWhiteboardView.enableWhiteboardEdition', function (done) {
const view = SharedWhiteboardView();
sinon.stub(view, "enableWhiteboardEdition", function() {
console.log('Hit');
});
module.onmessage('SharedWhiteboardModule-setEditable', true);
done();
});
No error but it does not hit the console.log, I removed the 'new' keyword as suggested
Errors that I got:
-Attempted to wrap undefined property enableWhiteboardEdition as function
-Cannot stub non-existent own property enableWhiteboardEdition
Please any help would be great. I have reached a dead end here.
Here is a codepen: http://codepen.io/anon/pen/bgmNxx?editors=0011
All I am trying to do is to have the Fake method get hit when my module calls enableEdition
SharedWhiteboardView is not a constructor, it is rather a factory function. Once called (without new) it returns new object that has enableWhiteboardEdition as own property.
Thus a stub has to be set on that object:
const view = SharedWhiteboardView();
sinon.stub(view, "enableWhiteboardEdition", function() {return 0});
This did it.
it('when type is "SharedWhiteboardModule-setEditable" should call setEditable with appropriate callback', function (done) {
var mockSharedWhiteboardView = {
enableWhiteboardEdition: function() {},
initWhiteboard: function() {},
initScrollBar: function() {},
refreshScrollBar: function() {},
isMainWhiteboardAvailable: function() {}
};
sandbox.spy(mockSharedWhiteboardView, 'enableWhiteboardEdition');
var tempGlobals = {
SharedWhiteboardView: global.SharedWhiteboardView
};
global.SharedWhiteboardView = function() {
return mockSharedWhiteboardView;
};
module = Box.Application.getModuleForTest('SharedWhiteboardModule', contextFake);
module.init();
var shouldEnable = true;
module.onmessage('SharedWhiteboardModule-setEditable', shouldEnable);
assert(mockSharedWhiteboardView.enableWhiteboardEdition.calledWithExactly(shouldEnable),
'should enable the whiteboard');
shouldEnable = false;
module.onmessage('SharedWhiteboardModule-setEditable', shouldEnable);
assert(mockSharedWhiteboardView.enableWhiteboardEdition.calledWithExactly(shouldEnable),
'should not enable the whiteboard');
// cleanup
global.SharedWhiteboardView = tempGlobals.SharedWhiteboardView;
done();
});

Javascript Class and scope

I want to make a class in javascript to reuse from my main code in the connection with an indexeddb object. What I have now is:
function DATABASE() {
this.DB_NAME = 'MYdatabase';
this.DB_VERSION = 1;
this.db = null;
this.results = null;
}
DATABASE.prototype.open = function(callback) {
var req = indexedDB.open(this.DB_NAME, this.DB_VERSION);
req.onsuccess = function (evt) {
this.db = this.result;
callback();
};
req.onerror = function (evt) {
console.error("openDb:", evt.target.errorCode);
};
req.onupgradeneeded = function (evt) {
console.log("openDb.onupgradeneeded");
};
}
My problem here is that when the onsuccess executes I loose the scope of my main class and this is not what I expected. How can I do what I am looking for?
I want to make some connections at the same time with this, something like:
var DB = new DATABASE();
DB.open(function(res){});
var DB2 = new DATABASE();
DB2.open(function(res){});
var DB3 = new DATABASE();
DB3.open(function(res){});
thanks so much.
Under var req add var self = this; and use like this whenever the scope changes:
self.db = self.result;
My problem here is that when the onsuccess executes I loose the scope of my main class and this is not what I expected.
It's not scope, but the value of this during a function call depends on how the function is called. So what's happening is that the functions you're assigning to req are getting called with this being a different value than it is in the call to open.
How can I do what I am looking for?
Since your functions already close over the scope of the call to open, the easiest way is to do what Andy suggested:
DATABASE.prototype.open = function(callback) {
var req = indexedDB.open(this.DB_NAME, this.DB_VERSION);
var self = this; // <=== New
req.onsuccess = function (evt) {
self.db = this.result; // <=== Changed
callback();
};
// ...
}
Note: In the changed line, I don't know what this.result is, so I don't know whether to change this to self there as well. It's entirely possible that you actually want this.result, if result is a property of the object that this points to on the callback.
More:
You must remember this
Closures are not complicated
Does this work for you? Putting the open function inside the DATABASE instead of on the prototype.
function DATABASE() {
var _this=this;
_this.DB_NAME = 'MYdatabase';
_this.DB_VERSION = 1;
_this.db = null;
_this.results = null;
_this.open = unction(callback) {
var req = indexedDB.open(_this.DB_NAME, _this.DB_VERSION);
req.onsuccess = function (evt) {
_this.db = _this.result;
callback();
};
req.onerror = function (evt) {
console.error("openDb:", evt.target.errorCode);
};
req.onupgradeneeded = function (evt) {
console.log("openDb.onupgradeneeded");
};
}
}
var that = this
req.onsuccess = function (evt) {
that.db = that.result;
callback();
};
Also I recommend to read this article: Scope and this in JavaScript

How to create a javascript library using a closure

I have written some javascript that I would to encapsulate in a closure so I can use it elsewhere. I would like do do this similar to the way jQuery has done it. I would like to be able to pass in an id to my closure and invoke some functions on it, while setting some options. Similar to this:
<script type="text/javascript">
_snr("#canvas").draw({
imageSrc : someImage.png
});
</script>
I have read a lot of different posts on how to use a closure to do this but am still struggling with the concept. Here is where I left off:
_snr = {};
(function (_snr) {
function merge(root){
for ( var i = 1; i < arguments.length; i++ )
for ( var key in arguments[i] )
root[key] = arguments[i][key];
return root;
}
_snr.draw = function (options) {
var defaults = {
canvasId : 'canvas',
imageSrc : 'images/someimage.png'
}
var options = merge(defaults, options)
return this.each(function() {
//More functions here
});
};
_snr.erase = function () {};
})(_snr);
When ever I try to call the draw function like the first code section above, I get the following error, '_snr is not a function'. Where am I going wrong here?
EDIT
Here is what I ended up doing:
function _snr(id) {
// About object is returned if there is no 'id' parameter
var about = {
Version: 0.2,
Author: "ferics2",
Created: "Summer 2011",
Updated: "3 September 2012"
};
if (id) {
if (window === this) {
return new _snr(id);
}
this.e = document.getElementById(id);
return this;
} else {
// No 'id' parameter was given, return the 'about' object
return about;
}
};
_snr.prototype = (function(){
var merge = function(root) {
for ( var i = 1; i < arguments.length; i++) {
for ( var key in arguments[i] ) {
root[key] = arguments[i][key];
}
}
return root;
};
return {
draw: function(options) {
var defaults = {
canvasId : 'canvas',
imageSrc : 'images/someimage.png'
};
options = merge(defaults, options);
return this;
},
erase: function() {
return this;
}
};
})();
I can now call:
<script type="text/javascript">
_snr("#canvas").draw({
imageSrc : someImage.png
});
</script>
Because you declared _snr as an object and not a function. Functions can have properties and methods, so there's various ways to achieve what you want, for example one of them would be say...
_snr = function(tag) {
this.tag = tag;
}
_snr.foo = function() {
//Code goes here
}
You can also pass the outer context into a closure to hide your variables from accidentally polluting the global namespace, so like...
(function(global) {
var _snr = function(tag) {
this.tag = tag;
}
_snr.foo = function() {
//Code goes here
}
//export the function to the window context:
global._snr = _snr;
})(window);
window._snr('#tag').foo('wat');
Happy coding.
Because your _snr is an object, not a function. You have to call it like this:
_snr.draw({
canvasId: '#canvas',
imageSrc: 'someImage.png'
});
When you do _snr('#canvas') that is a function call which is why you're getting that error. _snr is an object with some methods attached to it such as draw() and erase(). The reason jQuery is able to pass arguments into the $ is because they return the $ as a function object which is why we're able to pass it various selectors as arguments.
You are going wrong at the first line _snr = {}
It needs to be
_snr = function(){
selector = arguments[0]||false;
//snr init on dom object code
return _snrChild;
}
Im on a mobile phone but when im on a pc I will maybe fix the whole code c:
Here you have a snr object and that has erase and draw methods. What you intend to do is to write a _snr function which will get an id and return a wrapper object. That returned object should have erase and draw methods. so you can do
var returnedObject = _snr("my_id");
returnedObject.draw("image.png");

Deep nesting functions in JavaScript

I cannot find an proper example for the love of my life on how to do this or even if this is possible. Based on my pieced together understanding from fragments of exmaples, I have come up with the following structure
var t = function()
{
this.nestedOne = function()
{
this.nest = function()
{
alert("here");
}
}
}
t.nestedOne.nest();
However this is not working (obviously). I would greatly appreciate if someone could point me in the right direction!
That is simply done with:
var t = {
nestedOne: {
nest: function() {
alert('here');
}
}
};
Your code otherwise doesn't make sense. this inside function doesn't refer to the function itself, it refers to the object context that the function is invoked in. And you are not even invoking the functions in your code.
If I say obj.func() then this inside func will be obj for that call. So assigning this.asd = true will assign true to that object's "asd" property.
If you wanted to do a nested class, it looks very different:
ClassA = (function() {
function ClassA() {
}
ClassA.prototype.method1 = function() {
};
function ClassB() {
}
ClassB.prototype.method1 = function() {
};
return ClassA;
}())
only ClassA can now make instances of ClassB. This should achieve same goals as nested classes in java.
See http://jsfiddle.net/CstUH/
function t(){
function f(){
this.nest = function()
{
alert("here");
}
}
this.nestedOne = new f();
}
var myt=new t();
myt.nestedOne.nest()
Edit 1:
You can also use
new t().nestedOne.nest()
instead of
var myt=new t();
myt.nestedOne.nest()
(http://jsfiddle.net/CstUH/1/)
Edit 2:
Or even more condensed:
function t(){
this.nestedOne = new function(){
this.nest = function(){
alert("here");
}
}
}
new t().nestedOne.nest()
http://jsfiddle.net/CstUH/2/
In JS functions are prime class objects, and you can access them directly in the code [i.e. without using reflection or so].
The code you put inside t body would be performed when actually executing t:
t();
You wrote t.nestedOne,nest(), but t has no nestedOne property - you should do like this:
var t = {
nestedOne : {
nest : function()
{
alert("here");
}
}
};
t.nestedOne.nest(); ​
I advice you to have a trip on John Resig's Learning Advanced JavaScript tutorial, it was very enlightening for me.
A simple callback handler I wrote today as an example of how I do deep nesting. I apologize if it's not the bees knees when it comes to code style, it made the concept a little clearer for me.
function test () {
this.that = this;
this.root = this;
this.jCallback = new Array(new Array()); // 2d
this.jCallbackCount = -1;
this.str = "hello";
// Callback handler...
this.command = {
that : this, // let's keep a reference to who's above us on the food chain
root : this.root, // takes us back to the main object
// add : function() { var that = this; console.log(that.that.str); },
add : function(targetFnc, newFunc) {
var that = this;
var home = that.that; // pretty much root but left in as an example of chain traversal.
var root = this.root; // useful for climbing back up the function chain
// console.log(that.that.str);
home.jCallbackCount++;
// target, addon, active
home.jCallback[home.jCallback.length] = { 'targetFunc' : targetFnc, 'newFunc' : newFunc, 'active' : true, 'id': home.jCallbackCount};
console.log('cbacklength: ' + home.jCallback.length);
console.log('added callback targetFunction:[' + targetFnc + ']');
return home.jCallbackCount; // if we want to delete this later...
},
run : function(targetFnc) {
var that = this;
var home = that.that;
console.log('running callback check for: ' + targetFnc + ' There is : ' + (home.jCallbackCount + 1) + 'in queue.');
console.log('length of callbacks is ' + home.jCallback.length);
for(i=0;i < home.jCallback.length - 1;i++)
{
console.log('checking array for a matching callback [' + targetFnc + ']...');
console.log('current item: ' + home.jCallback[i]['targetFunc'] );
if( home.jCallback[i]['targetFunc'] == targetFnc )
{
// matched!
home.jCallback[i]['newFunc']();
}
// console.log(that.that.jCallback[i].targetFunction);
}
}
};
}
test.prototype = {
say : function () {
var that = this;
console.log('inside');
// that.command('doSay');
that.command.run('doSay');
console.log(that.str);
}
} // end proto
// BEGIN TESTING **************************************************************************
// BEGIN TESTING **************************************************************************
// BEGIN TESTING **************************************************************************
var testing = new test();
testing.command.add('doSay', function () { console.log('213123123'); } );
testing.command.add('doSay', function () { console.log('12sad31'); } );
testing.command.add('doSay', function () { console.log('asdascccc'); } );
testing.say();
live:
http://jsfiddle.net/Ps5Uf/
note: to view console output, just open inspector in chrome and click on the "console" tab.

JavaScript refer to a method inside a method?

Ok, just solved one problem where this refered to the wrong scope. Now I have another problem.
So I want to call a method that is inside a method. But I do not know how, check this source:
function someObj() {
var self = this;
this.someMethod1 = function() {
var elementBtn = document.getElementById('myBtn');
elementBtn.onclick = function() {
self.someMethod2.methodMethod();
//I want this.someMethod2.methodMethod() to be called
//...but I get an big error instead. Is it even possible?
//this.someMethod2() works fine.
};
};
this.someMethod2 = function() {
this.methodMethod = function() {
alert('THIS IS THE ONE I WANTED!');
};
alert('NO, NOT THIS!');
};
}
Error msg:
Uncaught TypeError: Object function () { ...
With your code, someMethod2 would need to execute first for the function expression to be assigned. Even then, it would be assigned to the parent instance.
Bearing in mind that all functions are objects in JavaScript, this is what you want instead:
this.someMethod2 = function() {
alert('NO, NOT THIS!');
};
this.someMethod2.methodMethod = function() {
alert('THIS IS THE ONE I WANTED!');
};
You are trying to use an object accessor on a function. If you want it to work in this way, you need to return an object literal from your call to the "outer" function.
this.someMethod2 = function() {
return {
methodMethod: function() {
alert('THIS IS THE ONE I WANTED!');
}
}
};
You can then chain the call. self.someMethod2().methodMethod();
While this is not directly possible, you can pass a "command" to the outer function to tell it to execute the inner function. But, are you sure this is what you really need? Perhaps you should use objects instead of functions here. But here's the "command" way:
this.someMethod2 = function(cmd) {
var methodMethod = function() {
alert('THIS IS THE ONE I WANTED!');
};
if (cmd === "methodMethod") {
methodMethod();
return;
}
alert('NO, NOT THIS!');
};
function someObj() {
var self = this;
this.someMethod1 = function () {
var elementBtn = document.getElementById('myBtn');
elementBtn.onclick = function () {
self.someMethod2().methodMethod();
};
};
this.someMethod2 = function () {
this.methodMethod = function () {
alert('THIS IS THE ONE I WANTED!');
};
//return this for chain method.
return this;
};
}
trying
function someObj() {
var self = this;
this.someMethod1 = function() {
var elementBtn = document.getElementById('myBtn');
elementBtn.onclick = function() {
self.someMethod2().methodMethod();
};
this.someMethod2 = function() {
this.methodMethod = function() {
alert('THIS IS THE ONE I WANTED!');
};
alert('NO, NOT THIS!');
return this;
};
}
Also if you use prototype then
function someObj() {
var self = this;
this.someMethod1 = function() {
var elementBtn = document.getElementById('myBtn');
elementBtn.onclick = function() {
self.someMethod2.methodMethod();//['methodMethod']();
};
};
this.someMethod2 = function() {
};
this.someMethod2.methodMethod = function() {
alert('THIS IS THE ONE I WANTED!');
};
};
But the method methodMethod is static

Categories