Принудительное исключение/ошибка JavaScript при чтении свойства объекта undefined?

Я - опытный программист на С++/Java, работающий в Javascript в первый раз. Я использую Chrome в качестве браузера.

Я создал несколько классов Javascript с полями и методами. Когда я прочитал поле объекта, которое не существует (из-за опечатки с моей стороны), среда выполнения Javascript не генерирует ошибку или исключение. По-видимому, такие поля чтения "undefined". Например:

var foo = new Foo();
foo.bar = 1;
var baz = foo.Bar; // baz is now undefined

Я знаю, что я могу проверить равенство против "undefined", как указано в "Обнаружение свойства объекта undefined в JavaScript", но это кажется утомительным так как я читал из полей объектов часто в моем коде.

Есть ли способ принудительно вызывать ошибку или исключение, когда я читаю свойство undefined?

И почему возникает исключение, когда я читаю переменную undefined (в отличие от свойства объекта undefined)?

Ответ 1

Это выглядит как классический случай попыток обучить один язык парадигмам другого - лучше ИМХО изменить свой стиль кодирования, чтобы следить за тем, как Javascript делает что-то, чем пытаться привести его в соответствие с концепциями и ожиданиями на С++.

Тем не менее, если вы хотите бросить ошибку, как вы предлагаете, вам нужно определить какую-то пользовательскую функцию getProperty, либо на объекте, к которому вы пытаетесь получить доступ, либо в глобальной области. Реализация может выглядеть так:

function getProperty(o, prop) {
    if (o.hasOwnProperty(prop)) return o[prop];
    else throw new ReferenceError('The property ' + prop + 
        ' is not defined on this object');
}

var o = {
    foo: 1,
    bar: false,
    baz: undefined
};

getProperty(o, 'foo'); // 1
getProperty(o, 'bar'); // false
getProperty(o, 'baz'); // undefined
getProperty(o, 'foobar'); 
// ReferenceError: The property baz is not defined on this object

Но это уродливо, и теперь у вас есть эта настраиваемая языковая конструкция во всем вашем коде, что делает ее менее переносимой (если, например, вы хотели скопировать любую часть своего кода в другой script, вы Вам также придется копировать вашу новую функцию) и менее читабельны для других программистов. Поэтому я бы рекомендовал работать в рамках парадигмы Javascript и проверять undefined перед тем, как получить доступ к необходимым вам свойствам (или настроить ваш код, чтобы значения false-y ожидались и не прерывали работу).

Что касается вашего второго вопроса, почему Javascript выдает ошибку для переменных undefined, но не для свойств объекта undefined, я не могу дать лучшего ответа, чем "Потому что это то, что указано в спецификации языка". Объекты возвращают undefined для имен свойств undefined, но undefined переменные ссылаются на ошибку.

Ответ 2

Это может быть достигнуто с помощью ES6-прокси:

function disallowUndefinedProperties(obj) {
    const handler = {
        get(target, property) {
            if (property in target) {
                return target[property];
            }

            throw new Error(`Property '${property}' is not defined`);
        }
    };

    return new Proxy(obj, handler);
}

// example
const obj = { key: 'value' };
const noUndefObj = disallowUndefinedProperties(obj);

console.log(noUndefObj.key);
console.log(noUndefObj.undefinedProperty); // throws exception

Ответ 3

В Firefox есть опция javascript.options.strictabout:config). Если вы включите это, предупреждения будут занесены в консоль для многих распространенных ошибок, включая чтение свойства undefined, используя = вместо == в if и т.д.

(Конечно, чтобы не сказать, что такой код обязательно является неправильным.)

Ответ 4

Есть ли способ принудительно вызвать ошибку или исключение, если я прочитайте свойство undefined?

Это возможно использование прокси ES6, как было сказано в предыдущих ответах. Я сделал небольшой модуль node "zaalit", чтобы избежать необходимости его выполнять каждый раз.

Если кто-то заинтересован: https://www.npmjs.com/package/zealit

const zealit = require('zealit')

const ref = { foo: true, bar: undefined }
ref.foo // true 
ref.bar // undefined 
ref.baz // undefined 

const zealed = zealit(ref)
zealed.foo // true 
zealed.bar // undefined 
zealed.baz // throws a ReferenceError 

Ответ 5

Есть ли способ принудительно вызывать ошибку или исключение, когда я читаю свойство undefined?

Короче говоря, нет. Вы всегда можете проверить, закончилось ли вы с undefined сравнением с undefined, как вы сказали, или попыткой доступа к атрибуту второго уровня:

s = Foo()

s.bar = 1

s['Bar'] // returns undefined.

s['Bar']['Baz'] // Throws TypeError, s.Bar is undefined.

Кроме того, undefined терпит неудачу в условной проверке, поэтому вы можете уйти от этого как сокращение для сравнения:

if (s['Bar']) {
  // Something here only if s['Bar'] is set.
}

Имейте в виду, что эта короткая рука может вызвать неожиданное поведение, если был установлен параметр [[Bar]], но был значением "Falsey", и вам было только интересно, вернулась ли она обратно undefined.