(function() {
LoggerBase.prototype.output = function(message) {
console.log('LoggerBase: ' + message);
};
function BookAppLogger() {
LoggerBase.call(this);
this.logBook = function(book) {
console.log('Book: ' + book.title);
}
}
BookAppLogger.prototype = Object.create(LoggerBase.prototype);
}());
In this code the BookAppLogger inherits the prototypes of the LoggerBase object, I think that is clear from the last statement. What I don't understand is the purpose of the LoggerBase.call(this) statement. What does this line do and why is it neccessary?
BookAppLogger.prototype = Object.create(LoggerBase.prototype);
will only add LoggerBase.prototype functions to BookAppLogger.prototype but you cannot inherit the functions/properties that are written inside LoggerBase function. For example if LoggerBase is something like
function LoggerBase () {
this.fname = "First";
this.lname = "Last";
this.fullname = function(){
return this.fname + " " + this.lname;
}
}
LoggerBase.prototype.somefunction = function(){}
If you do not write LoggerBase.call(this) inside BookAppLogger, then only only LoggerBase somefunction is inherited but not fname, lname, fullname
Its just calling the base class constructor
LoggerBase is a function object and the call method of a function can be used to call that function with a specific this value. Calling LoggerBase directly would result in this being the global object, which in a browser is the window object.
function LoggerBase() {
console.log(this);
}
function BookAppLogger() {
LoggerBase.call(this); // will print the book logger
LoggerBase(); // will print the global object
}
BookAppLogger.prototype = Object.create(LoggerBase.prototype);
Related
This is the most basic JS object example I can think of that illustrates my questions.
Question 1.
How can I reference functions within a class so that in other code I could call a method? This gives me an error.
var name1 = new Name();
name1.render();
Question 2.
What is the difference between declaring functions in-line like this vs. using var getByID = function() ...?
Example object:
function Name(user_id, container_id) {
this.userID = user_id;
this.containerID = container_id;
this.firstName = null;
this.lastName = null;
function getByID(userID) {
// An ajax call that takes a userID to get a name.
}
function setName() {
// An ajax call to get the name from db.
name_record = this.getByID(this.userID); ????? this returns an error that getByID is undefined.
this.firstName = name_record.firstName;
this.lastName = name_record.lastName;
}
function render() {
$(this.containerID).val(this.firstName + ' ' + this.lastName);
}
}
You can declare an object like you done in your second question, it's valid because a function is an object too. Or other ways like:
var Name = {
render: function() {
}
}
Name.render();
Or with prototype:
function Name() {
}
Name.prototype.render = function() {
}
// or
Name.prototype = {
getByID: function() {
},
setName: function() {
}
}
var n = new Name();
All these snipets are a valid object declaration.
Your second question may answer the first ones. When you declare a function like this:
function Name() {
function render() {
}
}
var n = new Name();
It is like render() be a private method. if you call outside the function name n.render(), you will see an error thrown because render is not recognized. But if you change to this...
function Name() {
this.render = function() {
}
}
... then n.render() will work like render() being a public method. See this and this for further information about public and private methods.
Now, the difference between declaring a function "in-line" or setting it to a variable is that with this:
function Name() {
}
You can do:
var n1 = Name();
var n2 = Name();
var nn = Name(); // and so on...
But with:
var n = function Name() {
}
Is that n() will work and Name() will not. Even var a = Name() will throw an exception.
Here's a good article about this subject that worth a read. I hope it can help.
Question 1:
A "Class" in Javascript is nothing more than an object. An object has properties which you can access. Those properties are either variables, functions, or other objects. By declaring your function like:
function render() {
$(this.containerID).val(this.firstName + ' ' + this.lastName);
}
You are declaring a function within the scope of function Name() but that function isn't a property of Name. It's just a private method. There are multiple ways you could make it a part of Name(), such as:
function Name(user_id, container_id) {
this.userID = user_id;
this.containerID = container_id;
this.firstName = null;
this.lastName = null;
this.render = function() {
console.log('hello world');
}
}
var name1 = new Name();
name1.render();
Question 2:
There is no difference. They are simply two different syntax's that achieve the same result. The second way (declaring a var and defining the function) immediately gives you a reference to the function, but that can be achieved just as well the first way.
Answer to your first question:
Functions getByID,setName and render are local to the constructor and cannot be called by class object. You have to use prototypal inheritance.
for eg.
function Name(user_id, container_id) {
this.userID = user_id;
this.containerID = container_id;
this.firstName = null;
this.lastName = null;
}
Name.prototype = {
getByID :function(userID) {
// An ajax call that takes a userID to get a name.
}
setName:function() {
// An ajax call to get the name from db.
name_record = this.getByID(this.userID);
this.firstName = name_record.firstName;
this.lastName = name_record.lastName;
}
render:function() {
$(this.containerID).val(this.firstName + ' ' + this.lastName);
}
};
Answer to your second question:
in case of
abc();//Error
function abc(){
}
this function is created at run time , so you can call it only after declaration
however, this
abc();
var abc = function(){
};
is created at parse time so you can call it before declaration.
How would you recommend I convert this JavaScript to TypeScript?
JAVASCRIPT:
function MyClass() {
var self = this,
var1 = "abc",
var2 = "xyz";
// Public
self.method1 = function () {
return "something " + self.var1;
};
self.method2 = function (parm1) {
var x = self.method1();
return x + " something";
};
// Private
function func1(parm1, parm2) {
return parm1 + parm2;
}
}
This is what I would like to do in TypeScript, or at least how I would expect to write it:
module MyNamespace {
export class MyClass {
private var1: string = "abc";
private var2: string = "xyz";
constructor() {
}
// Public
public method1() {
return "something " + self.var1;
}
public method2(parm1) {
var x = this.method1();
return x + " something";
}
// Private
private func1(parm1, parm2) {
return parm1 + parm2;
}
}
}
But the generated JavaScript puts everything on the prototype and I will have some "this" scoping issues:
var MyNamespace;
(function (MyNamespace) {
var MyClass = (function () {
function MyClass() {
this.var1 = "abc";
this.var2 = "xyz";
}
// Public
MyClass.prototype.method1 = function () {
return "something " + this.var1;
};
MyClass.prototype.method2 = function (parm1) {
var x = this.method1();
return x + " something";
};
// Private
MyClass.prototype.func1 = function (parm1, parm2) {
return parm1 + parm2;
};
return MyClass;
})();
MyNamespace.MyClass = MyClass;
})(MyNamespace || (MyNamespace = {}))
I know I can declare the methods within the constructor, use lambda functions to get "_this" instead of "this", etc. but what are the best practices of "porting to TypeScript"?
But the generated Javascript puts everything on the prototype
I think that's what you want to happen. The only time it creates a "this" issue is when you want to pass the function as a callback. That's a known concern when passing callbacks and when doing so is the right time to worry about it. To me it feels like the JavaScript way and it's better to embrace the system rather than fight it.
If every instance has a unique function closure you're using a lot more memory or at a minimum creating way more work for the optimizer.
I think the porting you have there looks right. You should consider letting class methods stay on the prototype for memory, performance, and reusability reasons. But if you have some methods you really want to be on the instance for the purposes of keeping this, you can use the member initialization + lambda syntax:
class MyClass {
greeting = 'hello, ';
/** someFunc is safe to use in callback positions */
someFunc = (msg: string) => {
console.log(this.greeting + msg);
}
}
JavaScript determines the value of this when calling/invoking the method, not when you declare it. https://stackoverflow.com/a/16063711/1641941 (under "The this variable")
To set the right context you can use =>
class MyClass {
greeting = 'hello, ';
someFunc(msg: string) {
console.log(this.greeting + msg);
}
}
var m = new MyClass();
setTimeout(() => {m.someFunc("hello")},100);
setTimeout will be passed a closure that is created in the current scope.
If you were to set an interval or event handler and the current scope has a very large irrelevant variable(s) in it then it's better to declare a function that returns the closure somewhere outside of the current scope and pass it the only the variables that are relevant for this closure.
Code that will return a closure function for you and limit scope:
class MyClass {
greeting = 'hello, ';
someFunc(msg: string) {
console.log(this.greeting + msg);
}
public static closures ={
someFunc(me:MyClass,msg:string){
return function(){
me.someFunc(msg);
};
}
}
}
var m = new MyClass();
setTimeout(MyClass.closures.someFunc(m,"hello"),100);
See the simplified code. What am I not getting with this pattern?
var john = new person('john');
john.hi();
function person(name) {
this.name = name;
}
person.prototype.hi = function() {
console.log('hi there. Name is ' + this.name);
};
If there's anything wrong it is the order of things. Other than that this seems correct.
function person(name) {
this.name = name;
}
person.prototype.hi = function() {
console.log('hi there. Name is ' + this.name);
};
var john = new person('john');
john.hi();
You could also add prototype function after the creation of your object, and this function can be called by all the instances, even those created before. Because when you call a function, the prototype chain will be searched if no function is found on your object itself.
How to pass values to super class constructors in Javascript.
In the following code snippet
(function wrapper() {
var id = 0;
window.TestClass = TestClass;
function TestClass() {
id++;
this.name = 'name_' + id;
function privateFunc() {
console.log(name);
}
function publicFunc() {
privateFunc();
}
this.publicFunc = publicFunc;
}
function TestString() {
this.getName = function() {
console.log("***" + this.name + "****************");
}
}
TestClass.prototype = new TestString();
})();
How do I pass values to the TestString constructor? Currently, the super class method is using value using 'this' keyword. Is there a way to directly pass values to the super class constructor. Also, I want to see a simple example of extending String. That would demystify a lot of things.
You can use the following code in the constructor of TestClass().
TestString.apply(this, arguments);
This will call the constructor with the new object as its context.
However, note that establishing the [[Prototype]] chain with TestClass.prototype = new TestString(); will have already called the constructor once.
jsFiddle.
I want to see a simple example of extending String.
You can augment its prototype property.
String.prototype.endsWidth = function(str) {
return this.slice(-str.length) === str;
};
I have the following javascript
function person() {
//private Variable
var fName = null;
var lName = null;
// assign value to private variable
fName = "Dave";
lName = "Smith";
};
person.prototype.fullName = function () {
return this.fName + " " + this.lName;
};
var myPerson = new person();
alert(myPerson.fullName());
I am trying to get an understanding of object orientated techniques in javascript. I have a simple person object and added a function to its prototype.
I was expecting the alert to have "Dave Smith", however I got "underfined underfined". why is that and how do I fix it?
Unfortunately you can't access a private variable. So either you change it to a public property or you add getter/setter methods.
function person() {
//private Variable
var fName = null;
var lName = null;
// assign value to private variable
fName = "Dave";
lName = "Smith";
this.setFName = function(value){ fName = value; };
this.getFName = function(){ return fName; }
};
see javascript - accessing private member variables from prototype-defined functions
But actually this looks like what you are looking for:
Javascript private member on prototype
from that SO post:
As JavaScript is lexically scoped, you can simulate this on a per-object level by using the constructor function as a closure over your 'private members' and defining your methods in the constructor, but this won't work for methods defined in the constructor's prototype property.
in your case:
var Person = (function() {
var store = {}, guid = 0;
function Person () {
this.__guid = ++guid;
store[guid] = {
fName: "Dave",
lName: "Smith"
};
}
Person.prototype.fullName = function() {
var privates = store[this.__guid];
return privates.fName + " " + privates.lName;
};
Person.prototype.destroy = function() {
delete store[this.__guid];
};
return Person;
})();
var myPerson = new Person();
alert(myPerson.fullName());
// in the end, destroy the instance to avoid a memory leak
myPerson.destroy();
Check out the live demo at http://jsfiddle.net/roberkules/xurHU/
When you call person as a constructor, a new object is created as if by new Object() and assigned to its this keyword. It is that object that will be returned by default from the constructor.
So if you want your instance to have properties, you need to add them to that object:
function Person() {
// assign to public properties
this.fName = "Dave";
this.lName = "Smith";
};
Incidentally, by convention functions that are intended to be called as constructors are given a name starting with a capital letter.
You're declaring those variables as local to the function, instead of making them part of the object. In order to put them in the instance, you've got to use 'this' in the constructor as well. For example:
function person() {
this.fName = 'Dave';
this.lName = 'Smith';
}
person.prototype.fullName = function () {
return this.fName + " " + this.lName;
};
var myPerson = new person();
alert(myPerson.fullName());
In the constructor you should assign your variables to this:
this.fName = null;
this.lName = null;
But then they are not private. JavaScript does not have private variables like a "classic" Object Oriented language. The only "private" variables are local variables. An alternative to the above is to assign getter/setter methods to this within the constructor.