Having trouble understanding why JSLint is surprised by my use of this
in the following code:
function testConstr (x) {
'use strict';
this.joker = "Whyyy sooo seriousss?";
this.x = x;
}
For both property assignments, JSLint says: Unexpected 'this'. How do I correct my code?
Your code might be perfectly correct (it might also be problematic, depending on how you call testConstr
).
My suggestion is: tell JSLint to shut up
Or don't use JSLint at all.
So in other words, JSLint doesn't automatically expect me to use a constructor pattern?
You know, I think you're right. Your question bugged me, and I signed up for Crockford's JSLint discussion group and asked. He replied, but ignored the solution I'm going to present, below, which I think means that it's okay, the same way JSLint doesn't complain if something passes muster.
(I'm still waiting for an updated Good Parts, though.)
That caveat aside, here's what I'd suggest doing for OO JavaScript that passes Beta JSLint (as of today, anyhow).
I'm going to rewrite an example from MDN's page, "Introduction to Object Oriented Programming," which itself uses this
liberally.
this
Here's the original, unlinted MDN example from the section linked, above:
var Person = function (firstName) {
this.firstName = firstName;
};
Person.prototype.sayHello = function() {
console.log("Hello, I'm " + this.firstName);
};
var person1 = new Person("Alice");
var person2 = new Person("Bob");
// call the Person sayHello method.
person1.sayHello(); // logs "Hello, I'm Alice"
person2.sayHello(); // logs "Hello, I'm Bob"
That follows the conventions we know and love.
this
It's pretty easy to figure out how to make "constructors" that don't follow that pattern, but we lose use of prototype
, if I'm not missing something, and have to include all of the object's methods in our constructor that we want all of our Peep
s to share.
/*jslint white:true, devel:true */
var Peep = function(firstName) {
"use strict";
var peep = {};
peep.firstName = firstName;
peep.innerSayHello = function() {
console.log("Hello, I'm " + peep.firstName + ".");
};
return peep;
};
var peep1 = new Peep("Bob");
var peep2 = new Peep("Doug");
peep1.innerSayHello();
peep2.innerSayHello();
So there's a lintable alternative. That does, other than the return peep;
and the inner definition of methods, make JavaScript act like many OO-first languages you might encounter. It's not wrong, at least.
Not having access to prototype
isn't horrible; it's really bad news to change prototype
somewhere that's not right beside the constructor, as your code would go to spaghetti. "Some Person
s have sayGoodbye()
and some don't, depending on if we'd amended the prototype at the point of their construction." That's awful. So this alternative convention has its advantages.
You can still, of course, add functions to a single instantiation of Peep
later, but I'm not sure how you'd access firstName
without using this
, so perhaps he wants us to stop munging objects after construction.
person1.sayGoodbye = function (other) {
console.log("Goodbye, " + other + ".");
};
(I mean, we could also still monkey-patch Peep
to change it mid-process, but that's horrible, stupid programming. Usually.)
this
)And inheritance is easy enough, I think.
var PeepWithGoodbye = function (firstName) {
"use strict";
var peepWithGoodbye = new Peep(firstName);
peepWithGoodbye.innerSayGoodbye = function (otherPeep) {
if (undefined === otherPeep) {
otherPeep = { firstName: "you" };
}
console.log("This is " + firstName
+ " saying goodbye to " + otherPeep.firstName + ".");
};
return peepWithGoodbye;
};
var pwg1 = new PeepWithGoodbye("Fred");
pwg1.innerSayHello(); // Hello, I'm Fred.
pwg1.innerSayGoodbye(peep1); // This is Fred saying goodbye to Bob.
pwg1.innerSayGoodbye(); // This is Fred saying goodbye to you.
EDIT: See also this answer where the asker later found Crockford's suggested means of creating OO javascript. I'm trying to convince that guy to delete that Q&A and move the A here. If he doesn't, I'll probably add his stuff and community wiki it here.
EDIT: See this from MDN for why it works:
(Normally constructors don't return a value, but they can choose to do so if they want to override the normal object creation process.)
In a strict mode this
reference is set to undefined
.
So both your statements will cause reading properties of the undefined
object, which will lead to an exception.
How do I correct my code?
Remove both those lines.
UPD: what I state above is how JSLint treats your code, not how I do that.
'use strict';
var SudoConstructor = (function () {
/* We need bind, < IE9 needs a (tiny) polyfill */
function protoEsqDeclare(sudoThis) {
return sudoThis;
}
function protoEsqSet(sudoThis, newValA, newValB) {
sudoThis.valA = newValA;
sudoThis.valB = newValB;
}
function instanceCreator(valA, valB) {
var sudoThis = {
valA: valA,
valB: valB
};
return {
declare: protoEsqDeclare.bind(null, sudoThis),
set: protoEsqSet.bind(null, sudoThis)
};
}
return instanceCreator;
}());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With