Как передать аргумент анонимной функции Javascript? - PullRequest
1 голос
/ 16 декабря 2009

Я пишу простой счетчик, и я хотел бы сделать установку этого счетчика очень простой для пользователей. Одним из самых простых кодов счетчиков (для пользователей, которые его устанавливают) был код Google Analytics

Итак, я хотел бы сохранить основной код в файле, и пользователю, который установит мой счетчик, нужно будет просто установить websiteID следующим образом:

<html><head><title></title></head><body>
<script type="text/javascript" src="http://counterhost.lan/tm.js">
var websiteId = 'XXXXX';
</script>
</body></html>

Вот мой код:

<script type="text/javascript" src="http://counterhost.lan/tm.js">
var page = _gat.init('new');
</script>

и это мой файл JS:

(function() {
    var z = '_gat';
    var aa = function init(data) { alert(data); alert(z);};

    function na() {
        return new z.aa();
    }
    na();
})();

Я пытался понять код JavaScript Google Analytics, но мне не удалось это сделать. Может кто-нибудь предложить, как я могу указать переменную между тегами, а затем прочитать ее в анонимной функции, которая находится в файле JavaScript? Спасибо.

Ответы [ 6 ]

2 голосов
/ 16 декабря 2009

Вы можете передавать переменные анонимной функции следующим образом:

(function(arg1, arg2, arg3) {
    alert(arg1);
    alert(arg2);
    alert(arg3);
})("let's", "go", "redsox");

// will alert "let's", then "go", then "redsox" :)
2 голосов
/ 16 декабря 2009

Может кто-нибудь подсказать, как можно указать переменную между тегами и затем прочитать ее [...]

Нет, если ваш тег имеет как атрибут SRC, так и содержимое JS.

<script type="text/javascript" src="http:/x.com/x.js"></script>

.. отличается от

<script type="text/javascript">
    var x = 1;
</script>

Одной из структур, которая дополнительно добавляет переменные JS в теги SCRIPT, является Dojo. Поэтому, если вы используете Dojo, вы можете добавить переменные в глобальный хеш djConfig , написав

<script type="text/javascript" src="mxclientsystem/dojo/dojo.js"
    djConfig="
    usePlainJson: true,
    parseOnLoad: true
">
</script>

Dojo делает это, пропуская теги SCRIPT и оценивая собственный атрибут djConfig .

Однако это не решит вашу проблему.

Вы действительно хотите два тега SCRIPT. Одна поговорка,

<script type="text/javascript">
    var websiteId = '123456';
</script>

, которая установит глобальную переменную websiteId и вторую

<script type="text/javascript" src="http:/x.com/myreporter.js"></script>

, который может загружаться откуда угодно и считывать переменную websiteId и, я предполагаю, сообщать об этом.

2 голосов
/ 16 декабря 2009

В вашем примере websiteId является глобальной переменной. Таким образом, он доступен везде, включая анонимные функции, если только не существует локальной переменной с тем же именем

<script> var websiteId = "something"; </script>

Позже на странице или в файле js ...

(function() {
    alert(websiteId); //this should work
})();
0 голосов
/ 16 декабря 2009

Если вы укажете атрибут src как часть элемента script, любой код в самих тегах элемента script не будет выполнен. Тем не менее, вы можете добавить эту функцию с помощью следующего кода. Я получил эту технику от Крокфорда (я полагаю, что это был он), где он использует ее в своих выступлениях по несвязанной теме рендеринга производительности и асинхронной загрузки скриптов на страницу с этой целью.

JavaScript:

(function() {
    // Using inner class example from bobince's answer
 var _gat = (function() {
     var data= null;

     return {
         init: function(d) {
          console.info("Configuration data: ", d);
             data = d;
         }
     }
 })();

 // Method 1: Extract configuration by ID (SEE FOOT NOTE)
 var config = document.getElementById("my-counter-apps-unique-and-long-to-avoid-collision-id").innerHTML;

 // Method 2: search all script tags for the script with the expected name
 var scripts = document.getElementsByTagName("script");

 for ( var i=0, l=scripts.length; i<l; ++i ) {
  if ( scripts[i].src = "some-script.js" ) {
   config = scripts[i].innerHTML;
   break;
  }
 }

 _gat.init( eval("(" +config+ ")") );
})();

HTML:

<script type="text/javascript" src="some-script.js" id="my-counter-apps-unique-and-long-to-avoid-collision-id">
 {some: "foo", config: "bar", settings: 123}
</script>

Оба метода имеют свои недостатки:

  1. Использование уникального и не конфликтующего идентификатора сделает определение правильного элемента скрипта более точным и быстрым; однако это недопустимая разметка HTML4 / XHTML. В HTML5 вы можете определять произвольные атрибуты, так что это не будет проблемой в то время

  2. Этот метод является допустимой разметкой HTML; однако простое сравнение, которое я показал, может быть легко нарушено, если ваш URL-адрес может быть изменен (например, http против https), а более надежный метод сравнения может быть в порядке

Записка о eval

Оба метода используют eval. Типичная мантра, касающаяся этой особенности, заключается в том, что «Эвал - это зло». Однако это означает, что использование eval без знания опасностей eval является злом.

В этом случае, AFAIK, данные, содержащиеся в тегах script, не подвергаются атаке внедрения, поскольку сценарий eval'ing (показанный код) выполняется, как только этот элемент достигается при разборе HTML-кода в DOM. Сценарии, которые могли быть определены ранее, не могут получить доступ к данным, содержащимся в тегах script счетчика, так как этот узел не существует в дереве DOM в момент их выполнения.

Это может быть случай, когда хорошо выполненное время setTimeout, выполненное из ранее включенного сценария, может работать во время между включением счетчика script и временем вычисления; однако, это может или не может иметь место, и, если возможно, может быть не так последовательно, в зависимости от загрузки процессора и т. д.

Мораль истории, если вы беспокоитесь об этом, включите не-1043 * IN парсер JSON и используйте его вместо этого.

0 голосов
/ 16 декабря 2009

Я думаю, вы немного запутались с тем, как называются объекты JS.

z - это строка, '_gat'. Вы не можете вызвать aa(), потому что в строке нет члена с именем aa. aa - это отдельная функция, хранящаяся в локальной переменной. Даже если вы вызывали aa(), он ничего не возвращает, поэтому использование оператора new для его результатов не имеет смысла. new можно вызывать только для функций-конструкторов.

Полагаю, вы имеете в виду что-то вроде:

var _gat= function() {

    // Private variable
    //
    var data= null;

    // Object to put in window._gat
    //
    return {

        // Set the private variable 
        //
        init: function(d) {
            data= d;
        }
    };
}();

Затем вызов _gat.init('foo'), как во втором примере, установит для переменной идентификатор веб-сайта 'foo'. Это работает, потому что объект _gat является возвращаемым объектом {init: function() {...}}, определенным внутри анонимной функции, сохраняя ссылку (закрытие) на скрытую переменную data.

0 голосов
/ 16 декабря 2009

Я не совсем понимаю, о чем вы спрашиваете, но ...

Вы можете пометить любой элемент HTML атрибутом id, а затем использовать
document.getEntityById() для извлечения этого конкретного элемента.

Вы также можете задать любые пользовательские атрибуты любого элемента HTML с именами по вашему выбору, а затем получить и установить их для этого элемента в Javascript.

...