Overriding nested properties in the prototype chain

I have the following nested data structure:

{ x: { y: 'foo', z: 'bar' } }

This data is stored on the prototype of the object, which is the parent of both specific objects and other prototypes.

I want to assign a property x.yto inherit objects without affecting the parent prototype. In addition, I want access to x.zbe delegated to the prototype.

What is the best way to do this?

Here is an executable snippet that better illustrates what I want to accomplish:

// Prototype with nested properties.
var prototype = {
    question: 'Am I nested?',
    nested: {
        answer: 'Yes.',
        thoughts: 'I like being nested.'
    }
};

// Another prototype. Overrides properties.
var liar = Object.create(prototype);
liar.nested.answer = 'N-No...!'; // Modifies prototype since
                                 // liar.nested === prototype.nested

// I could do this, but then I lose the other nested properties.
var indecisive = Object.create(prototype);
indecisive.nested = { answer: 'I dunno?' }; // New object, won't delegate.

// Output some text on the snippet results panel.
function results(text) { results.element.appendChild(document.createTextNode(text + '\n')); }; results.element = document.getElementById('results'); results.json = function() { for(var i = 0, len = arguments.length; i < len; ++i) { results(JSON.stringify(arguments[i], results.json.replacer, results.json.indentation)); } }; results.json.replacer = function(k, v) { return typeof v === 'undefined' ? 'undefined' : v; }; results.json.indentation = 4;

results.json(
  prototype.nested.answer,    // Shouldn't have been changed.
  liar.nested.answer,         // As expected.
  indecisive.nested.answer,   // As expected.

  prototype.nested.thoughts,  // As expected.
  liar.nested.thoughts,       // As expected.
  indecisive.nested.thoughts, // Undefined, when it should delegate to the prototype.

  prototype,                  // It been modified.
  liar,                       // It empty. It should have an own property.
  indecisive                  // Has own property, but nested object does not delegate.
);
<html>
  <body>
    <pre id="results"></pre>
  </body>
</html>
Run codeHide result

This question is complex because the property nestedrefers to the same object both in the prototype and in the objects associated with it. If I assign object.nested.answer, it changes object.nestedwhich is the same object that it refers to prototype.nested.

. , . object.nested.answer object.

object.nested. , object, object.nested.thoughts. , , prototype.nested.thoughts .

. prototype.nested.thoughts , , object ; nested.thoughts.

, , . ? , ?


,

. , API, , , , , , , , , , , - .

:

  • . , tuple.
  • tuple s.

    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚ Abstraction โ”‚  Pair  โ”‚      Description       โ”‚
    โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
    โ”‚ Coordinates โ”‚ (x, y) โ”‚ Cartesian coordinates. โ”‚
    โ”‚  Dimensions โ”‚ (w, h) โ”‚ Width and height.      โ”‚
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
    
  • , .

    • , toString prototype.
    • (x, y), tuple.
    • dimensions |w, h|.
    • :

      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
      โ”‚ Abstraction โ”‚      Notation      โ”‚              Grammar              โ”‚
      โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
      โ”‚       Tuple โ”‚ (xโ‚€, xโ‚, ... , xแตข) โ”‚ '(' element ( ', ' element )* ')' โ”‚
      โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
      โ”‚ Coordinates โ”‚       (x, y)       โ”‚ Inherits the grammar of Tuple.    โ”‚
      โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
      โ”‚  Dimensions โ”‚       |w, h|       โ”‚ '|' element ( ', ' element )* '|' โ”‚
      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
      

// 1. Tuple prototype.

var tuple = {
    prototype: {
        toString: function tuple_toString() {
            return '(' + this.elements.join(', ') + ')';
        }
    },
    new: function tuple_new() {
        var tuple = Object.create(this.prototype);
        tuple.elements = Array.prototype.slice.call(arguments);
        return tuple;
    }
};

// 2. Geometric concepts.

var coordinates = {
    prototype: Object.create(tuple.prototype),
    new: tuple.new
};

var dimensions = {
    prototype: Object.create(tuple.prototype),
    new: tuple.new
};

// 3.1 Prototype properties in the toString function.

tuple.prototype.toString = function tuple_toString() {
    var elements = this.elements,
        notation = this.notation, // Should be inherited from the prototype.
        join     = notation.join
        brackets = notation.brackets,
        open     = brackets.open,
        close    = brackets.close;

    return open + elements.join(join) + close;
};

// 3.4 Notational metadata in prototype.

tuple.prototype.notation = {
    brackets: {
        open: '(',
        close: ')'
    },
    join: ', '
};

dimensions.prototype.notation = {
    brackets: {
        open: '|',
        close: '|'
    }
    // Is the ', ' from tuple.prototype.notation.join inherited?
};

// Output some text on the snippet results panel.
function results(text) { results.element.appendChild(document.createTextNode(text + '\n')); }; results.element = document.getElementById('results'); results.json = function() { for(var i = 0, len = arguments.length; i < len; ++i) { results(JSON.stringify(arguments[i], results.json.replacer, results.json.indentation)); } }; results.json.replacer = function(k, v) { return typeof v === 'undefined' ? 'undefined' : v; }; results.json.indentation = 4;

var triplet = tuple.new(1, 2, 3);
var origin  = coordinates.new(0, 0);
var fullHD  = dimensions.new(1920, 1080);

results.json(
  triplet.toString(),    // (1, 2, 3) - As expected.
  origin.toString(),     // (0, 0) - As expected.
  fullHD.toString(),     // |1920,1080| - Where is the space?

  triplet.notation.join, // ', ' - As expected.
  origin.notation.join,  // ', ' - As expected.
  fullHD.notation.join   // undefined
);
<html>
  <body>
    <pre id="results"></pre>
  </body>
</html>
Hide result

fullHD.notation.join undefined. Array.prototype.join, , , .

, tuple.prototype.notation.join, ', '.

+4

Source: https://habr.com/ru/post/1614020/


All Articles