Почему & ldquo; [] === [] & rdquo; или & ldquo; [] == [] & rdquo; оценить значение false в javascript? [Дубликат]

Еще один интересный способ использования синтаксиса функции ES6:

x = ['a', 'a', 'a', 'a']
!x.filter(e=>e!==x[0])[0]  // true

x = ['a', 'a', 'b', 'a']
!x.filter(e=>e!==x[0])[0] // false

x = []
!x.filter(e=>e!==x[0])[0]  // true

И если вы не хотите повторно использовать переменную для массива (x):

!['a', 'a', 'a', 'a'].filter((e,i,a)=>e!==a[0])[0]    // true

Предыдущий плакат IMO, который использовал массив. Каждый (...) имеет самое чистое решение.

19
задан Shubham Khatri 23 January 2018 в 13:49
поделиться

7 ответов

Массивы Javascript - это объекты, и вы не можете просто использовать оператор равенства ==, чтобы понять, является ли содержание для этих объектов одинаковым. Оператор равенства будет проверять только, если два объекта на самом деле являются точно одним и тем же экземпляром (например, myObjVariable==myObjVariable, также работает для null и undefined).

Если вам нужно проверить, равны ли два массива я бы рекомендовал просто пересечь оба массива и убедиться, что все элементы имеют одинаковое значение (и что два массива имеют одинаковую длину).

Что касается равенства пользовательских объектов, я бы построил вместо этого конкретный equals, и я добавлю его в прототип вашего класса.

Учитывая, что в конце вы преобразовали оба массива в String и проверили равенство полученных строк, вы могли бы однажды подумать используя аналогичную, но более общую технику, которую вы найдете в более чем нескольких местах:

JSON.stringify(OBJ1) === JSON.stringify(OBJ2) 

Ну, не надо.

Хотя это может работать, если порядок свойства всегда будут одинаковыми для этих экземпляров объектов, это оставляет дверь открытой для чрезвычайно неприятных ошибок, которые трудно отследить. Всегда предпочитайте более явный подход и просто пишите чистую и читаемую функцию, которая будет проверять равенство, проверяя все необходимые поля.

25
ответ дан Umberto Raimondi 15 August 2018 в 20:01
поделиться
  • 1
    Интересно отметить, что myObjVariable == myObjectVariable истинно во всех случаях JS, кроме myObjVariable = NaN ... :) – War10ck 3 May 2018 в 20:21
  • 2
    есть много интересных заметок о NaN, одном из самых известных существ NaN.constructor === Number. – Dmitry 3 May 2018 в 20:22

Равенство для объектов скажет вам, являются ли два объекта одинаковыми.

var a = [];
var b = a;
a === b;    // True, a and b refer to the same object
[] === [];  // False, two separate objects

Вам нужно будет пропустить массивы, чтобы увидеть, имеют ли они одинаковые элементы.

См.: Как проверить, равны ли два массива с JavaScript?

0
ответ дан Community 15 August 2018 в 20:01
поделиться

Мое предположение заключается в том, что, поскольку при разработке javascript они считали, что элементное сравнение было редко используемой функцией, поэтому оно никогда не помещалось в язык.

Эта функция довольно распространена на популярных языках; Java не поддерживает его, C # не поддерживает его, C ++ stl-типы не поддерживают его.

Элементное сравнение довольно дорогое и сложное по сравнению с эталонным сравнением.

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

К сожалению, мы не живем в идеальном мире, и выше это возможно только для строк с пулом строк, а также с некоторыми другими относительно дорогими вариантами кэширования относительно памяти.

Некоторые языки, такие как Prolog и Haskell, позволяют сравнивать по значению; например

myProgram :- 
    Object1 = [1, "something", true, [1,[[], []], true,[false]]],
    Object2 = [1, "something", false, [1,[[], []], true,[false]]],
    Object3 = [1, "something", true, [1,[[], []], true,[false]]],
    Object4 = [1, "something", false, [1,[[], []], true,[false]]],
    (Object1 = Object2 
        -> write("first test passed.")    
        ; write("first test failed\n")),
    (Object1 = Object3 
        -> write("second test passed!\n")
        ; write("second test failed!\n")),
    (Object2 = Object4
        -> write("third test passed!\n")
        ; write("third test failed!")).

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

class MyList {
    constructor(a, b) {
        this.head_ = a;
        this.tail_ = b;
    }
    getHead() {
        return this.head_;
    }
    getTail() {
        return this.tail_;
    }
    setHead(x) {
        this.head_ = x;
    }
    setTail(x) {
        this.tail_ = x;
    }
    equals(other) {
        if (typeof other !== 'object') {
            console.log(other, 'EEP');
            return false;
        }
        if (!(other instanceof MyList)) {
            console.log(other, 'EEP');
            return false;
        }

        var h = this.head_;
        var ho = other.getHead();
        var cmp1 = comparatorof(h);
        if (!cmp1(h, ho)) {
            return false;
        }
        var t = this.tail_;
        var to = other.getTail();
        var cmp2 = comparatorof(t);
        if (!cmp2(t, to)) {
            return false;
        }

        return true;
    }
}

var object1 = {
    0: "one",
    1: "two",
    2: ["one", "two", []],
    something: {
        1: [false, true]
    }
};

function strictComparator(a, b) {
    return a === b;
}

// given any object, tries finding a function for comparing 
// that object to objects of the same kind. Kind being
// used loosely, since some objects like null resist being categorized,
// so these objects need special alteration of the comparatorof itself.
function comparatorof(x) {
    if (x === null || x === undefined) {
        return strictComparator;
    }

    x = Object(x); // promote primitives to objects
    var ctor = x.constructor;
    var c2ct = ctorToComparatorTable;
    var n = c2ct.length;

    for (var i = 0; i < n; ++i) {
        var record = c2ct[i];
        var keyCtor = record[0];

        if (keyCtor === ctor) {
            return record[1];
        }
    }
    throw new TypeError('no comparator exists for ' + x);
}

var ctorToComparatorTable = [
    [String, function(a, b) {
        return a == b;
    }],
    [Object, function(a, b) {
        for (var key in a) {
            var avalue = a[key];
            var bvalue = b[key];
            var cmp = comparatorof(avalue);

            if (!cmp(avalue, bvalue)) {
                return false;
            }
        }

        return true;
    }],
    [Number, function(a, b) {
        return a == b;
    }],
    [Boolean, function(a, b) {
        return a == b;
    }],
    [Array, function(as, bs) {
        if (typeof bs !== 'object') {
            return false;
        }
        var nAs = as.length;
        var nBs = bs.length;

        if (nAs !== nBs) {
            return false;
        }

        for (var i = 0; i < nAs; ++i) {
            var a = as[i];
            var b = bs[i];
            var cmp = comparatorof(a);

            if (!cmp(a, b)) {
                return false;
            }
        }

        return true;
    }],
    [MyList, function(a, b) {
        return a.equals(b);
    }]
];

// true
console.log(comparatorof([])([new MyList(1, new MyList(2, 3))], [new MyList(1, new MyList(2, 3))]));
// true
console.log(comparatorof([])([{}, new MyList(1, new MyList(2, 3))], [{}, new MyList(1, new MyList(2, 3))]));
// false
console.log(comparatorof([])([{}, new MyList(1, new MyList(2, 3))], [{}, new MyList(1, new MyList(3, 3))]));
// true
console.log(comparatorof({})({
    1: 'one',
    one: '1',
    x: new MyList(1, {})
}, {
    1: 'one',
    one: '1',
    x: new MyList(1, {})
}));
// true
console.log(comparatorof(2)(
    3,
    3
));
//true
console.log(comparatorof(true)(
    true,
    true
));
//false
console.log(comparatorof([])(
    [1, 2, new MyList(1, 2)], [1, 2, new MyList(4, 9)]
));
// true
console.log(comparatorof([])(
    [1, 2, new MyList(1, 2), null], [1, 2, new MyList(1, 2), null]
));
// false
console.log(comparatorof(null)(
    null,
    undefined
));
// true
console.log(comparatorof(undefined)(
    undefined,
    undefined
));
// true
console.log(comparatorof(null)(
    null,
    null
));

Одна большая проблема заключается в том, что ES6 уже полон функций, которые несовместимы с JScript и Nashorn JJS, а также с ActionScript, что язык может также быть переименован как совершенно новый язык каждые несколько месяцев, учитывая, что это эффективно то, что вы получить, когда вы добавляете новые функции на язык, который нарушает совместимость со старыми версиями, которые не могут быть реплицированы без дополнительного уровня eval.

Эта проблема длится долго, когда на одной стороне у вас минимальный язык как Lisp, который «легче» (до сих пор не может перегружать «оператор»), чтобы внедрить функции «первого класса», не нарушая обратной совместимости, а затем у вас есть такие языки, как Perl, которые не могут быть расширены с помощью новых первоклассных ключевых слов без дополнительной оценки Эйер. JavaScript выбрал второй подход и, как правило, обходит последствия, используя вспомогательные объекты, такие как Math, Object, чтобы вводить новые функции, но в любое время, когда он хочет добавить «конструкции первого класса», он в конечном итоге нарушает обратную совместимость.

доказательство концепции, в Lisp вы можете перегрузить == operator, тогда как в JavaScript вы не можете, а в Perl вы можете, но через механизм, который резервирует ключевые слова.

-1
ответ дан Dmitry 15 August 2018 в 20:01
поделиться
  • 1
    ", потому что, когда javascript был спроектирован, они считали, что элементное сравнение было редко используемой функцией, поэтому оно никогда не помещалось в язык." . – Ry-♦ 22 July 2018 в 19:20
  • 2
    Это я знал, что кто-то поймает меня за это. Я сделал предположение, потому что это дополнительная языковая функция, которую я не могу придумать ни о каком другом языке сценариев в то время, когда предлагаю. Очень немногие языки предлагают сопоставление списков на уровне языка, и это вызывает некоторую путаницу, потому что c-подобные языки обычно работают путем сравнения ссылок, а не сравнения значений. Большой улов, хотя, я буду перефразировать его, чтобы быть более благотворительным позже. – Dmitry 22 July 2018 в 20:17

Массивы - это объекты в JavaScript, которые проходят по ссылке. Это означает, что при инициализации массива:

var array = [1, 2, 3];

Я создал ссылку на этот массив в памяти. Если я тогда скажу:

var otherArray = [1 2, 3];

array и otherArray имеют два отдельных адреса в памяти, поэтому они не будут равно друг другу (даже если значения равны.) Чтобы проверить проход по ссылке, вы можете играть вокруг с массивами:

var copyArray = array;

В этом случае copyArray ссылается на тот же адрес в памяти, что и на массив, поэтому:

copyArray === array; //will evaluate to true
array.push(4); //copyArray will now have values [1, 2, 3, 4];
copyArray.push(5); //array will have values [1, 2, 3, 4, 5];
copyArray === array; //still true

Чтобы проверить равенство значений в массив или объект, вам нужно сделать «глубокое сравнение» - для массивов это будет пересекать оба массива для сравнения индекса и значения, чтобы убедиться, что оба они равны - для объектов он будет пересекать каждый ключ и гарантирует, что значение будет одинаковым. Для более глубоких сравнений вы можете проверить источник аннотированных объектов underscore.js:

http://underscorejs.org/docs/underscore.html

4
ответ дан Geoffrey Abdallah 15 August 2018 в 20:01
поделиться
  • 1
    «Передача по ссылке» является свойством аргумента в вызове функции (и его нет в JavaScript). Здесь нет вызова функции. – Ry-♦ 22 July 2018 в 19:18

Оператор == для объектов в Javascript проверяет, являются ли объекты одной и той же ссылкой на фактический объект, а не если они представляют собой два отдельных объекта, которые содержат одно и то же содержимое. Нет встроенного оператора для проверки того, содержат ли они одно и то же содержимое. Вам нужно будет написать функцию, чтобы выполнить подобное сравнение.

Преобразование строк является одним из способов сравнения двух массивов, если элементы массива содержат только примитивные значения (а не другие объекты). Если элементы массива могут содержать другие элементы, тогда вам нужно будет убедиться, что сами эти объекты также были преобразованы в репрезентативные строки.

И преобразование в строку не различало бы элемент массива, содержащий "4" против единицы, которая содержит 4, поскольку оба преобразуются в "4" в строчном представлении.

8
ответ дан jfriend00 15 August 2018 в 20:01
поделиться

В javascript каждый [] является экземпляром класса window.Array. Таким образом, вы в основном пытаетесь сравнить два разных объекта. Поскольку у массива может быть нет. и любые типы элементов, включая объекты и пользовательские объекты, и те вложенные массивы могут снова иметь множество свойств и массивов и т. д.

. Когда дело доходит до сравнения, становится неясным, вы никогда не будете уверены, что вы хотите делать с этими объектами и вложенными свойствами. То, чего вы пытаетесь достичь путем сравнения, может быть сделано многими другими способами. Вам просто нужно выяснить правильный путь для вашего дела.

2
ответ дан Vinay Aggarwal 15 August 2018 в 20:01
поделиться
0
ответ дан Community 5 September 2018 в 19:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: