Javascript:变量范围问题

时间:2011-09-12 12:58:34

标签: javascript scope

为什么我来alert打电话给undef

#!/usr/bin/env perl
use warnings;
use 5.014;
use utf8;
use Mojolicious::Lite;
use DBI;

my $db = 'my_test_db.db';
my $table = 'my_test_table';
my $dbh = DBI->connect( "dbi:SQLite:dbname=$db", '', '', 
            { RaiseError => 1, PrintError => 0, AutoCommit => 1, sqlite_unicode => 1, } 
        ) or die $DBI::errstr;
$dbh->do( "CREATE TEMP TABLE $table ( str TEXT, num INTEGER )" );
my $sth = $dbh->prepare( "INSERT INTO  $table ( str, num ) VALUES ( ?, ?)" );
$sth->execute( 'aaa', '111' );
$sth->execute( 'bbb', '222' );
$sth->execute( 'ccc', '333' );

get '/eingabe' => sub {
    my $self = shift;
    $self->render( 'eingabe' );
};

get '/search_db/:col' => sub {
    my $self = shift;
    my $col = $self->param( 'col' );
    my $term = $self->param( 'term' );
    my $sth = $dbh->prepare( "SELECT DISTINCT $col FROM $table WHERE $col LIKE ?" );
    $sth->execute( $term . '%');
    my $ref;
    while ( my $row = $sth->fetchrow_arrayref() ) {
            push @$ref, @$row;
    }
    $self->render( json => $ref );
};

app->start;

__DATA__
@@ eingabe.html.ep
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.js"></script>
<script type="text/javascript">
    $( document ).ready( function() {
        var ids = [ 'str', 'num' ];
        for ( var i = 0; i < ids.length; i++ ){
            $( "#" + ids[i] ).autocomplete({
                source: function( request, response ){ 

                    alert( ids[i] );  // <---

                    $.getJSON( '/search_db/'  + ids[i], request, function( data_from_server ){
                        var suggestions = [];
                        var len = data_from_server.length;
                        for( var i = 0; i < len; i++ ){
                            suggestions.push( data_from_server[i] );
                        }
                        response( suggestions );
                    });
                }
            });
        }
    });
</script>
</head>
<body>
<form>
    <table>
        <tr><td>String:</td><td><input type="text" id="str" name="str"" /></td></tr>
        <tr><td>Number:</td><td><input type="number" id="num" name="num" /></td></tr>
    </table><br />
    <input type="submit" value="OK"/>
</form>
</body>
</html>

3 个答案:

答案 0 :(得分:3)

听起来你遇到了这里解释的问题:Creating closures in loops: A common mistake

您在调用undefined时获得alert的原因是,当调用autocomplete函数时,您的for循环已完成执行意味着您的循环变量{{ 1}}的值为2,即i。因此ids.length + 1ids[i]相同,因为您的ids[2]数组中只有2个元素,因此不存在ids。我试图想出这个行为的简单演示来帮助说明发生了什么:http://jsfiddle.net/ianoxley/KwXVs/1/(你需要打开浏览器的控制台才能看到结果)。

如果你创建了一个额外的闭包,它应该有助于保留你的范围并摆脱undefined(见http://jsfiddle.net/ianoxley/BVa5Q/)。

如果您尝试将代码更改为此类代码,希望它可以解决问题:

$(document).ready(function () {
    function initAutocomplete(element_id) {
        $("#" + element_id).autocomplete({
            source: function (request, response) {

                alert(element_id);  // <---

                $.getJSON('/search_db/' + element_id, request, function (data_from_server) {
                    var suggestions = [];
                    var len = data_from_server.length;
                    for (var i = 0; i < len; i++) {
                        suggestions.push(data_from_server[i]);
                    }
                    response(suggestions);
                });
            }
        });        
    }

    var ids = ['str', 'num'];
    for (var i = 0; i < ids.length; i++) {
        var current_id = ids[i];
        initAutocomplete(current_id);
    }
});

希望这有帮助。

答案 1 :(得分:0)

您正在定义i次迭代变量两次:它会在您的回调中用于$.getJSON再次调用。

您应该将该名称重命名为其他名称j(仅作为示例)。

所以它会说:

$( document ).ready( function() {
    var ids = [ 'str', 'num' ];
    for ( var i = 0; i < ids.length; i++ ){
        $( "#" + ids[i] ).autocomplete({
            source: function( request, response ){ 

                alert( ids[i] );  // <---

                $.getJSON( '/search_db/'  + ids[i], request, function( data_from_server ){
                    var suggestions = [];
                    var len = data_from_server.length;
                    for( var j = 0; j < len; j++ ){
                        suggestions.push( data_from_server[j] );
                    }
                    response( suggestions );
                });
            }
        });
    }
});

我希望这有帮助!

答案 2 :(得分:0)

您的源回调函数超出范围。当你将一个函数攻击到一个事件链接时,它会在你的for循环完成后触发事件时被调用。

使用回调时,一个好的经验法则是始终传递该函数所需的所有内容,或将对象所需的所有内容附加到窗口对象并将其全局化。