this.something = this.something.bind(this)
What is the above line actually doing? I am a newbie so please give a elementary level of explanation(for my understanding) also in a technical way
What is the above line actually doing?
Use of the JavaScript 'bind' method
bind creates a new function that will have this set to the first parameter passed to bind().
This is necessary because in the DOM library and many parts of JavaScript the hidden/implicit this function parameter is changed to point to different objects behind-the-scenes.
A good example concerns event-handlers in JavaScript, where the this parameter is not what it seems:
HTML:
<button id="someButton" name="Bar">Hello</button>
JavaScript (run after DOM is loaded):
function Foo() {
this.name = "Foo";
}
Foo.prototype.eventHandler( event ) {
console.log( event.type ); // will always print "click"
console.log( this.name ); // will print either "Foo" or "Bar"
}
var button = document.getElementById("someButton"); // HTMLButton
var fooInstance = new Foo(); // fooInstance.name == "Foo"
button.addEventListener( 'click', fooInstance.eventHandler );
If you run this code and click the button and set a breakpoint in Foo.prototype.eventHandler then you'll see that this.name is "Bar" and not "Foo" - even though you passed in a reference to fooInstance.eventHandler which surely knows about fooInstance when invoked?
It doesn't.
This is because the DOM API changes the this of fooInstance.eventHandler to be the button instance instead. I don't know the exact reason, but I believe it's related to maintaining backwards compatibility with old-school HTML-attribute based JavaScript event-handlers like these:
<button onclick="alert(this.name)" name="Baz">Click me</button>
(Where this refers to the containing HTMLElement)
So using .bind overrides the library's changing of this. You might think that as .bind(this) returns another Function that the this parameter will be changed anyway, but in fact, it doesn't. This is because the Function returned actually cannot have its this member changed at all, unlike most Function objects.
In ReactJS:
The use of foo = foo.bind(this) isn't anything unique to ReactJS (it's part of JavaScript) but it is an idiom in ReactJS:
why do you need to bind a function in a constructor
This is because React didn't want to mess with ES6 specifications (binding this to functions from its class is not in the ES6 class spec), but at the same time, wanted to give its users the convenience of ES6 class syntax. You can read more about this below.
Related
I am using angularJS 1.5 component in my application. sample code of component's controller as bellow:
function testController()
{
var vm = this;
activate(); // this will be called on first load on component.
vm.testMethod = function ()
{
return "test Method";
}
function activate()
{
console.log(vm.testMethod());
}
when I execute this I am getting error
TypeError: vm.testMethod is not a function.
I know I can create a local function to controller not appending vm., however, in my need, I have a vm.testMethod() used in template to get return some text, which is working properly. e.g.
--template code
{{$ctrl.testMethod()}} // This works properly and display 'test Method' on page.
Due to some reason, I am trying to call vm.testMethod() inside another method e.g. activate(), however getting an error mentioned above?
May I know if am missing anything or trying something which is not possible.
Your issues does not have anything to do with Angular :-)
Your activate function is hoisted because it is a function declaration. That why you can call it "before your wrote it". BUT, vm.testMethod is a function expression and won't get hoisted.
Here is a super simple example that shows the issue your having:
var vm = {};
console.log(vm.hello);
vm.hello = function () {};
console.log(vm.hello);
I would recommend you to read this article for a better understanding of how expressions and declarations work in JavaScript. Also, in order to prevent this from happening again you should follow this advice from John Papa:
Always write function declarations at the bottom of your controller and assign them at the top when you defined your vm variable.
I saw some code in the existing code base:
angular.module("myApp", [])
.service("myService", function() {
return {
getData: function() { } // etc ...
};
});
I think the concept is this: if it is module.factory(), you provide a function to return an object (which is the service object), versus, if it is module.service(), you provide a function, which is in fact just a constructor function, so that later on, a new keyword will be used with this constructor function to obtain the service object.
However, the code above surprisingly actually works. It apparently is due to the fact that, if it is taken to be a constructor function (even though it is not), when the new keyword is used with it, it returns an object, so this object is return instead of the object instantiated with the new keyword. But the fact is, it still works.
So is it true that even when we should use module.factory(), using module.service() actually works. Is there any side effect?
I think it is best to be changed back to module.factory(), but at the same time, I am afraid if everything works now, changing it back to module.factory() may introduce new bugs.
I'm currently in the progress of learning Backbone.js and I'm using the book Developping Backbone Applications.
I have a questions about the reference to HTML elements and how they are stored. For example:
initialize: function() {
this.$input = this.$('#new-todo');
Here the HTML element with ID to-do is stored in the this.$input, why do we use the $ in front of input, is this merely a convention? If I change this.$input to this.input my code works fine. I find this confusing because the book states:
The view.$el property is equivalent to $(view.el) and view.$(selector) is equivalent to $(view.el).find(selector).
I would think that $(view.el) does something completely different than (view.el).
How is this.$input saved in Backbone.js? If I console.log it, it produces:
Object[input#new-todo property value = "" attribute value = "null"]
Could someone give me some insight? :)
Using $ infront of a variable name is just a naming convention. It helps developer in distinguishing variable holding jQuery objects from others.
view.$el is a helper variable provided by Backbone, so that we can use it directly, instead of explicitly forming the jQuery object. Hence view.$el is equivalent to $(view.el).
view.$el is assigned in setElement method:
setElement: function(element, delegate) {
// Some code
this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
// Some code
}
Backbone.$ is reference to $ global variable exported by jQuery.
view.$(selector) is a method defined in View. It's definition does exactly same as $(view.el).find(selector)
$: function(selector) {
return this.$el.find(selector);
}
Motivation: I want to wrap all functions within backbone model with log functionality to make it more easy to follow function calls.
I am iterating over models functions and warping them with underscores wrap().
But it looks like event function bindings from 'events' hash doesn't get wrapped as it looks like these functions are copied and stored somewhere in DOM, not sure.
Has anybody came to this problem as well or any ideas how to workaround?
Manually entering console.log() in these function is not what I am looking for.
I think you're experiencing the same problem as when people are trying to test the functionality provided with the events -hash. Spying on the event callback directly on the View doesn't work, but spying on the class prototype before instantiating works.
// This won't work
var view = new SomeView();
spyOn(view, 'onClick');
view.$el.click(); // spy isn't called
// This works
spyOn(SomeView.prototype, 'onClick');
var view = new SomeView();
view.$el.click(); // spy is called
Try iterating over the prototype of your 'class' right after creating it, because that should be where the methods called by the events -implementation should reside.
I need to execute some code both on initialize and render methods, but as I understand, I canot just modfy them directly when using Chaplin - when I define my own initialize method, my routes stop working.
I also tried afterInitialize() but it seems its not meant to be overrided: https://github.com/chaplinjs/chaplin/issues/168#issuecomment-8015915
[...] but as I understand, I canot just modfy them directly when using
Chaplin
You can modify them directly as long you appropriately delegate to the extended prototype.
As you haven't tagged your question javascript or coffeescript, the following are two solutions for each one. First up is javascript. Notice how we must explicitly invoke the extended function.
var View = Chaplin.View.extend({
initialize: function(options) {
// Add code here ..
// The below invokes the initialize function of the
// base Chaplin.View class in the context of
// this class
Chaplin.View.prototype.initialize.call(this, arguments);
// .. or here
}
});
Next is coffeescript, which makes this kind of thing significantly easier.
class View extends Chaplin.View
initialize: ->
// Add code here ..
// The below auto-magically invokes the
// initialize method of the base class
super
// .. or here