Search code examples
javascriptoperatorsorder-of-execution

Why do these snippets of JavaScript behave differently even though they both encounter an error?


var a = {}
var b = {}

try{
  a.x.y = b.e = 1 // Uncaught TypeError: Cannot set property 'y' of undefined
} catch(err) {
  console.error(err);
}
console.log(b.e) // 1

var a = {}
var b = {}

try {
  a.x.y.z = b.e = 1 // Uncaught TypeError: Cannot read property 'y' of undefined
} catch(err) {
  console.error(err);
}

console.log(b.e) // undefined


Solution

  • Actually, if you read the error message properly, case 1 and case 2 throw different errors.

    Case a.x.y:

    Cannot set property 'y' of undefined

    Case a.x.y.z:

    Cannot read property 'y' of undefined

    I guess it's best to describe it by step-by-step execution in easy English.

    Case 1

    // 1. Declare variable `a`
    // 2. Define variable `a` as {}
    var a = {}
    
    // 1. Declare variable `b`
    // 2. Define variable `b` as {}
    var b = {}
    
    try {
    
      /**
       *  1. Read `a`, gets {}
       *  2. Read `a.x`, gets undefined
       *  3. Read `b`, gets {}
       *  4. Set `b.z` to 1, returns 1
       *  5. Set `a.x.y` to return value of `b.z = 1`
       *  6. Throws "Cannot **set** property 'y' of undefined"
       */
      a.x.y = b.z = 1
      
    } catch(e){
      console.error(e.message)
    } finally {
      console.log(b.z)
    }

    Case 2

    // 1. Declare variable `a`
    // 2. Define variable `a` as {}
    var a = {}
    
    // 1. Declare variable `b`
    // 2. Define variable `b` as {}
    var b = {}
    
    try {
    
      /**
       *  1. Read `a`, gets {}
       *  2. Read `a.x`, gets undefined
       *  3. Read `a.x.y`, throws "Cannot **read** property 'y' of undefined".
       */
      a.x.y.z = b.z = 1
      
    } catch(e){
      console.error(e.message)
    } finally {
      console.log(b.z)
    }

    In comments, Solomon Tam found this ECMA documentation about assignment operation.