【问题标题】:the 'this' key word with IIFE in javascriptjavascript中带有IIFE的'this'关键字
【发布时间】:2014-10-07 20:56:05
【问题描述】:

我正在从书中的一个示例中练习 java 脚本并遇到以下情况

代码一:在这里我学到了 javascript 中的“this”关键字引用了拥有“this”关键字所在代码的对象。

function Vehicle1(theYear, theMake, theModel) {
    var year = theYear;
    var make = theMake;
    var model = theModel;
    this.getYear = function () { return year; };
    this.getMake = function () { return make; };
    this.getModel = function () { return model; };
}

Vehicle1.prototype.getInfo = function () {
    return 'Vehicle1: ' + this.getYear() + ' ' + this.getMake() + ' ' + this.getModel();
}

代码二:这里我正在学习使用 IIFE(立即调用函数表达式)创建命名空间。

(function () {
    this.myApp = this.myApp || {};
    var ns = this.myApp;

    var vehicleCount = 5;
    var vehicles = new Array();

    ns.Car = function () { };
    ns.Truck = function () { };

    var repair = {
        description: 'changed spark plugs',
        cost: 100
    };
} ());

我应该单独执行上述代码以理解作者试图解释的概念。但我最终在单个文件中执行了这两个代码,并且我在代码一中收到错误消息说明

Uncaught TypeError: undefined is not a function Vehicle1.getInfo.myApp

问题是:IIFE 函数为何或如何尝试在代码 1 中放置或查找 myApp 命名空间?

如果我分别执行以上 2 个代码,所有代码都按预期工作。

编辑 这是完整的代码,只需使用脚本标签将其复制到 html 的头部。我在 chrome 中运行它并在控制台中查看错误详细信息

function Vehicle1(theYear, theMake, theModel) {
        var year = theYear;
        var make = theMake;
        var model = theModel;
        this.getYear = function () { return year; };
        this.getMake = function () { return make; };
        this.getModel = function () { return model; };
    };

    Vehicle1.prototype.getInfo = function () {
        return 'Vehicle1: ' + this.getYear() + ' ' + this.getMake() + ' ' + this.getModel();
    }


    (function () {
        this.myApp = this.myApp || {};
        var ns = this.myApp;

        var vehicleCount = 5;
        var vehicles = new Array();

        ns.Car = function () { };
        ns.Truck = function () { };

        var repair = {
            description: 'changed spark plugs',
            cost: 100
        };
    } ());

【问题讨论】:

  • “我知道'this'关键字引用了拥有'this'关键字所在代码的对象。” -- 不完全是。 this 在调用函数之前什么都不是。奇迹发生在newthis 将取决于您如何调用该函数。
  • 您是否创建了Vehicle1,如果是,您是否使用了new 运算符?因为听起来您只是输入了Vehicle1() 而不是new Vehicle1()
  • 你能发布给你这个错误的“组合”代码吗?就其本身而言,第二个 sn-p 应该没问题
  • 我认为如果你在组合代码中的 sn -p 2: ;(function () { 之前添加一个分号,错误将得到修复。
  • @user815923:是的,';'解决了这个问题。

标签: javascript design-patterns


【解决方案1】:

我在 javascript 中学习了 'this' 关键字引用了拥有 'this' 关键字所在代码的对象。

事实并非如此,但似乎有点像。

警告 - 以下内容听起来很愚蠢。那是因为 javascript this 是一个非常糟糕的语言功能(人们应该停止使用它)。

这就是交易 - 没有像 this 这样的东西。至少不是你想的那样。它实际上是一个函数参数,就像其他任何参数一样。

让我告诉你。

假设你有这样的功能

function sayHi(firstName, lastName) {
    console.log("Hi", firstName, " ", lastName);
}

这里有两种不同但几乎相同的调用方式:

sayHi("Fred", "Flintstone");
sayHi.call(null, "Fred", "Flintstone");

这是因为所有函数都有一个call 方法。如果您愿意,您可以使用.call 编写所有函数调用。

但是第一个null 参数是什么?嗯,这个参数就是 this 将被设置的。所以如果你有:

function sayHi(lastName) {
    console.log("Hi", this, " ", lastName);
}

你可以说

sayHi.call("Fred", "Flintstone");

所以现在让我问你一个问题。如果您始终可以使用.call 编写所有函数,并且如果.callthis 作为紧邻其他参数的参数,那么this 与任何其他参数究竟有何不同?只是一个你不知道的名字。

但是sayHi(...) 格式与this 有什么关系呢?由于我们没有直接指定它,它必须来自某个地方。好吧,以这种形式 - 这实际上只是 call 的一个门面 - javascript 猜测 你想要它是什么。规则不是很复杂,但仍然很混乱。

如果您将其作为对象调用

var fred = "Fred";
fred.sayHi = sayHi;
fred.sayHi("Flintstone");

等价于

fred.sayHi.call(fred, "Flintstone");

直接调用的情况下:

sayHi("Flintstone");

规则规定它会猜测this 是全局window 对象。除非您处于严格模式,否则它将是undefined(我认为,它可能是null)。

sayHi.call(window, "Flintstone");

这就是 IIFE 的情况。

基本上,this 是为了使它看起来更像 Java 而添加的一个功能,并且对于该语言来说实际上根本不需要。有些图书馆使用它,你别无选择,但我总是咨询人们,当他们完全可以控制它时they don't use this or new (which is even more confusing)

【讨论】:

    【解决方案2】:

    由于第一个代码后缺少分号而出现错误,导致以与预期完全不同的方式解释组合文件。

    让我们简化代码以查看结构。你有类似的东西:

    getInfo = function () {
        this.getYear();
    }
    
    (function () {
        this.myApp = {};
    } ());
    

    第一个函数后面没有分号,第二个函数的括号被视为给了调用第一个函数的参数:

    getInfo = function () {
        this.getYear();
    }(function () {
        this.myApp = {};
    } ());
    

    所以基本上就像你写的一样:

    function getInfo() {
        this.getYear();
    }
    
    getInfo(function () {
        this.myApp = {};
    }());
    

    this 在这两种情况下都是指Window(或全局对象),因为该函数没有在实例上调用。您正在调用第二个函数,它将设置Window.myApp,然后将其返回值(未定义)传递给getInfogetInfo 将访问不存在的 this.getYear,因此您会收到类型错误。

    我在这里遇到的错误是:

    TypeError: this.getYear 不是函数

    因为this 是全局对象,所以this.getYear 将是未定义的(不是函数)。

    【讨论】:

    • 终于有人回答这个问题了:)
    • @fgb 谢谢你的详细解释。根据 'douglas crockford' 的 'javascript the good parts',javascript 引擎(编译器或解析器)不应该为我们添加分号吗?
    • @venu 分号通常是自动插入的,但也有一些像这样的模棱两可的情况,它们不是。如果不使用分号,则需要注意以([+-/ 开头的行。
    【解决方案3】:

    JavaScript 中的this 关键字是调用或执行函数的任何内容。在您的示例中,对于 IIFE,this 将是全局 Window 对象 AKA window

    您的问题似乎缺少代码。 CarTruck 应该扩展 Vehicle1 吗?

    而且您没有调用Vehicle1.getInfo.myApp 的代码,所以我不确定您是如何收到该消息的。

    【讨论】:

    • 没有代码丢失。唯一缺少的是驻留在其他文件中的 QUnit 的测试脚本。正如我所说,我应该在单独的文件中执行它们以了解作者试图解释的内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-19
    • 1970-01-01
    • 2017-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多