Что представляет собой выражение Javascript 'a = a || функция() {...} 'означает?

Я не уверен, что это за конструкция, но я видел это несколько раз. Ниже приведен пример из другого вопроса о переполнении стека. Я не уверен, как интерпретировать исходную "или" конструкцию:

Object.keys = Object.keys || (function () {
  var hasOwnProperty = Object.prototype.hasOwnProperty,
      hasDontEnumBug = !{toString:null}.propertyIsEnumerable("toString"),
      DontEnums = [ 
          'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty',
          'isPrototypeOf', 'propertyIsEnumerable', 'constructor'
      ],
      DontEnumsLength = DontEnums.length;
  //etc...
});

Ответы

Ответ 1

a = a || function(){...} - это идиома, которая очень распространена в Javascript. Он опирается на два понятия, которые, хотя и не являются уникальными для Javascript, вы, возможно, еще не знакомы.

1. Короткое замыкание оператора

Оператор короткого замыкания [wikipedia] - это оптимизация компилятора, которая была изобретена для предотвращения ненужной оценки.

Чтобы продемонстрировать это, давайте предположим, что мы хотим определить, является ли человек подростком: то есть, имеет ли человек возраст от 13 до 19 лет.

var isTeenager = person.age >= 13 && person.age <= 19;

Теперь предположим, что код выполняется, и оказывается, что человек моложе 13. Первое условие будет оценено и вернет false. Поскольку теперь программа знает, что левая часть оператора && равна false, и поскольку && требует, чтобы обе стороны были true, чтобы оценить значение true, он знает, что оценка права сторона стороны бессмысленна.

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

Такой же принцип применяется к оператору ||. Предположим, мы хотели узнать, может ли человек бесплатно ездить на автобусе: если человек старше 70 лет или инвалид.

var canRideFree = person.age >= 70 || isHandicapped(person);

Если человек старше 70 лет, программа уже знает, что он может ехать бесплатно. На данный момент программе все равно, если он инвалид или нет, и поэтому не оценивает вызов функции isHandicapped. Если, с другой стороны, человек был моложе 70, тогда canRideFree будет установлен на все isHandicapped.

2. Значения правды и ложности

Значения truthy и falsy [некоторый случайный блог] - это логические оценки объектов. В Javascript каждый объект будет оценивать либо "правдивое", либо "ложное" значение.

Выражение является "ложным", если его значением является любое из них:

false, null, undefined, 0, "", NaN

Все остальное правдиво.

Люди используют тот факт, что переменная null или undefined имеет значение false. Это означает, что вы можете проверить, существует ли переменная очень просто:

if (a) { /* a exists and is not a falsy value */ }

Объединяя то, что мы знаем

Короткие замыкания оператора || и возвращает значение последнего выражения, которое оно оценивает. Этот принцип сочетается с правдивостью в этом единственном утверждении:

Object.keys = Object.keys || function() {...}

Если Object.keys является правдивым, оно будет оцениваться и присваиваться самому себе. В противном случае функции Object.keys будут назначены функции. Это очень распространенная идиома в Javascript для проверки того, существует ли уже существующее значение и присваивает ему что-то еще, если это не так.

Некоторые другие языки, такие как С#, которые не имеют правдоподобия, имеют оператор с нулевой связностью [MSDN], который имеет аналогичную цель.

object Value = PossiblyNullValue ?? ValueIfNull;

В этом коде Value будет присвоен PossiblyNullValue, если он не равен нулю, и в этом случае ему будет присвоено значение ValueIfNull.

tl; dr [wikipedia]

Если вы не удосужились прочитать что-либо, о чем я сказал выше, все, что вам нужно знать, это то, что a = a || function() {...} в основном делает то, что делает этот код:

if (exists(Object.keys)) {
  Object.keys = Object.keys;
} else { 
  Object.keys = function() {...};
}

function exists(obj) {
  return typeof obj !== "undefined" && 
         obj !== null && 
         obj !== false &&
         obj !== 0 &&
         obj !== "" &&
         !isNaN(obj);
}

Ответ 2

Это выглядит неполным для меня, но кажется, что это прокладка для Object.keys. В принципе, если свойство не существует (например, в браузерах, не совместимых с стандартами), мы реализуем его сами.

Оператор or будет оценивать второй операнд только в том случае, если первый является ложным. Как таковой

alert(false || "Hello, world");

Будет предупреждать "Привет, мир". В этом случае Object.keys будет undefined, который оценивается как false.

Ответ 3

|| в основном означает: Если Object.keys не определено, определите его, используя выражение позади ||.

Это поведение основывается на функции JavaScript, что любая переменная undefined оценивается как false. Если переменная true, второе выражение не нужно оценивать, если оно есть false.

Ответ 4

Из того, что я могу сказать, этот код пытается определить функцию Object.keys, если она еще не определена (или если она ложна). Функция слева от || станет функцией Object.keys.

Причина, по которой я сказал "из того, что я могу сказать", заключается в том, что вы не опубликовали весь фрагмент кода. Обратите внимание, что код после || читает (function(){ вместо function(){. Возможно, автор установил функцию для самостоятельного вызова.

Если после определения функции вы видите })(), тогда возвращаемое значение функции сохраняется в Object.keys. Если нет, тогда сама функция хранится там.