Javascript + пространство имен + FF проблема - PullRequest
0 голосов
/ 03 декабря 2009
var utils = function() {
    function getMyPrivateName() {
        return "Caoimhin";
    }
    return {
        messages: {
            getMyPublicName: function getMyPublicName() {
                return "Kevin";
            },
            sayHello: function() {
                document.writeln("hello " + getMyPublicName() + "<br/>");
                document.writeln("hello " + getMyPrivateName() + "<br/>");
            }
        }
    };
} ();

utils.messages.sayHello();

Я играю с пространствами имен javascript и столкнулся с неожиданным поведением. Я разрабатываю в основном в IE, так как это целевой браузер для нашего приложения для внутренней сети.

В IE вышеупомянутое, если оно включено на пустую страницу, выдает:

Привет, Кевин
привет Цаоимхин

В FF скрипт встречает ошибку:

getMyPublicName не определено

Если я закомментирую оскорбительную строку:

//document.writeln("hello " + getMyPublicName() + "<br/>");

FF выходы:

привет Цаоимхин

Так что я знаю, что он может получить доступ к закрытой функции ...

Может кто-нибудь объяснить, почему это происходит? И что мне нужно сделать, чтобы иметь кросс-браузерное решение, подобное приведенному выше.

Я знаю, что мог бы написать что-то вроде:

document.writeln("hello " + utils.messages.getMyPublicName() + "<br/>");

но предпочел бы не ....

Заранее спасибо, Kevin

Ответы [ 4 ]

5 голосов
/ 03 декабря 2009

Вы наткнулись на ошибку в языке JScript, используемом в IE.

getMyPublicName: function getMyPublicName() {
    ...
},

Здесь значение function getMyPublicName() является выражением встроенной функции, которому присвоен необязательный идентификатор getMyPublicName, совпадающий с именем его свойства в владельце. (sayHello опускает этот идентификатор.)

Что необязательный идентификатор должен делать в соответствии со стандартом ECMAScript, так это делать ссылку на функцию, видимую в области действия самого тела функции, под именем идентификатора getMyPublicName. Это может быть использовано для создания анонимной встроенной функции, которая ссылается на себя (для рекурсии).

То, что на самом деле делает в IE, неправильно, делает функцию видимой под именем getMyPublicName в родительской области (функция utils). Поскольку он виден в этой области видимости, он становится видимым и для дочерней области функции sayHello, что делает ваш код работающим, когда это не так, на самом деле.

Вы можете использовать this., чтобы правильно получить ссылку на getMyPublicName, как предложил Дастин. В качестве альтернативы, если вы хотите избежать проблем с привязкой this в JavaScript (например, потому что вы собираетесь передать функцию sayHello в качестве делегата тайм-ауту или событию), вы можете предпочесть поместить публичные функции в родительская область тоже:

var utils = function() {
    function getMyPrivateName() {
        return "Caoimhin";
    }
    function getMyPublicName() {
        return "Kevin";
    }
    function sayHello() {
        document.writeln("hello " + getMyPublicName() + "<br/>");
        document.writeln("hello " + getMyPrivateName() + "<br/>");
    }
    return {
        messages: {
            getMyPublicName: getMyPublicName,
            sayHello: sayHello,
        }
    }
}();
4 голосов
/ 03 декабря 2009
Поведение

Firefox соответствует, так как определение функции в инициализаторе объекта представляет собой выражение функции и не a объявление функции .

ECMA-262, 3-е издание, раздел 13:

Идентификатор в выражении FunctionEx можно ссылаться изнутри FunctionExpression's FunctionBody to позволить функции вызывать себя рекурсивно. Однако, в отличие от FunctionDeclaration, Идентификатор в FunctionExpression не может быть ссылается на и не влияет объем, охватывающий ВыражениеФункции.

Я предлагаю перенести определение из инициализатора объекта:

var utils = (function() {
    function getMyPrivateName() {
        return "Caoimhin";
    }
    function getMyPublicName() {
        return "Kevin";
    }
    return {
        messages: {
            getMyPublicName: getMyPublicName,
            sayHello: function() {
                document.writeln("hello " + getMyPublicName() + "<br/>");
                document.writeln("hello " + getMyPrivateName() + "<br/>");
            }
        }
    };
})();


utils.messages.sayHello();
2 голосов
/ 03 декабря 2009

Это вопрос объема:

var utils = function() {
    function getMyPrivateName() {
        return "Caoimhin";
    }
    return {
        messages: {
            getMyPublicName: function() {
                return "Kevin";
            },
            sayHello: function() {
                document.writeln("hello " + this.getMyPublicName() + "<br/>");
                document.writeln("hello " + getMyPrivateName() + "<br/>");
            }
        }
    };
} ();

utils.messages.sayHello();
0 голосов
/ 03 декабря 2009

Один из способов сделать это:

var utils = function() {
    var getMyPrivateName = function () {
        return "Caoimhin";
    };

    var self = {
        getMyPublicName: function () {
            return "Kevin";
        },
        sayHello: function() {
            document.writeln("hello " + getMyPublicName() + "<br/>");
            document.writeln("hello " + self.getMyPrivateName() + "<br/>");
        };

    return self;
}();
...