๐Ÿ’พ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