Почему «это» разрешение настолько особенное в JavaScript? - PullRequest
5 голосов
/ 14 июня 2011

Предупреждение: сначала глючит код JavaScript!

// 1: buggy counter
// -----------------
// problem: 'this' can be "broken"
var Counter1 = function() {
    this.count = 0;
    this.increment = function() {
        function increment_helper(){
            ++this.count; // this refers to window (global), not to the object that Counter1 was called with
        }
        increment_helper();
    }
    this.reset = function() { this.count = 0; }
    this.get_count = function() { return this.count; }
}

var counter1 = new Counter1();
counter1.increment();
document.writeln("<p> 1: " + counter1.get_count() + "</p>");

Как видно, this в increment_helper скорее относится к глобальной области (или к области window, если быть точным, ЕСЛИЯ правильно понял) вместо того, чтобы ссылаться на это закрывающего закрытия.Таким образом, вывод будет:

0

вместо

1

I 'Я перечислю лучшее (все еще не идеальное, но все в порядке) решение, а затем задам основной вопрос.Итак, решение (IMHO) можно отсортировать так:

// 2: better counter
// -----------------
// solved: 'that' can't be "broken"
var Counter2 = function() {
    var that = this;
    that.count = 0;
    that.increment = function() {
        function increment_helper(){
            ++that.count; // that refers right to the object the Counter1 was called with
        }
        increment_helper();
    }
    that.reset = function() { that.count = 0; }
    that.get_count = function() { return that.count; }
}

var counter2 = new Counter2();
counter2.increment();
document.writeln("<p> 2: " + counter2.get_count() + "</p>");

Итак, главный вопрос: почему this особенный, как никто другой в JavaScript?Почему только this и для какой цели?

Большое спасибо!

Обновление: После @ комментария Джордана ниже (где он объяснил разницу между относительные переменные вроде this и переменные области действия как обычные), перефразируя мои вопросы:

A: Каково общее обоснование относительных переменных?

B: почему this является единственной относительной переменной в JavaScript?Любое обоснование того, почему относительная / ограниченная концепция может (исключительно) применяться к каждой переменной?

Ответы [ 3 ]

2 голосов
/ 14 июня 2011

Эта статья даст вам глубокое понимание того, как "это" работает в javascript.

2 голосов
/ 14 июня 2011

A.В JavaScript, в отличие от других С-подобных ОО-языков, функции являются объектами первого класса.Вы можете копировать функции, передавать их в другие функции, возвращать их из функций, создавать новые.Функции не подобны методам в Java или C #, которые постоянно прикреплены к объявлению класса.Это означает, что this должно быть относительно самой функции и того, как она была вызвана.В противном случае это не имеет смысла.

В качестве глупого примера:

var o = {
  name: "My name is o",
  foo: function () { alert(this.name); }
};

var p = {
  name: "My name is p",
};

p.foo = o.foo;
p.foo(); // "My name is p"

Это невозможно сделать на других языках типа OO C, но это можно сделать в JavaScript.Следовательно, this должно быть относительным.Да, это вызывает проблемы, но язык становится невероятно выразительным.

B.arguments также относительно.

1 голос
/ 14 июня 2011

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

Исторически сложилось так, что причина this определяется так, как она есть, потому что это настолько близко, насколько это возможно, чтобы дизайнеры подражали смыслу, который он имеет в Java.

Также рассмотрим, что происходит, когда вы пишете ближайший эквивалентный код на Java:

class Foo {
    int count = 0;
    IncrementHelper helper = new IncrementHelper() {
        public void increment() {
            ++this.count; // doesn't compile
        }
    }

    public void increment() { helper.increment(); }
    public void reset() { this.count = 0; }
    public int getCount() { return this.count; }
}

Указанная строка даже не компилируется (вы должны сказать ++Foo.this.count), потому что во внутреннем классе this не является экземпляром Foo.

...