2010-04-19 3 views
9

У меня есть одноэлементный объект, использовать другой объект (не одиночки), требовать некоторой информации на сервер:JavaScript «класс» и одноэлементные проблемы

var singleton = (function(){ 

    /*_private properties*/ 
    var myRequestManager = new RequestManager(params, 
    //callbacks 
    function(){ 
     previewRender(response); 
    }, 
    function(){ 
     previewError(); 
    } 
); 

    /*_public methods*/ 
    return{ 

    /*make a request*/ 
    previewRequest: function(request){ 
     myRequestManager.require(request); //err:myRequestManager.require is not a func 
    }, 

    previewRender: function(response){ 
     //do something 
    }, 

    previewError: function(){ 
     //manage error 
    } 
    }; 
}()); 

Это является «класс», которые делают запрос к сервер

function RequestManager(params, success, error){ 
    //create an ajax manager 
    this.param = params; 
    this._success = success; //callbacks 
    this._error = error; 
} 

RequestManager.prototype = { 

    require: function(text){ 
    //make an ajax request 
    }, 
    otherFunc: function(){ 
    //do other things 
    } 

}

проблема заключается в том, что я не могу назвать myRequestManager.require внутри одноплодным объекта. Firebug consolle говорит: «myRequestManager.require не является функцией», но я не понимаю, где проблема. Есть ли лучшее решение для реализации этой ситуации?

+0

Я не получил ошибку ... Откуда возникают параметры, когда вы создаете RequestManager? –

+0

В примере кода, который вы даете, параметры нигде не определены. Вы оставили что-то из своего примера? – Robusto

ответ

6

Ваш код в том порядке, в котором вы его цитировали, не так ли? Синглтон появляется выше RequestManager в источнике?

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

  1. Функция RequestManager.
  2. Ваша анонимная функция, которая создает ваши одиночные прогоны, включая экземпляр экземпляра RequestManager.
  3. Прототип RequestManager заменен на новый.

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

Вы можете исправить это легко повторно заказав код, либо путем добавления свойства RequestManager «s прототип, а не заменить его, например:

RequestManager.prototype.require = function(text){ 
    //make an ajax request 
}; 
RequestManager.prototype.otherFunc = function(){ 
    //do other things 
}; 

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

Почему это происходит немного технически, и я в основном буду откладывать спецификацию. Когда интерпретатор вводит новый «контекст исполнения» (например, функцию или глобальный   —, например, контекст страницы   —), порядок, в котором он делает вещи, не является строгим порядком источника сверху вниз, есть этапы , Одной из первых фаз является создание всех функций, определенных в контексте; что происходит до выполняется любой пошаговый код. Подробности во всей их славе в разделах 10.4.1 (глобальный код), 10.4.3 (код функции) и 10.5 (привязки объявлений) в the spec, но в основном функции создаются до первой строки пошагового кода.:-)

Это легче увидеть изолированный тестовый пример:

<!DOCTYPE HTML> 
<html> 
<head> 
<meta http-equiv="Content-type" content="text/html;charset=UTF-8"> 
<title>Test Page</title> 
<style type='text/css'> 
body { 
    font-family: sans-serif; 
} 
</style> 
<script type='text/javascript'> 
// Uses Thing1 
var User1 = (function() { 
    var thing1 = new Thing1(); 

    function useIt() { 
     alert(thing1.foo()); 
    } 

    return useIt; 
})(); 

// Uses Thing2 
var User2 = (function() { 
    var thing2 = new Thing2(); 

    function useIt() { 
     alert(thing2.foo()); 
    } 

    return useIt; 
})(); 

// Thing1 gets its prototype *replaced* 
function Thing1() { 
    this.name = "Thing1"; 
} 
Thing1.prototype = { 
    foo: function() { 
     return this.name; 
    } 
}; 

// Thing2 gets its prototype *augmented* 
function Thing2() { 
    this.name = "Thing2"; 
} 
Thing2.prototype.foo = function() { 
    return this.name; 
}; 

// Set up to use them 
window.onload = function() { 
    document.getElementById('btnGo').onclick = go; 
} 

// Test! 
function go() { 

    alert("About to use User1"); 
    try 
    { 
     User1(); 
    } 
    catch (e) 
    { 
     alert("Error with User1: " + (e.message ? e.message : String(e))); 
    } 

    alert("About to use User2"); 
    try 
    { 
     User2(); 
    } 
    catch (e) 
    { 
     alert("Error with User2: " + (e.message ? e.message : String(e))); 
    } 
} 

</script> 
</head> 
<body><div> 
<div id='log'></div> 
<input type='button' id='btnGo' value='Go'> 
</div></body> 
</html> 

Как вы можете увидеть, если вы запустите его, User1 терпит неудачу, потому что Thing1 экземпляр он использует не имеет foo свойства (потому что прототип был заменен), но User2 работает, потому что экземпляр Thing2, в котором он использует *, (потому что прототип был дополнен, а не заменен).

+1

+1 JavaScript снова поднимает ловушку! – bobince

+1

Спасибо за объяснение и примеры, я не получил разницу между дополненным прототипом и прототипом. Теперь это работает :-) –

+1

@ Kucebe: Отлично! Да, это тонкий. :-) Не просто прототипы, это порядок, в котором происходят вещи, которые иногда вас укусят (это, безусловно, имеет * me *). –

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