未捕获的SyntaxError:意外的令牌{

Error prompted when execute console.log($obj.longurl) from the Chrome Developer Console

Uncaught SyntaxError: Unexpected token { 
$.ajax.complete 
L jquery.min.js:19
N

Below is the script I execute from a HTML page and submit a form to call an external PHP file.

Javascript is called from http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js

$('#shortener').submit(function(e) {
    e.preventDefault();
    $('#status').text('');
    $.ajax({
        cache: false,
        type: "POST",
        dataType: "json",
        data: $('#shortener').serialize(),
        url: $('#shortener').attr('action'),
        complete: function (XMLHttpRequest, textStatus) {
            console.log(XMLHttpRequest);
            $obj = JSON.parse(XMLHttpRequest.response);
            if ($obj.loginResult == "Passed") {
                ($('#longurl').val() === "") ? console.log("Empty longurl") : console.log($obj.longurl);
            } else {
                $('#status').text("Login Failed");
            };
        }
    });
    return false;
});

PHP

echo json_encode(array('loginResult' =>'Passed'));
echo json_encode(array('longurl' => BASE_HREF . $shortened_url));

typeof $obj.longurl is string but don't know why it can be returned to the $('#shortener').val(), anyone have similar experience and have the solution?

Your PHP code is producing invalid JSON. You are basically echoing two JSON encoded objects after each other, which overall results in invalid JSON. It will look like:

{"loginResult": "Passed"} {"longurl": "<some URL>"}

The second { is the syntax error.

It should either be an array of objects (although that would be a strange structure)

[{"loginResult": "Passed"}, {"longurl": "<some URL>"}]

or one object

{"loginResult": "Passed", "longurl": "<some URL>"}

Create and encode one array:

echo json_encode(array(
    'loginResult' => 'Passed',
    'longurl' => BASE_HREF . $shortened_url
));

Another problem might be that, at least officially, the jqXHR object passed to the complete callback doesn't have a .response property. Since you also already set the dataType: 'json' option, there is no need for you to parse the response explicitly.

Here is an improved version of your code:

$.ajax({
    cache: false,
    type: "POST",
    dataType: "json",
    data: $('#shortener').serialize(),
    url: $('#shortener').attr('action'),
}).done(function (data) {
    if (data.loginResult == "Passed") {
        ($('#longurl').val() === "") ? console.log("Empty longurl") : console.log(data.longurl);
    } else {
        $('#status').text("Login Failed");
    }
});