этот объект не может быть доступен в частных функциях JavaScript без взлома? - PullRequest
6 голосов
/ 18 июля 2010

Я некоторое время работал над проектом, пытаясь выяснить, что я делаю неправильно, когда я наконец сузил «ошибку» до того факта, что приведенный ниже код не работает так, как я ожидал:

function Alpha()
    {
    this.onion = 'onion';

    function Beta()
        {
        alert(this.onion);
        }

    Beta();
    }

alpha1 = new Alpha();
// Alerts 'undefined'

Однако, если я изменю код на это:

function Alpha()
    {
    var self = this;
    this.onion = 'onion';

    function Beta()
        {
        alert(self.onion);
        }

    Beta();
    }

alpha1 = new Alpha();
// Alerts 'onion'

это работает так, как я и ожидал. Потратив большую часть своей жизни, кто-нибудь может объяснить, почему это так работает?

Ответы [ 3 ]

10 голосов
/ 18 июля 2010

Работает так, потому что каждая функция имеет свой собственный контекст выполнения .

Однако есть и другие способы сделать это, например:

Использование call или apply для вызова функции:

function Alpha() {
  this.onion = 'onion';

  function Beta() {
    alert(this.onion);
  }

  Beta.call(this);
}

var alpha1 = new Alpha();
// Alerts 'onion'

В новом стандарте ECMAScript 5-го издания представлен способ сохранения функции context , метод Function.prototype.bind:

function Alpha() {
  this.onion = 'onion';

  var Beta = function () {
    alert(this.onion);
  }.bind(this);

  Beta();
}

var alpha1 = new Alpha();
// Alerts 'onion'

Можно сказать, что функция Beta ограничена , и как бы вы ее ни вызывали, ееЗначение this останется неизменным.

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

Теперь позвольте мне подробнее рассказать о том, как работает this:

Значение this существует в каждом контексте выполнения , и для кода функции устанавливается неявно, когда выполняется вызов функциизначение определяется в зависимости от того, как ссылка , если сформирована.

В вашемНапример, когда вы вызываете Beta();, поскольку он не привязан ни к какому объекту, мы можем сказать, что ссылка не имеет базового объекта , тогда значение this будет ссылаться на глобальный объект.

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

var obj = {
  foo: function () { return this === obj;}
};
obj.foo(); // true

Как видите, вызываемая ссылка obj.bar(); содержит базуобъект, который равен obj, и значение this внутри вызванной функции будет ссылаться на него.

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

Третий случай, когда значение this устанавливается неявно, это когда вы используете оператор new, онбудет ссылаться на вновь созданный объект, который наследуется от прототипа его конструктора:

function Foo () {
  return this; // `this` is implicitly returned when a function is called 
}              // with `new`, this line is included only to make it obvious

var foo = new Foo();
foo instanceof Foo; // true
Foo.prototype.isPrototypeOf(foo); // true
7 голосов
/ 18 июля 2010

С JavaScript: Полное руководство, 5-е издание (книга носорогов):

Когда функция вызывается как функция, а не как метод, this ключевое слово относится к глобальному объект. Смущает, это правда, даже когда вызывается вложенная функция (как функция) внутри содержащего метода который был вызван как метод: this Ключевое слово имеет одно значение в содержащий функцию, но (нелогично) относится к глобальный объект в теле вложенная функция.

Обратите внимание, что this - это ключевое слово, а не имя переменной или свойства. JavaScript синтаксис не позволяет назначать значение до this.

Здесь следует обратить внимание на две вещи:

  1. this не является переменной, поэтому обычные правила захвата замыканий не применяются.
  2. this - это «отскок» при каждом вызове функции, будь то метод, обычный вызов функции или new. Поскольку вы выполняете обычный вызов функции (при вызове Beta), this привязывается к «глобальному объекту».
2 голосов
/ 18 июля 2010

Когда вы вызываете функцию, не являющуюся членом (не вызывается как someObject.method()), она запускается в контексте окна. Неважно, приватная ли это функция или глобальная.

Вы можете сделать:

Beta.call(this);

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

Однако мне неясно (даже для тривиального примера), почему лук является общедоступным, а бета - частным.

...