2010-07-12 3 views
12

Возможно ли переопределить функцию JavaScript из собственного тела. Например, могу ли я сделать следующее?Переопределение функции JavaScript

function never_called_again(args) { 
    // Do some stuff 
    never_called_again = function (new_args) { 
    // Do some new stuff 
    } 
} 

Является ли вышеизложенное и имеет ли он правильную семантику? Я не хочу создавать новую глобальную переменную со старым именем функции, потому что я пытаюсь делать такие вещи не в глобальной области, а из разных областей объектов, и мне не нужны столкновения имен, когда я переопределить функцию внутри этих локальных областей.

+2

Я понятия не имею, можете ли вы или нет, но это не похоже на то, что нужно делать. Я, очевидно, не знаю, каковы ваши обстоятельства, но это звучит так, как будто у него большой потенциал для путаницы, трудно отслеживать ошибки и трудно читать код. Я бы много думал о том, является ли это правильным решением, или если вы хотите создать резервную копию шага и задать вопрос, который привел вас к этому в качестве ответа. Извините, если вы уже рассмотрели все варианты. Вы никогда не можете сказать, что у кого-то есть тогут об уже или нет ... – Chris

+5

Для этого есть законное использование, и это мощная вещь. Люди боятся того, чего не знают, но это не значит, что они плохие. – galambalazs

+0

Обратите внимание, что этот метод на самом деле не переопределяет функцию, она изменяет, к которой относится функция 'never_called_again'.Исходная функция не обязательно исчезает, учитывая, что (хотя вы этого не делаете) можно создать другую переменную, которая ссылается на исходную функцию: put 'original = never_called_again;' перед переназначением 'never_called_again' и' original () 'будет ссылаться на оригинал ... – nnnnnn

ответ

14

Да, вы можете переопределить функцию таким образом.

Запуск Это:

function never_called_again(args) { 
    console.log('Func 1', args); 

    never_called_again = function (new_args, x) { 
     console.log('Func 2', new_args, x); 
    } 
} 

never_called_again('arg A', 'arg B'); 

never_called_again('arg A', 'arg B'); 

Урожайность это:

Func 1 arg A 
Func 2 arg A arg B 
+1

@galambalazs: Я дал вам кредит, и я расширил аспекты, которые вы не наделили моим удовлетворением. Кроме того, мой первый ответ и главный ответ не имели ничего общего с вашим и были достаточными. –

+1

Это ** не сообщество wiki **. Глобальные переменные не имеют ничего общего с переопределением функций, они связаны только с Lazy Func. Шаблон определения, который является примером переопределения функции. Все хорошо объясняется в ссылке btw ... Но опять-таки это был лишь пример. Ваш ответ был напряжен и не получил голосов, поэтому вы его изменили ... – galambalazs

+1

@galambalazs: Нет, до того, как я его изменил, у меня было столько голосов, сколько вы (1 каждый) - до того, как я поддержал вас. Я изменил свой ответ, чтобы сделать его более полным, включая уроки из статьи, которую вы цитировали, что вы этого не сделали. Кроме того, я дал вам кредит. Я видел, как другие люди это делают. Предполагается, что речь идет об улучшении ответов, а не глупости. По вашей логике, Питер Мишо должен быть после вас за плагиат. Во всяком случае, я откатил свой ответ –

2

Ваш пример в основном так же, как:

var never_called_again = function(args) { 
    //do some stuff 
    never_called_again = function (new_args) { 
     //do some new stuff 
    } 
} 

Так как вы, наверное, знаете, что это работает:

var a = 1; 

function myFunction() { 
    //do some stuff 
    a = 2; 
} 

myFunction(); 

alert(a) //==> 2 

это ясно, что первый пример тоже работает.

Действительно ли вы на самом деле хотите, чтобы сделать это или нет, более открытый вопрос. Будет ли это сделать код сложнее понять?

40

Это действительно возможно переопределить функцию из своего тела. Этот метод используется в так называемом Lazy Function Definition Pattern.

Это выглядит следующим образом:

// Lazy Function Definition Pattern 
var foo = function() { 
    var t = new Date(); 
    foo = function() { 
     return t; 
    }; 
    return foo(); 
} 

Эта функция сохраняет Дата первого вызова, и возвращает эту дату впоследствии.

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

// Conditional Module Pattern 
var foo = (function() { 
    var t; 
    return function() { 
     if (t) { 
      return t; 
     } 
     t = new Date(); 
     return t; 
    } 
})(); 
+0

Ницца. snip 8 <--- – mplungjan

+0

Спасибо за ссылку, это было довольно интересно, и я использую шаблон таким же образом, чтобы избежать различных условных путей выполнения. – davidk01

1

Да, это возможно, и это не создаст глобальной функции. Я проверил это в Интернете   Проводник   6, Firefox, Chrome и Opera. Рассмотрим следующий код:

<head> 
    <title>Never called again</title> 
    <style type="text/css"> 
    </style> 

    <script type="text/javascript"> 

      function hello() { 
      function never_called_again(args) { 
       alert("Hello world " + never_called_again); 
       //do some stuff 
       never_called_again = function (new_args) { 
        //do some new stuff 
        alert("hello " + never_called_again); 
       } 
      } 
      never_called_again(); 
      never_called_again(); 

      } 

     </script> 

    </head> 
    <body onload=""> 

    <button onclick="hello(); never_called_again();">Call</button> 
    </body> 

Это будет печатать «Hello World {код функции}» в первый раз в never_called_again и второй раз он будет печатать «привет {изменил код функции}» во второй раз.

Но когда он вызывается на кнопке onclick, он выдает ошибку, говоря, что функция не определена, что ясно указывает на то, что функция была переопределена (и не создана глобально).

3

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

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

Это на самом деле означает, что на момент выполнения объект функции, выполняющий выполнение и определение исходной функции, на самом деле представляет собой две разные вещи, что позволяет переопределить исходную функцию, а ... что-то действительно.

Одним из лучших (и самых крутых) способов использования этого является создание функции, которая по сути является собственной фабрикой. Таким образом, вам не нужно переносить множество определений объектов, которые не будут использоваться.

Пример:

d = function(type){ 
    switch(type.toUpperCase()){ 
     case 'A' : 
      d = (
        function(){ 
         return { 
          name : 'A', 
          getName : function(){return this.name;} 
         }; 
        } 
       )(); 
       break; 

     case 'B' : 
      d = (
       function(){ 
        return { 
         name : 'B', 
         getName : function(){return this.name;} 
        }; 
       } 
      )(); 
      break; 

     default: 
      d = (
       function(){ 
        return { 
         name : 'DEFAULT', 
         getName : function(){return this.name;} 
        }; 
       } 
      )(); 
      break; 
    } 
}; 

console.dir(d); 
d('A'); 
console.dir(d); 
console.log(d.getName()); 
1

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

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

greet_once = function() { 
    console.log('Hello.'); 
    greet_once = function() { console.log('Can I help you?') }; 
}; 

Аналогично функция может использовать состояние closured сферы по-разному ведут себя во второй раз его называют (явно не «переопределение»).

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

greet_always = function() { 
    greet_once = function() { 
    console.log('Hello.') 
    greet_once = function() { console.log('Can I help you?') } 
    }; 
    return greet_once() 
}() 

greet_always() 
greet_always() 

функция вызывается, как greet_always (который всегда печатает «Hello».) Такой же один, присвоенный первоначально greet_once.

Самый близкий, я считаю, что вы можете переопределить функцию, чтобы переназначить свои методы применения и вызова, что создает сценарий, в котором myFunction.call() отличается от myFunction(), что странно, но, возможно, полезно.

Смежные вопросы