Функция JavaScript сглаживание не работает

Я просто читала этот вопрос и хотел попробовать метод псевдонима, а не метод function-wrapper, но я не мог заставить его работать ни в Firefox 3, ни в 3.5beta4 или Google Chrome, как в их отладочных окнах, так и на тестовой веб-странице.

Firebug:

>>> window.myAlias = document.getElementById
function()
>>> myAlias('item1')
>>> window.myAlias('item1')
>>> document.getElementById('item1')
<div id="item1">

Если я помещаю его на веб-страницу, вызов myAlias дает мне эту ошибку:

uncaught exception: [Exception... "Illegal operation on WrappedNative prototype object" nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)" location: "JS frame :: file:///[...snip...]/test.html :: <TOP_LEVEL> :: line 7" data: no]

Chrome (с > > > вставлен для ясности):

>>> window.myAlias = document.getElementById
function getElementById() { [native code] }
>>> window.myAlias('item1')
TypeError: Illegal invocation
>>> document.getElementById('item1')
<div id=?"item1">?

и на тестовой странице Я получаю тот же"незаконный вызов".

Я делаю что-то неправильно? Может кто-нибудь воспроизвести?

кроме того, как ни странно, я просто попытался, и он работает в IE8.

6 ответов


вы должны привязать этот метод к объекту document. Смотри:

>>> $ = document.getElementById
getElementById()
>>> $('bn_home')
[Exception... "Cannot modify properties of a WrappedNative" ... anonymous :: line 72 data: no]
>>> $.call(document, 'bn_home')
<body id="bn_home" onload="init();">

когда вы делаете простой псевдоним, функция вызывается на глобальном объекте, а не на объекте документа. Используйте метод под названием closures, чтобы исправить это:

function makeAlias(object, name) {
    var fn = object ? object[name] : null;
    if (typeof fn == 'undefined') return function () {}
    return function () {
        return fn.apply(object, arguments)
    }
}
$ = makeAlias(document, 'getElementById');

>>> $('bn_home')
<body id="bn_home" onload="init();">

таким образом, вы не потеряете ссылку на исходный объект.

в 2012 году появился новый bind метод из ES5, который позволяет нам делать это более причудливым образом:

>>> $ = document.getElementById.bind(document)
>>> $('bn_home')
<body id="bn_home" onload="init();">

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

прежде чем я доберусь до того, почему вы не можете псевдоним document.getElementById, я попытаюсь объяснить, как работают функции/объекты JavaScript.

всякий раз, когда вы вызываете функцию JavaScript, интерпретатор JavaScript определяет область и передает ее функции.

рассмотрим следующую функцию:

function sum(a, b)
{
    return a + b;
}

sum(10, 20); // returns 30;

эта функция объявлена в Область окна и при ее вызове значение this внутри функции sum будет глобальный


Это короткий ответ.

следующее делает копию (ссылку на) функции. Проблема в том, что теперь функция находится на window объект, когда он был разработан, чтобы жить на document "объект".

window.myAlias = document.getElementById

варианты

  • использовать обертку (уже упоминавшуюся Фабьеном Менагером)
  • или вы можете использовать два псевдонима.

    window.d = document // A renamed reference to the object
    window.d.myAlias = window.d.getElementById
    

еще один короткий ответ, только для упаковки / сглаживания console.log и аналогичные методы ведения журнала. Они все рассчитывают оказаться в console контексте.

это можно использовать при оклеивании console.log С некоторыми отступлениями, в случае, если вы или ваши пользователи столкнулись с проблемами, когда С помощью браузера, который не (всегда) поддерживает его. Это не полное решение этой проблемы, хотя, как это должно быть расширенные проверки и запасной вариант - ваш пробег может отличаться.

пример использование предупреждений

var warn = function(){ console.warn.apply(console, arguments); }

тогда используйте его как обычно

warn("I need to debug a number and an object", 9999, { "user" : "Joel" });

если вы предпочитаете видеть свои аргументы журнала, завернутые в массив (я делаю, большую часть времени), замените .apply(...) С .call(...).

должны работать с console.log(), console.debug(), console.info(), console.warn(), console.error(). См. также console на MDN.

консоль firebug


в дополнение к другим отличным ответам, есть простой метод jQuery $.прокси.

Вы можете псевдоним такой:

myAlias = $.proxy(document, 'getElementById');

или

myAlias = $.proxy(document.getElementById, document);

вы на самом деле не могу "чистый псевдоним" функция на предопределенном объекте. Поэтому ближе всего к сглаживанию вы можете получить без обертывания, оставаясь в одном объекте:

>>> document.s = document.getElementById;
>>> document.s('myid');
<div id="myid">