Странное поведение при применении метода Array.prototype.slice к результату querySelectorAll - PullRequest
3 голосов
/ 15 сентября 2010

Я пытаюсь использовать механизм выбора Sizzle jQuery в качестве пользовательского API локации Selenium, как в этой статье: http://johnjianfang.blogspot.com/2009/04/how-to-use-jquery-to-create-custom.html

К сожалению, когда я использую selenium.click('jquery=a.mylink'), ничего не происходит.1006 *selenium.click('css=a.mylink') отлично работает.

Я провел небольшое исследование и обнаружил, что проблема заключается в том, как jQuery преобразует результат API querySelectorAll.Вот фрагмент из jQuery 1.4.2:

Sizzle = function(query, context, extra, seed){
    context = context || document;

    // Only use querySelectorAll on non-XML documents
    // (ID selectors don't work in non-HTML documents)
    if ( !seed && context.nodeType === 9 && !isXML(context) ) {
        try {
            return makeArray( context.querySelectorAll(query), extra );
        } catch(e){}
    }

    return oldSizzle(query, context, extra, seed);
};


var makeArray = function(array, results) {
    array = Array.prototype.slice.call( array, 0 );

    if ( results ) {
        results.push.apply( results, array );
        return results;
    }

    return array;
};

Когда я изменяю makeArray следующим образом:

var makeArray = function(arrayLikeObject, results) {

    var array = new Array(arrayLikeObject.length);
    for (var i = 0, n = arrayLikeObject.length; i < n; i++) {
        array[i] = arrayLikeObject[i];
    }

    if ( results ) {
        results.push.apply( results, array );
        return results;
    }

    return array;
};

Это решает эту странную проблему.

Есть идеи, почему это исправление работает?!

1 Ответ

1 голос
/ 26 сентября 2012

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

// Perform a simple check to determine if the browser is capable of
// converting a NodeList to an array using builtin methods.
// Also verifies that the returned array holds DOM nodes
// (which is not the case in the Blackberry browser)
try {
    Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;

// Provide a fallback method if it does not work
} catch(e){
    makeArray = function(array, results) {
        var ret = results || [];

        if ( toString.call(array) === "[object Array]" ) {
            Array.prototype.push.apply( ret, array );
        } else {
            if ( typeof array.length === "number" ) {
                for ( var i = 0, l = array.length; i < l; i++ ) {
                    ret.push( array[i] );
                }
            } else {
                for ( var i = 0; array[i]; i++ ) {
                    ret.push( array[i] );
                }
            }
        }

        return ret;
    };
}
...