Доступ к родителю родителя из объекта JavaScript - PullRequest
53 голосов
/ 08 октября 2008

Что-то вроде

var life= {
        users : {
             guys : function(){ this.SOMETHING.mameAndDestroy(this.girls); },
             girls : function(){ this.SOMETHING.kiss(this.boys); },
        },
        mameAndDestroy : function(group){ },
        kiss : function(group){ }
};

this.SOMETHING это то, что я представляю себе формат, но это может быть не так. Что будет на шаг назад к родителю объекта?

Ответы [ 11 ]

55 голосов
/ 05 октября 2010

Я просто добавил в первую функцию

parentThis = this;

и используйте parentThis в подфункции. Зачем? Потому что в JavaScript объекты мягкие. Новый член может быть добавлен к мягкому объекту простым присваиванием (не как, например, Java, где классические объекты сложны. Единственный способ добавить новый член к жесткому объекту - создать новый класс). 1004 *http://www.crockford.com/javascript/inheritance.html

А также в конце вам не нужно убивать или уничтожать объект. Почему я нашел здесь: http://bytes.com/topic/javascript/answers/152552-javascript-destroy-object

Надеюсь, это поможет

42 голосов
/ 08 октября 2008

JavaScript не предлагает эту функциональность изначально. И я сомневаюсь, что вы могли бы даже создать этот тип функциональности. Например:

var Bobby = {name: "Bobby"};
var Dad = {name: "Dad", children: [ Bobby ]};
var Mom = {name: "Mom", children: [ Bobby ]};

Кому принадлежит Бобби?

19 голосов
/ 08 октября 2008

В этом случае вы можете использовать life для ссылки на родительский объект. Или вы можете сохранить ссылку на life в объекте users. Не может быть фиксированного parent доступного вам на языке, потому что пользователи - это просто ссылка на объект, и могут быть другие ссылки ...

var death = { residents : life.users };
life.users.smallFurryCreaturesFromAlphaCentauri = { exist : function() {} };
// death.residents.smallFurryCreaturesFromAlphaCentauri now exists
//  - because life.users references the same object as death.residents!

Возможно, вам будет полезно использовать что-то вроде этого:

function addChild(ob, childName, childOb)
{
   ob[childName] = childOb;
   childOb.parent = ob;
}

var life= {
        mameAndDestroy : function(group){ },
        kiss : function(group){ }
};

addChild(life, 'users', {
   guys : function(){ this.parent.mameAndDestroy(this.girls); },
   girls : function(){ this.parent.kiss(this.boys); },
   });

// life.users.parent now exists and points to life
4 голосов
/ 05 февраля 2017

О звонке:

Вы можете решить эту проблему, используя .call(), которая:

  • должен вызываться для функции addName.call()
  • вы передаете ему объект того, кем вы хотите быть "этим" addName.call({"name" : 'angela'});
  • вы можете передать дополнительные аргументы, которые можно использовать в функции, для которой она вызывается addName.call({"name": "angela"}, true);, где, возможно, addName принимает аргумент логического append.

Использовать звонок:

Для этой конкретной проблемы мы можем передать «родительский» объект через call, чтобы переопределить this, обычно присутствующий в дочернем объекте.

Сначала посмотрите на нашу проблему

var app = {
    init: function() {
        var _this = this; // so we can access the app object in other functions

        $('#thingy').click(function(){
            alert(_this.options.thingy());
        });

        $('#another').click(function(){
            alert(_this.options.getAnother());
        });
    },
    options: {
      thingy: function() {
      // PROBLEM: the this here refers to options
        return this.getThingy();
      },
      getAnother: function() {
        // PROBLEM 2: we want the this here to refer to options,
        // but thingy will need the parent object
        return 'another ' + this.thingy();
      },
    },
    getThingy: function() {
        return 'thingy';
    }
};

Теперь вот вызов использования решения

И JSFIDDLE чтобы увидеть, как это работает.

var app = {
    init: function() {
        var _this = this; // so we can access the app object in other functions

        $('#thingy').click(function(){
            // SOLUTION: use call to pass _this as the 'this' used by thingy
            alert(_this.options.thingy.call(_this));
        });

        $('#another').click(function(){
            // SOLUTION 2: Use call to pass parent all the way through
            alert(_this.options.getAnother.call(_this)); 
        });
    },
    options: {
      thingy: function() {
        // SOLUTION in action, the this is the app object, not options.
        return this.getThingy(); 
      },
      getAnother: function() {
        // SOLUTION 2 in action, we can still access the options 
        // AND pass through the app object to the thingy method.
        return 'another ' + this.options.thingy.call(this); 
      },
    },
    getThingy: function() {
        return 'thingy';
    }
};

В заключение

Вы можете использовать .call() всякий раз, когда вы используете метод для свойства вашего основного объекта: app.options.someFunction(arg) всегда должен вызываться с .call - app.options.someFunction.call(this, arg); - таким образом вы можете быть уверены, что у вас всегда будет доступ к каждой части объекта. Это может дать вам доступ к методам другого свойства, таким как app.helpers.anotherFunction().

Хорошая идея в somefunction, хранить this в переменной _parentThis, поэтому очевидно, что отражает this.

4 голосов
/ 08 октября 2008

Если я правильно читаю ваш вопрос, объекты в целом не знают, где они содержатся. Они не знают, кто их родители. Чтобы найти эту информацию, вы должны проанализировать родительскую структуру данных. У DOM есть способы сделать это для нас, когда вы говорите об элементных объектах в документе, но похоже, что вы говорите о ванильных объектах.

3 голосов
/ 23 декабря 2009

Вот, пожалуйста:

var life={
        users:{
             guys:function(){ life.mameAndDestroy(life.users.girls); },
             girls:function(){ life.kiss(life.users.guys); }
        },
        mameAndDestroy : function(group){ 
          alert("mameAndDestroy");
          group();
        },
        kiss : function(group){
          alert("kiss");
          //could call group() here, but would result in infinite loop
        }
};

life.users.guys();
life.users.girls();

Кроме того, убедитесь, что у вас нет запятой после определения "girls". Это приведет к аварийному завершению работы скрипта в IE (каждый раз, когда у вас запятая после последнего элемента в массиве в IE, он умирает).

Смотри, беги

2 голосов
/ 30 января 2018

Как уже говорили другие, невозможно напрямую искать родителя от вложенного ребенка. Все предлагаемые решения предлагают различные способы возврата к родительскому объекту или родительской области с помощью явного имени переменной.

Однако прямой переход к родительскому объекту возможен, если вы используете рекурсивный ES6 Proxies для родительского объекта.

Я написал библиотеку с именем ObservableSlim , которая, помимо прочего, позволяет вам переходить от дочернего объекта к родительскому.

Вот простой пример ( jsFiddle demo ):

var test = {"hello":{"foo":{"bar":"world"}}};
var proxy = ObservableSlim.create(test, true, function() { return false });

function traverseUp(childObj) {
    console.log(JSON.stringify(childObj.__getParent())); // returns test.hello: {"foo":{"bar":"world"}}
    console.log(childObj.__getParent(2)); // attempts to traverse up two levels, returns undefined because test.hello does not have a parent object
};

traverseUp(proxy.hello.foo);
1 голос
/ 03 июля 2016

Я использовал что-то похожее на синглтон-паттерн:

function myclass() = {
    var instance = this;

    this.Days = function() {
        var days = ["Piątek", "Sobota", "Niedziela"];
        return days;
    }

    this.EventTime = function(day, hours, minutes) {
        this.Day = instance.Days()[day];
        this.Hours = hours;
        this.minutes = minutes;
        this.TotalMinutes = day*24*60 + 60*hours + minutes;
    }
}
0 голосов
/ 19 декабря 2016

Если вы хотите получить все родительские ключи узла в литеральном объекте ({}), вы можете сделать это:

(function ($) {
    "use strict";

    $.defineProperties($, {
        parentKeys: {
            value: function (object) {
                var
                    traces = [],
                    queue = [{trace: [], node: object}],

                    block = function () {
                        var
                            node,
                            nodeKeys,
                            trace;

                        // clean the queue
                        queue = [];
                        return function (map) {
                            node = map.node;
                            nodeKeys = Object.keys(node);

                            nodeKeys.forEach(function (nodeKey) {
                                if (typeof node[nodeKey] == "object") {
                                    trace = map.trace.concat(nodeKey);
                                    // put on queue
                                    queue.push({trace: trace, node: node[nodeKey]});

                                    // traces.unshift(trace);
                                    traces.push(trace);
                                }
                            });
                        };
                    };

                while(true) {
                    if (queue.length) {
                        queue.forEach(block());
                    } else {
                        break;
                    }
                }

                return traces;
            },

            writable: true
        }

    });

})(Object);

Этот алгоритм использует концепцию FIFO для итерации графиков с использованием метода BFS. Этот код расширяет класс Object, добавляя статический метод parentKeys, который ожидает literal Object (хэш-таблица - ассоциативный массив ...) Javacript, в качестве параметра.

Надеюсь, я помог.

0 голосов
/ 17 мая 2016

С помощью следующего кода вы можете получить доступ к родителю объекта:

var Users = function(parent) {
    this.parent = parent;
};
Users.prototype.guys = function(){ 
    this.parent.nameAndDestroy(['test-name-and-destroy']);
};
Users.prototype.girls = function(){ 
    this.parent.kiss(['test-kiss']);
};

var list = {
    users : function() {
        return new Users(this);
    },
    nameAndDestroy : function(group){ console.log(group); },
    kiss : function(group){ console.log(group); }
};

list.users().guys(); // should output ["test-name-and-destroy"]
list.users().girls(); // should output ["test-kiss"]

Я бы порекомендовал вам прочитать о javascript Objects , чтобы узнать, как вы можете работать с объектами, это мне очень помогло. Я даже узнал о функциях, о которых даже не знал, что они существуют.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...