Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSLint Error: Unexpected 'this'

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?

like image 243
jdw Avatar asked May 19 '15 00:05

jdw


4 Answers

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

enter image description here

Or don't use JSLint at all.

like image 79
Oriol Avatar answered Nov 16 '22 00:11

Oriol


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.

With 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.

Without 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 Peeps 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 Persons 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.)

Inheritance (without 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.)

like image 37
ruffin Avatar answered Nov 15 '22 22:11

ruffin


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.

like image 3
zerkms Avatar answered Nov 15 '22 23:11

zerkms


'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;

}());
like image 3
Lee Avatar answered Nov 15 '22 23:11

Lee