简体   繁体   中英

Javascript typeof throws referenceerror

lets get right into it.
I am using typeof to check if a variable API exists. I learned that typeof returns "undefined" if the variable does not exist.

function exitApplication() {
    let typeOfApi = typeof API;
    if (typeOfApi !== "undefined") {
        API.close(() => {
            strip.shutdown();
            ...
            ...
            ...
        });
    }
    else {
        console.log("Bye!");
        process.exit(0);
    }
}

If I now run my program with test data that leads into a call to exitApplication when API is not yet defined I get a ReferenceError:

    let typeOfApi = typeof API;
                    ^

ReferenceError: API is not defined

Because I am using Webpack I changed the output file and replaced API with anything else that was not defined and voila it works and typeOfApi is "undefined" (the code I pasted is the Webpack outup).

API is a const value and I only use let and const in my code. I read something about Temporal Dead Zones, but typeof should still return "undefined" if a let variable is not defined?

I also read this Why does typeof only sometimes throw ReferenceError? but I am not using a expression.

Oh and my code is written in typescript. But I am not that "good" at it and don't really know how to get the types for restify, so API is of type any . (I know that typeof and the typescript type are completely different things :D). But the code seems to be translated 1 to 1 anyways.


Edit: So I made this little example. This is the Webpack output

#!/usr/local/bin/node
/******/ (function(modules) { // webpackBootstrap
/******/    // The module cache
/******/    var installedModules = {};
/******/
/******/    // The require function
/******/    function __webpack_require__(moduleId) {
/******/
/******/        // Check if module is in cache
/******/        if(installedModules[moduleId]) {
/******/            return installedModules[moduleId].exports;
/******/        }
/******/        // Create a new module (and put it into the cache)
/******/        var module = installedModules[moduleId] = {
/******/            i: moduleId,
/******/            l: false,
/******/            exports: {}
/******/        };
/******/
/******/        // Execute the module function
/******/        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/        // Flag the module as loaded
/******/        module.l = true;
/******/
/******/        // Return the exports of the module
/******/        return module.exports;
/******/    }
/******/
/******/
/******/    // expose the modules object (__webpack_modules__)
/******/    __webpack_require__.m = modules;
/******/
/******/    // expose the module cache
/******/    __webpack_require__.c = installedModules;
/******/
/******/    // define getter function for harmony exports
/******/    __webpack_require__.d = function(exports, name, getter) {
/******/        if(!__webpack_require__.o(exports, name)) {
/******/            Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/        }
/******/    };
/******/
/******/    // define __esModule on exports
/******/    __webpack_require__.r = function(exports) {
/******/        if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/            Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/        }
/******/        Object.defineProperty(exports, '__esModule', { value: true });
/******/    };
/******/
/******/    // create a fake namespace object
/******/    // mode & 1: value is a module id, require it
/******/    // mode & 2: merge all properties of value into the ns
/******/    // mode & 4: return value when already ns object
/******/    // mode & 8|1: behave like require
/******/    __webpack_require__.t = function(value, mode) {
/******/        if(mode & 1) value = __webpack_require__(value);
/******/        if(mode & 8) return value;
/******/        if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/        var ns = Object.create(null);
/******/        __webpack_require__.r(ns);
/******/        Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/        if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/        return ns;
/******/    };
/******/
/******/    // getDefaultExport function for compatibility with non-harmony modules
/******/    __webpack_require__.n = function(module) {
/******/        var getter = module && module.__esModule ?
/******/            function getDefault() { return module['default']; } :
/******/            function getModuleExports() { return module; };
/******/        __webpack_require__.d(getter, 'a', getter);
/******/        return getter;
/******/    };
/******/
/******/    // Object.prototype.hasOwnProperty.call
/******/    __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/    // __webpack_public_path__
/******/    __webpack_require__.p = "";
/******/
/******/
/******/    // Load entry module and return exports
/******/    return __webpack_require__(__webpack_require__.s = "./src/test.ts");
/******/ })
/************************************************************************/
/******/ ({

/***/ "./src/test.ts":
/*!*********************!*\
  !*** ./src/test.ts ***!
  \*********************/
/*! no static exports found */
/***/ (function(module, exports) {

exitApplication();
const API = {};
function exitApplication() {
    let typeOfApi = typeof API;
    console.log(typeOfApi);
    if (typeOfApi !== "undefined") {
        console.log("Bye!");
        process.exit(0);
    }
    else {
        console.log("Bye!");
        process.exit(0);
    }
}


/***/ })

/******/ });
//# sourceMappingURL=LED-Controller.js.map

And this will also throw a referenceerror

Edit: Here are my TS and Webpack configs. https://gist.github.com/Lucarus/ebbfab5cc6560094a292ba86557ffd1d
For the example I replaced Applications.ts with test.ts but it used the same config.

You're calling a function that references the const API = {} variable BEFORE that variable has been initialized, but inside the scope where it will be declared. With const and let , that is not allowed. You have this:

exitApplication();
const API = {};
function exitApplication() {
    let typeOfApi = typeof API;
    console.log(typeOfApi);
    if (typeOfApi !== "undefined") {
        console.log("Bye!");
        process.exit(0);
    }
    else {
        console.log("Bye!");
        process.exit(0);
    }
}

The function is hoisted to the top of that scope so that's why you can call exitApplication() , but you have not yet executed the line of code that initializes API . But, the intrepreter knows it's there and not yet initialized and it's a ReferenceError in Javascript to attempt to access a const or let defined variable in the scope where it is defined before it the line containing its declaration runs.

When I run this in Chrome, the exact error I get is:

Uncaught ReferenceError: Cannot access 'API' before initialization

which is telling you exactly what the problem is. In the first pass of the interpreter, it has parsed the code and it knows that const API = {} is there, so its illegal to access it until it reaches that line of code that initializes it. If you really want to get around this, then change const to var , but there's likely just a better way to write your code that doesn't need to use var .


Of course, if you just move the declaration of API up one line, no problem:

const API = {};
exitApplication();
function exitApplication() {
    let typeOfApi = typeof API;
    console.log(typeOfApi);
    if (typeOfApi !== "undefined") {
        console.log("Bye!");
        process.exit(0);
    }
    else {
        console.log("Bye!");
        process.exit(0);
    }
}

For a good article on this topic, you can read this article: Why typeof is no longer safe .

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