简体   繁体   中英

Why doesn't this method call work from within a prototype?

I'm trying to learn how to write better javascript but I'm not sure why this doesn't work. I have two method calls that write to a text field. The first one works fine, but the second one doesn't. Why is the text field variable undefined going thorough a nested call? Any help would be appreciated:

(function () {
    var TestObj = function (logEl) {
        this.log = logEl;
    };

    TestObj.prototype = function () {
        var log1 = function (text) {
            this.log.val(text);
        };

        var log2 = function (text) {
            log1(text);
        }

        return {
            log1: log1,
            log2: log2
        };
    }();

    $(function () {
        var logEl = $("#log");
        var test = new TestObj(logEl);
        test.log1("This Works");
        test.log2("This Dosen't"); //this.log is undefined
    });
})()

In the second case, log1 is being called without any context. The value of this when being called from log2 will be the global object, not an instance of TestObj.

Try changing it to:

var log2 = function (text) {
    this.log1(text);
}

demo fiddle

I believe the issue is related to not using this in log2 :

var log2 = function (text) {
    this.log1(text);
}

A fiddle example: http://jsfiddle.net/y66YT/

As dc5 and Hayes pointed out the value of this is the invoking object. It's the object that comes before the function:

somebutton.click();//this is somebutton
click();//nothing before click, window is assumed or throw exception in strict mode
myObject.doSomething();//this in doSomething is myObject

Since log1 is available through closures it doesn't throw an exception immediately (log1 is undefined) but this in log1 function is window since log2 didn't provide an invoking object.

To set the invoking object you could change code to:

 log1.call(this,text);

I'm not a big fan of throwing everything including the kitchen sink in IIFE as it creates unneeded closures for every method. You can wrap your application an an object literal instead and use IIFE where you actually need closures :

var app ={
  testObj:function(...

log1 won't be available through closures in log2 but you can call it using this

 this.log1(text);

More on prototype, constructor functions, inheritance and the value of this can be found here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM