2010-05-18 7 views
4

이 문제는 일반적인 변수 범위 및 클로저 항목을 넘어서는 것 같고 어쩌면 저는 바보입니다. 여기에 어쨌든 간다 ...자바 스크립트 변수 범위/OOP 및 콜백 함수에 도움이 필요합니다.

나는 jQuery 플러그인에서 즉석에서 많은 오브젝트를 만들고있다. 이

function WedgePath(canvas){ 
    this.targetCanvas = canvas; 
    this.label; 
    this.logLabel = function(){ console.log(this.label) } 
} 

JQuery와 플러그인과 같은 개체 모양의 무언가는 'globalFunction가'전달, 각각에 대해 호출이

(function($) { 
    $.fn.myPlugin = function() { 

    return $(this).each(function() { 

    // Create Wedge Objects 
    for(var i = 1; i <= 30; i++){ 
     var newWedge = new WedgePath(canvas); 
     newWedge.label = "my_wedge_"+i; 
     globalFunction(i, newWedge]); 
    } 
    }); 
    } 
})(jQuery); 

그래서 ... 플러그인이 wedgeObjects의 무리를 생성 같이 보입니다 최신 WedgePath 인스턴스 전역 함수는 다음과 같습니다.

function globalFunction(indicator_id, pWedge){ 

    var targetWedge = pWedge; 
    targetWedge.logLabel(); 

} 

다음으로 콘솔에서 각 쐐기 레이블을 올바르게 기록합니다. 그러나 globalFunction 내에서 좀 더 복잡한 것이 필요합니다. 그래서 실제로는 이렇게 보입니다 ...

function globalFunction(indicator_id, pWedge){ 

     var targetWedge = pWedge; 

     someSql = "SELECT * FROM myTable WHERE id = ?"; 
     dbInterface.executeSql(someSql, [indicator_id], function(transaction, result){ 

      targetWedge.logLabel(); 

     }) 

    } 

여기에 많은 부분이 있으므로 설명하겠습니다. 나는 클라이언트 측 데이터베이스 스토리지 (WebSQL 내가 그것을 호출)를 사용하고 있습니다. 'dbInterface'는 클라이언트 측 데이터베이스와 상호 작용하는 기본 사항을 처리하는 간단한 자바 스크립트 객체의 인스턴스입니다. [이 질문의 끝 부분에 나와 있습니다.] executeSql 방법 4 개 인수

  • 하는 SQL 스트링
  • 선택적 인수 어레이
  • 선택적으로 onSuccess 핸들러
  • (이 예에서는 사용되지 않음) 임의의 OnError 핸들러
을 차지

내가해야 할 일은 다음과 같습니다. WebSQL 쿼리가 완료되면 특정 데이터의 일부를 가져 와서 특정 쐐기의 일부 특성을 조작합니다. 그러나 onSuccess 핸들러 내에서 WedgePath의 인스턴스에서 'logLabel'을 호출하면 플러그인 코드에서 다시 만들어진 WedgePath의 마지막 인스턴스 레이블이 표시됩니다.

이제 문제가 var newWedge = new WedgePath(canvas)에있는 것으로 의심됩니다. 선. 그래서 나는 ... 나는 대체하거나 모든 반복에 WedgePath 인스턴스를 덮어에서 그 선을 방지 것이라고 생각 배열에

wedgeArray = []; 

// Inside the plugin... 
for(var i = 1; i <= 30; i++){ 
    var newWedge = new WedgePath(canvas); 
    newWedge.label = "my_wedge_"+i; 
    wedgeArray.push(newWedge); 
} 

for(var i = 0; i < wedgeArray.length; i++){ 
    wedgeArray[i].logLabel() 
} 

각 newWedge을 밀어 시도 그러나 다시, 나는 WedgePath의 마지막 인스턴스를 생성 할 수 .

이것은 나를 미치게합니다. 나는 질문의 길이에 대해 사과하지만 나는 가능한 한 분명하고 싶었다.

END

========================================= =======================

dbInterface 객체에 대한 코드는 다음과 같습니다.this

답변

3

나는이 클라이언트 측의 데이터베이스 스토리지는 비동기 실행되는 때문입니다 추측 것을 읽을

function(transaction, result){ 

     targetWedge.logLabel(); 

    }) 

:

function DatabaseInterface(db){ 

var DB = db; 

this.sql = function(sql, arr, pSuccessHandler, pErrorHandler){ 

    successHandler = (pSuccessHandler) ? pSuccessHandler : this.defaultSuccessHandler; 
    errorHandler = (pErrorHandler) ? pErrorHandler : this.defaultErrorHandler; 

    DB.transaction(function(tx){ 

    if(!arr || arr.length == 0){ 
    tx.executeSql(sql, [], successHandler, errorHandler); 
    }else{ 
    tx.executeSql(sql,arr, successHandler, errorHandler) 
    } 

    });  
} 

// ---------------------------------------------------------------- 
// A Default Error Handler 
// ---------------------------------------------------------------- 

this.defaultErrorHandler = function(transaction, error){ 
    // error.message is a human-readable string. 
    // error.code is a numeric error code 
    console.log('WebSQL Error: '+error.message+' (Code '+error.code+')'); 

    // Handle errors here 
    var we_think_this_error_is_fatal = true; 
    if (we_think_this_error_is_fatal) return true; 
    return false; 
} 


// ---------------------------------------------------------------- 
// A Default Success Handler 
// This doesn't do anything except log a success message 
// ---------------------------------------------------------------- 

this.defaultSuccessHandler = function(transaction, results) 
    { 
     console.log("WebSQL Success. Default success handler. No action taken."); 
    }  
} 
+0

이것은 매우 가까워서 맛볼 수 있습니다. 나는 "...}) (targetWedge)"를 'executeSql()'에 대한 익명 onSuccess 함수의 끝에 추가해야했으며 실제로 targetWedge에 대한 올바른 레이블을 로깅합니다. 하지만 두 가지 이상한 일이 벌어지고 있습니다. 먼저 console.log (result)가 정의되지 않은 오류를 생성합니다. 또한 익명 함수가 호출됨을 나타내는 웨지 레이블을 로깅하더라도 기본 onSuccess 핸들러를 호출합니다. 나는 정말로 밀도가 있습니까? 아니면이 것이 진정으로 혼란스러운 문제입니까? – gargantuan

+0

먼저, executeSql 내에서 console.log (결과)를 수행하면됩니까? 둘째로 당신이 원하는 것을 당신이 원하는 정보로 편집 할 수 있습니까? 위젯의 목적은 무엇입니까? – fredrik

+0

CONSOLE.LOG (결과)이 같은 위로 executeSql 내부는 onSuccess 호출 내에서 호출 (실제 코드, 그래서 다른 조금 보임) {(targetWedge) (indicator_id, REGION_ID, pWedge) { 창 함수 '기능 getDataForIndicatorAndRegion이다 someSql = "SELECT dataRows.status FROM dataRows WHERE indicator_id =? AND region_id =?"; dbInterface.sql (someSql [indicator_id, REGION_ID] \t 기능 (트랜잭션, 결과) { targetWedge.changeColor (randomHex()); \t} (targetWedge) \t \t \t ); }} (pWedge); }' – gargantuan

0

나는 당신의 문제가 globalFunction 내부에가는 변형 한 폐쇄 의심 AJAX 호출이 가능합니다. 즉, 호출 된 메서드의 결과를 기다리기 위해 호출 체인을 중지하지 않습니다.

결과적으로 javascript 엔진은 globalFunction을 실행하기 전에 for 루프를 완료합니다.

이 문제를 해결하기 위해 클로저 내부에서 db 쿼리를 수행 할 수 있습니다.

function getDataForIndicatorAndRegion(indicator_id, region_id, pWedge){ 
    return function (targetWedge) { 
     someSql = "SELECT dataRows.status FROM dataRows WHERE indicator_id = ? AND region_id = ?"; 
     dbInterface.sql(someSql, [indicator_id, region_id], function(transaction, result) { 
      targetWedge.changeColor(randomHex()); 
     }); 
    }(pWedge); 
} 

이렇게하면 각 실행마다 pWedge를 보존 할 수 있습니다. 두 번째 방법은 스스로 호출하여 pWedge가 현재 인수로 무엇인지를 보냅니다.

편집 : 주석의 코드가 업데이트되었습니다. 그리고 그것을 변경했습니다. 콜백 함수가 자체 호출되지 않아야합니다. 자체적으로 호출하면 함수의 결과가 인수로 전달됩니다. 또한 작동하지 않는 경우 다른 인수를 전달하십시오.

+0

나는이 문제가 될 것이라고 생각하기 때문에 폐쇄에 대한 내 머리를 잡으려고 꽤 많은 시간을 보냈습니다. 나는 완전히 이해한다고 생각하지는 않지만, globalFunction이 호출 될 때마다 새 클로저가 만들어지고 그 시점에 targetWedge가 무엇이든지 해당 함수 호출의 해당 인스턴스에 대해 클로저에 추가됩니다. 하지만 그렇지 않을 수도 있습니다. – gargantuan

+1

다시 한번 의심 스럽지만 :'$ (this) .each() '루프가 반복하여 쐐기 변수를 생성하면,이 변수는 전달되고 globalFunction의 콜백 함수에서 사용됩니다. each() 루프는 callback이 호출되는 것보다 더 빠르게 iterating을 유지합니다. 이는 두 번째 각각에서 첫 번째 globalfunction 콜백 내에서 쐐기 참조가 변경되었음을 나타냅니다. –

관련 문제