-->

What does the Javascript expression 'a = a ||

2019-02-03 06:19发布

问题:

I'm not sure what this construct means but I've seen it a few times. The example below is from another Stack Overflow question. I'm not sure how to interpret the initial "or" construct itself:

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(){...} is an idiom that is very common in Javascript. It relies on two concepts that, while not unique to Javascript, you might not yet be familiar with.

1. Operator short circuiting

Operator short circuiting[wikipedia] is a compiler optimization that was invented to prevent unnecessary evaluation.

To demonstrate this, let us suppose that we want to determine whether a person is a teenager: that is, whether a person has an age inclusively between 13 and 19 years.

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

Now, let us suppose that the code executes and it turns out that the person is younger than 13. The first condition will be evaluated and will return false. Since the program now knows that the the left hand side of the && operator is false, and since && requires both sides to be true in order to evaluate to true, it knows that evaluating the right hand side is pointless.

In other words, the program, having seen that the person's age is not greater than 13, already knows that he is not a teenager and couldn't care less whether or not he is less than 19.

The same sort of principle applies to the || operator. Suppose we wanted to know if a person can ride the bus for free: that is, if the person is over 70 years old or is handicapped.

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

If the person is over 70, the program already knows that he can ride free. At this point, the program does not care if he is handicapped or not and thus does not evaluate the call to the isHandicapped function. If, on the other hand, the person was younger than 70, then canRideFree would be set to whatever isHandicapped returns.

2. Truthy and falsy values

Truthy and falsy values[some random person's blog] are the boolean evaluations of objects. In Javascript, every object will evaluate to either a "truthy" or a "falsy" value.

An expression is "falsy" if its value is any of these:

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

Everything else is truthy.

People take advantage of the fact that a null or undefined variable evaluates to false. This means that you can check if a variable exists very easily:

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

Combining what we know

The || operator short circuits and returns the value of the last expression that it evaluates. This principle combines with truthiness in this single statement:

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

If Object.keys is truthy, it will be evaluated and assigned to itself. Otherwise, Object.keys will be assigned to the function. This is a very common idiom in Javascript for checking if a value already exists and assigning it to something else if it doesn't.

Some other languages, such as C#, that do not have truthiness, have a null-coalescing operator[MSDN] that has a similar purpose.

object Value = PossiblyNullValue ?? ValueIfNull;

In this code, Value will be assigned to PossiblyNullValue, unless it's null, in which case it will be assigned to ValueIfNull.

tl;dr [wikipedia]

If you didn't bother to read anything I said above, all you need to know is that a = a || function() {...} basically does what this code does:

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:

This looks incomplete to me, but it seems as if it is a shim for Object.keys. Basically, if the property doesn't exist (in non standards compliant browsers, for example), we implement it ourselves.

The or operator will evaluate the second operand only if the first one is falsy. As such

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

Will alert "Hello, world". In this case, Object.keys would be undefined, which evaluates to false.



回答3:

The || basically means: If Object.keys is not defined, define it using the expression behind the ||.

This behavior bases on the JavaScript feature that any variable that is undefined evaluates to false. If the variable is true, the second expression does not need to be evaluated, if it is false it does.



回答4:

From what I can tell, that code attempts to define the function Object.keys if it isn't already defined (or if it's false). The function to the left of || will become the function Object.keys.

The reason I said "from what I can tell" is that you haven't posted the entire code snippet. Notice that the code after || reads (function(){ instead of just function(){. It's possible that the author has set up the function to be self invoking.

If, after the function definition, you see })(), then the return value of the function is stored in Object.keys. If not, then the function itself is stored there.