obj.prop(path)

如果 JavaScript 引擎不支援 optional chaining (?., ?.[]),就可以用下面的程式。

由於使用 mixin 的方式,所以當我們使用 user.prop('info.age') 的方式來讀取物件屬性時,user 本身已經確定是個物件(不會是 null 或 undefined),因此我們在 prop(path) 這個 method 內部並沒有去檢查 this 是不是 null 或 undefined。

// ⭐ mixin for objects
const ObjectTools = {
    
    // obj.prop(path)
    prop(path) {
        
        let value = this;
        let components = path.split('.');
        
        while (components.length) {
            
            // pull first component
            let component = components.shift();
            // check if last character === '?'
            const isValueOptional = component.slice(-1) === '?';

            if (isValueOptional) {
                // remove "?"
                component = component.slice(0, -1);
                // get nested property
                value = value[component];
                // return early if value is nullish
                if (value === null || value === undefined) return undefined;
            } else {
                // if not optional, get property directly
                value = value[component];
            }
            
        }
        
        return value;
    }
};

// for node.js module
module.exports = objectTools;

💈範例:

"use strict";
const { log } = console;

// ⭐ mixin for objects
const ObjectTools = require('./ObjectTools.js');

// ---------- main ------------

// test object
const user = { 
    name: 'Joy',
    info: { 
        address: { 
            street: '5th Street',
            zip: 333,
        } 
    } 
};

// ⭐ apply mixin to `obj`
Object.assign(user, ObjectTools);

// ---------- log ------------
;
[
    user.prop("info.address"),           // { street: '5th Street', zip: 333 }
    user.prop("info.address.street"),    // '5th Street'
    
    user.prop("info.address.street.bar"),// undefined
    user.prop("info.age"),               // undefined
    user.prop("info.age?.details"),      // undefined
    user.prop("bar?.age?.details"),      // undefined
    
    // user.prop("bar.age"),             // ⛔ TypeError: 
    //                ^^^  <----  Cannot read property 'age' of undefined

    user === global.user,                // false: `const` doesn't create property of `global`
    
].forEach(x => log(x));

// user.prop("info.address.street")
// ---------------------------------
// initial states:
//
//   • value = user
//   • components = [ 'info', 'address', 'street' ] 
//
// while loop:
// --------------------------------------------------------------------
// length  shift()    components             value           
// --------------------------------------------------------------------
//   3     'info'    ['address', 'street']    user.info
//   2     'address' ['street']               user.info.address
//   1     'street'  [ ]                      user.info.address.street
//   0    <---- exit while loop              ╰── return value ───╯
// --------------------------------------------------------------------

Last updated