Еще один интересный способ использования синтаксиса функции 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, который использовал массив. Каждый (...) имеет самое чистое решение.
Массивы Javascript - это объекты, и вы не можете просто использовать оператор равенства ==
, чтобы понять, является ли содержание для этих объектов одинаковым. Оператор равенства будет проверять только, если два объекта на самом деле являются точно одним и тем же экземпляром (например, myObjVariable==myObjVariable
, также работает для null
и undefined
).
Если вам нужно проверить, равны ли два массива я бы рекомендовал просто пересечь оба массива и убедиться, что все элементы имеют одинаковое значение (и что два массива имеют одинаковую длину).
Что касается равенства пользовательских объектов, я бы построил вместо этого конкретный equals
, и я добавлю его в прототип вашего класса.
Учитывая, что в конце вы преобразовали оба массива в String
и проверили равенство полученных строк, вы могли бы однажды подумать используя аналогичную, но более общую технику, которую вы найдете в более чем нескольких местах:
JSON.stringify(OBJ1) === JSON.stringify(OBJ2)
Ну, не надо.
Хотя это может работать, если порядок свойства всегда будут одинаковыми для этих экземпляров объектов, это оставляет дверь открытой для чрезвычайно неприятных ошибок, которые трудно отследить. Всегда предпочитайте более явный подход и просто пишите чистую и читаемую функцию, которая будет проверять равенство, проверяя все необходимые поля.
Равенство для объектов скажет вам, являются ли два объекта одинаковыми.
var a = [];
var b = a;
a === b; // True, a and b refer to the same object
[] === []; // False, two separate objects
Вам нужно будет пропустить массивы, чтобы увидеть, имеют ли они одинаковые элементы.
Мое предположение заключается в том, что, поскольку при разработке 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 вы можете, но через механизм, который резервирует ключевые слова.
Массивы - это объекты в 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:
Оператор ==
для объектов в Javascript проверяет, являются ли объекты одной и той же ссылкой на фактический объект, а не если они представляют собой два отдельных объекта, которые содержат одно и то же содержимое. Нет встроенного оператора для проверки того, содержат ли они одно и то же содержимое. Вам нужно будет написать функцию, чтобы выполнить подобное сравнение.
Преобразование строк является одним из способов сравнения двух массивов, если элементы массива содержат только примитивные значения (а не другие объекты). Если элементы массива могут содержать другие элементы, тогда вам нужно будет убедиться, что сами эти объекты также были преобразованы в репрезентативные строки.
И преобразование в строку не различало бы элемент массива, содержащий "4"
против единицы, которая содержит 4
, поскольку оба преобразуются в "4"
в строчном представлении.
В javascript каждый []
является экземпляром класса window.Array
. Таким образом, вы в основном пытаетесь сравнить два разных объекта. Поскольку у массива может быть нет. и любые типы элементов, включая объекты и пользовательские объекты, и те вложенные массивы могут снова иметь множество свойств и массивов и т. д.
. Когда дело доходит до сравнения, становится неясным, вы никогда не будете уверены, что вы хотите делать с этими объектами и вложенными свойствами. То, чего вы пытаетесь достичь путем сравнения, может быть сделано многими другими способами. Вам просто нужно выяснить правильный путь для вашего дела.
myObjVariable == myObjectVariable
истинно во всех случаях JS, кромеmyObjVariable = NaN
... :) – War10ck 3 May 2018 в 20:21NaN.constructor === Number
. – Dmitry 3 May 2018 в 20:22