объект JavaScript это - PullRequest
       31

объект JavaScript это

2 голосов
/ 30 октября 2011

У меня есть объект, и у него есть другой внутренний объект.Как я могу вызвать родительский объект из внутреннего объекта?

var test = {
    init: function () {
        var instance = this;
    },
    call: function() {
        this.stop(); // works
    },
    stop: function() {
        this.parseText(); // works
    },
    parseText: {
        load: function ()
        {
            this.call(); //*** dont work
            instance.call(); // work, but what if i have this instance (same name) on another object, would'nt this conflict it?
        }
    }
};

Я использую экземпляр, который работает нормально, но что если я или кто-то написал экземпляр (то же имя) var в другом объекте,Разве это не будет конфликтовать и перезаписывать этот экземпляр?

Ответы [ 4 ]

9 голосов
/ 30 октября 2011

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

В JavaScript this полностью устанавливается как функция вызывается ( на данный момент ; подробности см. Ниже под сгибом), а не , где функция определен , как и в некоторых других языках, имеющих такое же ключевое слово (Java, C ++, C #, ...).

Вы, кодер, определяете, каким будет this каждый раз, когда вы вызываете функцию. Есть два основных способа: вызвать функцию через свойство объекта (в том же выражении) или явно использовать встроенные в функцию функции call и apply.

через свойство объекта

Использование свойства объекта:

obj.foo();    // or
obj["foo"](); // both work

Это делает две совершенно разные вещи, но которые совместно устанавливают значение this: во-первых, ссылка на функцию определяется путем поиска свойства foo объекта obj. Затем функция вызывается. Поскольку вы вызывали его как часть того же общего выражения, извлекающего значение свойства, механизм JavaScript установит this в obj в вызове.

Таким образом, в вашем примере test.parseText.load() в вызове load this будет parseText, а не test, потому что это объект, на котором был найден load.

Обратите внимание, что настройка- this -via-property-lookup работает только тогда, когда они выполняются одновременно. Это не работает:

var f = obj.foo;
f(); // `this` will not be `obj` within the call

Это не работает, потому что они не были сделаны одновременно. Поиск свойства и вызов функции были разделены.

Использование call или apply

Второй способ установки this является более явным: все функции имеют свойства call и apply, которые сами являются ссылками на функции, которые вызывают функцию, используя предоставленную вами информацию. В обоих случаях первый аргумент - это объект, который будет использоваться как this во время вызова. Поэтому, если мы хотим исправить приведенный выше пример, который не работает, мы можем сделать это:

var f = obj.foo;
f.call(obj);  // `this` will be `obj` within the call
f.apply(obj); // same

Единственная разница между call и apply заключается в том, как вы задаете аргументы функции. С call вы предоставляете их как дополнительные дискретные аргументы функции; с apply вы передаете массив аргументов.

Так что все они делают одно и то же:

// 1 - Directly via property
obj.foo("a", "b", "c");

// 2 - Using `call`
f = obj.foo;
f.call(obj, "a", "b", "c");

// 3 - Using `apply`
f = obj.foo;
f.apply(obj, ["a", "b", "c"]); // Note the `[ ... ]`, one array with three elements

Вы можете увидеть, как call и apply могут работать с вашей существующей структурой:

test.parseText.load.call(test.parseText);

Это вызывает test.parseText.load, делая this = test.parseText внутри звонка.

Что Эрик сделал в своем ответе, так это использовал закрытие, чтобы вам было проще звонить parseText с ожидаемым значением this.

Дальнейшее чтение (раскрытие: из моего блога):


Наверху я сказал:

В JavaScript this полностью устанавливается как функция вызывается ( на данный момент ...

Причина, по которой я сказал «пока», заключается в том, что в ES6 JavaScript получает «функции стрелок», и в отличие от других функций, значение this внутри функции стрелок задается там, где они созданы , не как они называются: они получают this из контекста, где вы их создаете.

Предположим, вы писали код в объектном методе и хотели использовать другой метод объекта для, я не знаю, вывода информации из массива (да, это надумано). В ES5 вы, вероятно, сделали бы это:

this.output("Entries:");
theArray.forEach(function(entry, index) {
    this.output(index + ": " + entry);
}, this);
// ^------- tells `forEach` what to use as `this` during the callback

Если вы пропустите аргумент, у вас будет ошибка:

this.output("Entries:");
theArray.forEach(function(entry, index) {
    this.output(index + ": " + entry); // <== Bug, `this` is either
                                       // `undefined` (strict) or
                                       // the global object (loose)
});

Но поскольку функции-стрелки наследуют this от того места, где они были созданы, а не получают его в зависимости от того, как они вызваны, версия функции-стрелки, для которой не требуется второй аргумент:

this.output("Entries:");
theArray.forEach((entry, index) => {
  this.output(index + ": " + entry);
});
7 голосов
/ 30 октября 2011

Если все, что вас беспокоит, это test изменение, сделайте это так:

var test = (function() {
    var object = {}
    object.call = function() {
        this.stop(); // works
    };
    object.stop = function() {
        this.parseText(); // apparently works, even though parseText is not a function
    };
    object.parseText = {
        load: function() {
            object.call(); // works
        }
    };
    return object;
})();
5 голосов
/ 30 октября 2011

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

Обратите внимание, что testне ссылка на функцию, а возвращаемое значение анонимной функции. Поскольку имя объекта (obj) заключено в функцию, его нельзя прочитать или изменить извне

Решение, приведенное ниже, является аккуратным, не загрязняет область действия testи работает как шарм.Как упоминалось ранее, test относится к тому же объекту, что и obj.Однако невозможно манипулировать переменной obj извне, так что код внутри функции ломается.

var test = (function(){ //Self-executing function
    var obj = {
        call: function() {
            this.stop(); // works
        },
        stop: function() {
            this.parseText(); // works
        },
        parseText: {
            load: function ()
            {
                obj.call();  // obj refers to the main object
            }
        }
    };
    return obj; //Return the object, which is assigned to `test`.
})(); //Invoke function

Обновление

Невозможно надежно сослаться на self,this или любая ссылка на объект внутри объекта, без переноса.

Ваше текущее решение не работает , см. Комментарии в коде ниже:

var obj = {
   init: function(){
      var instance = this; //`instance` is declared using `var` inside a function
   },                       // This variable cannot read from "the outside"
   parseText: {
      load: function(){
          instance.call(); //Does NOT work! instance is not defined
      }
   }
}
0 голосов
/ 30 октября 2011

" call " на самом деле является встроенной функцией объекта функции, которую можно использовать для вызова функции, определяющей, что использовать для этого. Как работает ваш код? Кажется, что это не так, поскольку parseText не является функцией ...

Может быть, попробовать это:

parseText: function() {
    var load =  function ()
    {
        this.call(); //*** should work
    };
    load.call(this);
}
...