Typescript object literal "this" keyword - javascript

What's the expected behavior when using this inside a function in an object literal?
For example, let's say I have a type foo that only has a function named bar and no other property on it. But in the fooObj.bar method, I'm able to access this.baz (where baz is not a property on type foo) I see no error. Shouldn't typescript error out, as fooObj does not have baz on it?
type foo = {
bar(): void;
}
var fooObj: foo = {
bar: () => {
// TS does not error out when I access this.baz
console.log(this.baz);
}
}

Setting the "noImplicitThis": true compiler option is how you would enable this functionality now. This pull request enabled typed this in object literals. Aleksey L originally suggested this compiler option in a comment on the question, but at the time it didn't function that way.

You’re using an arrow function, which has lexical this.
The shorthand for a non-arrow function property in an object literal is even shorter, though:
var fooObj: foo = {
bar() {
console.log(this.baz);
}
}

This answer was true at the time of the question. This have since changed with new versions of typescript and target javascript versions.
You are asking typescript to infer that this is fooObj.
Typescript binds this by creating a local variable _this, that is bound to the this-context where the fat-arrow is declared. And in your case, this is the global scope, which is any. This is what it gets compiled into:
var _this = this;
var fooObj = {
bar: function () {
// TS does not error out when I access this.baz
console.log(_this.baz);
}
};
This is how it looks like within a class:
class Bar
{
private var = 23;
public makeSound = () => console.log(this.var)
}
// Compiles into:
var Bar = (function () {
function Bar() {
var _this = this;
this.var = 23;
this.makeSound = function () { return console.log(_this.var); };
}
return Bar;
}());

Related

What does this JavaScript code return for bar, baz, and biz function calls?

Learning JavaScript Fundamentals, confused on what the function calls return.
I have an idea of f.bar returns 7 because when the f object is created it gets access to functions of Foo that have the "this" keyword. Also I believe f.baz returns an error because this function is only available locally and does not use the "this" keyword which makes it unavailable outside Foo. f.biz I am confused but I do know the Prototype keyword allows for inheritance of Foo properties.
An explanation for each function call would be awesome, thank you everyone!
var Foo = function(a){
this.bar = () => {
return a;
}
var baz = function(){
return a;
}
Foo.prototype = {
biz: () => {
return this.bar();
}
}
}
var f = new Foo(7);
f.bar();// what does this return?
f.baz(); // what does this return?
f.biz(); // what does this return?
As it is now, only the bar function will work as intended.
The baz function is in a local variable, so it's only accessible inside the Foo function as baz but not as this.baz (variables and instance properties (this.whatever) are not connected in any way).
The case of biz is a bit more complicated. Normally, that's more or less how you'd create a prototype method, but you did it in the wrong place. It should be outside the function, because the way it is now, it's:
reassigned on every call of new Foo() (unnecessary)
assigned only after the current instance is created, so it will take effect only on the next instance (also if you used a in it (which you shouldn't), you'd find that it always has the a of the previous call)
You also don't want to use an arrow function when you want to "let JS set this" (arrow functions copy their this from where they were defined).
So, to make biz work, you have to do this:
var Foo = function(a){
this.bar = () => {
return a;
}
}
Foo.prototype = {
biz: function (){
return this.bar();
}
}
var f = new Foo(7);
console.log(f.bar());
console.log(f.biz());

Is there a way to have a constructor within an already existing constructor?

I have the following function that acts a base constructor:
function Foo() = {}
...
exports Foo
It's an empty constructor, and is used by other functions which I don't want to change. Also, Foo is only being exported from the file.
Now I need to create a different constructor perhaps within Foo.
The following is what I'd have with enum as a standalone constructor. But how do I make it a part of Foo?
function enum(data) {
this.data = data
}
enum.prototype.getVal() { return this.data; }
var obj = new enum(5);
obj.getVal();
Taking a completely wild guess from your commnets.
exporting from the file is of no real concern. If you're just using Foo as a namespace to "hang" functions off of you can do this:
Enum.js
// all constructors should be capitalized
function Enum() { }
Enum.prototype.whatever ...
exports Enum
Foo.js
const Enum = require('./Enum');
// it's unclear why `Foo` is even a function to be honest
function Foo() { }
Foo.Enum = Enum;
exports Foo
someOtherFile.js
const Foo = require('./Foo');
const myEnumInstance = new Foo.Enum();

Does ES2015 exported class create a closure?

As it's currently compiled via Babel + Webpack, module's exported class will create a closure: variables created inside the module will be shared between class instances.
bar.js:
let foo;
export default class Bar {
set foo(value) {
foo = value;
}
get foo() {
return foo;
}
}
app.js:
import Bar from './bar.js';
var barOne = new Bar();
var barTwo = new Bar();
barOne.foo = 'quux';
console.assert(barTwo.foo === 'quux');
I wonder if this behavour correct according to the spec.
I wonder if this behavour correct according to the spec.
Yes. JavaScript has lexical scope. That doesn't change with classes.
Keep in mind that classes are more or less just syntactic sugar for constructor function + prototype. Would you have had the same question if you wrote
let foo;
function Bar(){};
Bar.prototype = {
set foo(value) {
foo = value;
}
get foo() {
return foo;
}
};
module.exports = Bar;
instead?

JavaScript: Add prototype methods to inner class

I want to add a method to the prototype of an inner class. Is that possible?
This is what I tried:
var Foo = function Foo() {};
Foo.prototype = {
Bar: function Bar() { },
Bar.prototype: { // <- this does not work
barMethod: function () {
console.log('hello');
}
},
fooMethod: function () {
var bar = new this.Bar();
bar.barMethod();
}
}
var foo = new Foo();
foo.fooMethod();
But Bar.prototype doesn't work, it throws a SyntaxError with the message Unexpected token ..
Your problem is that you're defining the Foo.prototype object, and as such, you're bound to the rules and syntax of object creation, for example the parser expects you to list the attributes in a key: value, nextkey: nextvalue format, which Bar.prototype does not fit. (Keys are effectively strings, and it doesn't make sense to use . in them, as they would create ambiguity while parsing*)
Try this:
var Foo = function Foo() {};
Foo.prototype.Bar = function Bar() { };
Foo.prototype.Bar.prototype = {
barMethod: function () {
console.log('hello');
}
};
There's a slight semantic difference though, as this way you're not overriding the prototype, just extending it. (consider equaling it to {} first, then extending it with every attribute of the object you tried to create)
(*) A note on ambiguity: I mention above that having a . in your object key would create ambiguity, here's a simple example:
var foo = {
bar: {
baz: 0,
qux: 20
},
bar.baz: 150 //note that this will throw an error
};
console.log(foo.bar.baz);
If this code above wouldn't throw an error, what would you expect console.log(foo.bar.baz) to print, 0 or 150?
That's why it doesn't make sense to use . in a key, and that's why the parser throws the unexpected token error on any ..
Of course, you could use the "bar.baz" string as a key as "bar.baz": 150 above (please don't!), but then you'd have to reference the value as
foo["bar.baz"]
which would be distinctly different from
foo.bar.baz;
All in all, this is just some intuition-based reasoning behind why you can't use a . in your keys, but the real reason is plainly this: because the parser will throw an error.
In an object literal you can only define properties of that object literal, but not properties of the values.
However, if you want to set the prototype when creating the object, consider Object.assign (which can be polyfilled):
Foo.prototype = {
Bar: Object.assign(function Bar() { }, {
prototype: {
barMethod: function () {
console.log('hello');
}
}
}),
fooMethod: function () {
var bar = new this.Bar();
bar.barMethod();
}
};
However, note that replacing all the prototype is a bad practice because you erase the constructor property.

Best way to define a function?

I'm always learned to define a function in JavaScript like this:
function myFunction(arg1, arg2) { ... }
However, I was just reading Google's guide to Javascript, it mentioned I should define methods like this:
Foo.prototype.bar = function() { ... };
Question: Is "Foo" in the example an Object, or is it a namespace? Why isn't the Google example the following code (which doesn't work):
prototype.bar = function() { ... };
UPDATE: In case it helps to know, all of my JavaScript will be called by the users browser for my web-application.
Your two examples are not functionally equivalent. The first example simply defines a function (probably a global one, unless you define it inside another function). The second example extends the prototype of a constructor. Think of it as adding a method to the class Foo.
Unless you're building a JavaScript library, my suggestion would be to use neither and use some kind of namespace system. Create a single global object that acts as a namespace through which you can access all your functions.
var MyObject = {
utils: {
someUtil: function() {},
anotherUtil: function() {}
},
animation: {
// A function that animates something?
animate: function(element) {}
}
};
Then:
// Assuming jQuery, but insert whatever library here
$('.someClass').click(function() {
MyObject.animation.animate(this);
});
If you want to emulate classes in JavaScript, you would define the "class" as a function (the function itself being the constructor) and then add methods through the prototype property.
function Foo() {
// This is the constructor--initialize any properties
this.a = 5;
}
// Add methods to the newly defined "class"
Foo.prototype = {
doSomething: function() { /*...*/ },
doSomethingElse: function() { /*...*/ }
};
Then:
var bar = new Foo();
console.log(bar.a); // 5
bar.doSomething();
// etc...
I'm always learned to define a function in JavaScript like this:
function myFunction(arg1, arg2) { ... }
There are two ways to define a function. Either as a function declaration
function foo(...) {
...
}
Or as a function expression
var foo = function() {
...
};
Read more here.
However, I was just reading Google's guide to Javascript, it mentioned I should define methods like this: Foo.prototype.bar = function() { ... };
This is specifically related to method creation for objects, not just normal, stand-alone functions. Assuming you have the base object declaration:
var Foo = function() {
...
};
Just like any other assignment, to assign a function to an object's property, you must use an assignment expression. You can do this two ways. The succinct and common way (as suggested by Google's reference)
Foo.prototype.bar = function() {};
Or, if you want to continue to use the declarative form of defining functions
function bar() {
...
};
Foo.prototype.bar = bar;
This is normally more verbose than necessary, but may be useful in situations where you want to assign the same method to multiple object prototypes.
Question: Is "Foo" in the example an Object, or is it a namespace? Why isn't the Google example the following code (which doesn't work): prototype.bar = function() { ... };
Foo is an object. Although the concept can be expressed through the use of static objects, as I've shown in my answer to your other question, there is no such thing as namespaces in JavaScript. Further, especially in the example code given, Foo is likely intended to be an instantiated object, which precludes it from being behaving like a namespace.
Of course it doesn't work: prototype has not been defined as an object (unless, of course, you define it as such). The prototype property exists on every object (a function is also an object), which is why you can do Foo.prototype.bar = ...;. Read more here.
=====> 2017 Update <=====
This question and answers is 7 years old and is very outdated. This answer includes new syntax for versions of ES5, ES6, and compatible with ES7.
Best way to define a function?
There is no one "Best" way to define a function. How you define the function is dependent on the intended use and lifetime of the function.
Global functions
Defined as a statement with the function token followed by the function name with lowercase camelcase
function functionName (arguments) {
// function body
}
is preferable over the function expression...
var functionName = function (arguments) {
// function body
}
...as the assignment to the variable of the function does not occur until the defining line is executed. Unlike the prefered method which is available immediately after parsing before any code is executed.
const functionName = function(arguments){/*function body*/}
var functionName = function functionName(arguments){/*function body*/}
var functionName = function functionAltName(arguments){/*function body*/}
Function objects
As a function statement with uppercase camelcase function name
function MyObjectFunction (arguments) {
/*function body*/
// if this function is called with the new token
// then it exits with the equivalent return this;
}
const obj = new MyObjectFunction(foo);
Anonymous function expression.
A common practice is to create object via an immediately invoked function that has no name (and is hence anonymous)
;(function (arguments) { /*function body*/ } ("argument val"))
Or
;(function(arguments){ /*function body*/ })("argument val")
NOTE the inclusion of the ; befor the function. This is very important as the open "(" will prevent automatic semicolon insertion on any code above the function.
Immediately invoked function expression.
const functionResult = (function (arguments) {
/*function body*/
return functionResult;
}());
const functionResult = (function (arguments) {
/*function body*/
return functionResult;
})();
As a var or block scopedconst, let
Anonymous callback.
With ES6 you should use the arrow function syntax rather than anonymous function expressions.
myArray.forEach((item,i) => {/*function body*/});
myArray.filter(item => !item);
setTimeout(() => {/*function body*/}, 1000);
Function as properties.
Using the object declaration function shorthand syntax.
var myObj = {
functionName (arguments) {/*function body*/},
}
// called
myObj.functionName("arg");
is preferable over
var myObj = {
functionName : function (arguments) {/*function body*/},
}
Or via function object declarations
function MyObjectFunction(arguments){
this.propertyFunction = function(arguments) { /*function body*/ }
// or arrow notation is fine
this.propertyFunction = (argument) => { /*function body*/ };
}
Functions as prototypes
function MyObj (arguments) {
MyObj.prototype.functionName = function(arguments) { /*function body*/ }
}
or
function MyObj (arguments) {}
MyObj.prototype.functionName = function(arguments) { /*function body*/ }
or
MyObj.prototype = {
functionName(arguments) { /*function body*/ }
}
Defining a prototype function is useful when creating constructors or 'classes' in JavaScript. e.g. a func that you will new
var MyClass = function(){};
MyClass.prototype.doFoo = function(arg){ bar(arg); }
but is of no use in plain old library functions e.g.
function doPopup(message){ /* create popup */};
There are several benefits of using a prototype function including but not limited to
speed
memory usage
extensibility
But, again, this is in the context of creating constructors for instantiable 'classes'
HTH
It works like so:
(function(){ // create an isolated scope
// My Object we created directly
var myObject = {
a: function(x,y) {
console.log('a');
},
b: function(x,y) {
console.log('b');
this.a(x,y);
}
};
})();
(function(){ // create an isolated scope
// Create a Object by using a Class + Constructor
var myClass = function(x,y) {
console.log('myClass: constructor');
this.b(x,y);
};
myClass.prototype = {
a: function(x,y) {
console.log('myClass: a');
},
b: function(x,y) {
console.log('myClass: b');
this.a(x,y);
}
};
// Define a function that should never inherit
myClass.c = function(x,y) {
console.log('myClass: c');
this.a(x,y);
};
// Create Object from Class
var myObject = new myClass();
// Will output:
// myClass: constructor
// myClass: b
// myClass: a
// Define a function that should never inherit
myObject.d = function(x,y) {
console.log('myObject: d');
this.a(x,y);
};
// Test the world is roung
console.log(typeof myClass.c, 'should be undefined...');
console.log(typeof myClass.d, 'should be function...');
})();
(function(){ // create an isolated scope
// If you are using a framework like jQuery, you can obtain inheritance like so
// Create a Object by using a Class + Constructor
var myClass = function(x,y) {
console.log('myClass: constructor');
this.b(x,y);
};
myClass.prototype = {
a: function(x,y) {
console.log('myClass: a');
},
b: function(x,y) {
console.log('myClass: b');
this.a(x,y);
}
};
// Create new Class that inherits
var myOtherClass = function(x,y) {
console.log('myOtherClass: constructor');
this.b(x,y);
};
$.extend(myOtherClass.prototype, myClass.prototype, {
b: function(x,y) {
console.log('myOtherClass: b');
this.a(x,y);
}
});
// Create Object from Class
var myOtherObject = new myOtherClass();
// Will output:
// myOtherClass: constructor
// myOtherClass: b
// myClass: a
})();
(function(){ // create an isolated scope
// Prototypes are useful for extending existing classes for the future
// Such that you can add methods and variables to say the String class
// To obtain more functionality
String.prototype.alert = function(){
alert(this);
};
"Hello, this will be alerted.".alert();
// Will alert:
// Hello, this will be alerted.
})();
Edit: Fixed code so that it will actually run in your browser if you copy and paste :-)
Foo is both an Object and a namespace. See this question.
Using objects as namespaces prevents name collisions. That's always a good idea, but especially when you're developing and/or using shared libraries.
If you don't expect to be making multiple Foo objects (and so don't need the object-oriented style), you could create your functions as methods on a singleton object:
var Foo = {}
Foo.bar = function() { ... }
or
var Foo = {
bar: function() {...},
quux: function() {...}
};
You'd then simply call the function as:
Foo.bar()
(This kind of declaration is roughly equivalent to a static method in C++ or Java.)

Categories