0,0
рейтинг
13 августа 2012 в 23:22

Разработка → Ключевое слово this в javascript — учимся определять контекст на практике tutorial

По просьбам некоторых читателей решил написать топик про контекст в javascript. Новички javascript часто не понимают значение ключевого слова this в javascript. Данный топик будет интересен не только новичкам, а также тем, кто просто хочет освежить данный аспект в памяти. Посмотрите пример ниже. Если вы затрудняетесь ответить на вопрос «что будет выведено в логе» хотя бы в одном из пунктов или хотите просто посмотреть ответы — добро пожаловать под кат.

var f = function() {
    this.x = 5;
    (function() {
        this.x = 3;
    })();
    console.log(this.x);
};

var obj = {x: 4, m: function() {
    console.log(this.x);
}};


f();
new f();
obj.m();
new obj.m();
f.call(f);
obj.m.call(f);


Ответы, для нетерпеливых
3
5
4
undefined
5
5


1. Теория


В отличие от многих других языков программирования ключевое слово this в javascript не привязывается к объекту, а зависит от контекста вызова. Для упрощения понимания будем рассматривать примеры применительно к браузеру, где глобальным объектом является window.

1.1. Простой вызов функции

function f() {
    console.log(this === window); // true
}
f();


В данном случае this внутри функции f равен глобальному объекту (например, в браузере это window, в Node.js — global).

Самовызывающиеся функции (self-invoking) работают по точно такому же принципу.

(function () {
    console.log(this === window); // true
})();


1.2. В конструкторе

function f() {
    this.x = 5;
    console.log(this === window); // false
}
var o = new f();
console.log(o.x === 5); // true


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

1.3. В методе объекта

var o = {
    f: function() {
        return this;
    }
}
console.log(o.f() === o); // true


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

var o = {
    f: function() {
        return this;
    }
}
var o2 = {f: o.f};
console.log(o.f() === o);//true
console.log(o2.f() === o2);//true


1.4. Методы apply, call

Методы apply и call позволяют задать контекст для выполняемой функции. Разница между apply и call — только в способе передачи параметров в функцию. Первый параметр обеих функций определяет контекст выполнения функции (то, чему будет равен this).

Разница в apply/call
function f(a,b,c) {
    return a * b + c;
}
f.call(f, 1, 2, 3); // аргументы перечисляются через запятую;
var args = [1,2,3];
f.apply(f, args); // // аргументы передаются в виде массива;
// В обоих случаях вызовется функция <b>f</b> с аргументами a = 1, b = 2, c = 3;



Примеры:

function f() {
}
f.call(window); // this внутри функции f будет ссылаться на объект window
f.call(f); //this внутри f будет ссылаться на f


Похитрее:

function f() {
    console.log(this.toString()); // 123
}
f.call(123); // this внутри функции f будет ссылаться на объект Number со значением 123


2. Разбираем задачу


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

2.1. f()

var f = function() {
    // Функция f вызывается с помощью простого вызова - f(),
    // поэтому this ссылается на глобальный объект
    this.x = 5; // window.x = 5;
    
    // В пункте 1.1 также указано, что в самовызывающихся функциях this также ссылается на глобальный объект
    (function() {
        this.x = 3;  // window.x = 3
    })();
    console.log(this.x); // console.log(window.x)
};


Результат: 3

2.2. new f();

var f = function() {
    // Функция f вызывается с использованием ключевого слова new,
    // поэтому this ссылается на создаваемый объект (обозначим его как object)
    this.x = 5; // object.x = 5;
    
    // В пункте 1.1 также указано, что в самовызывающихся функциях this ссылается на глобальный объект
    (function() {
        this.x = 3;  // window.x = 3
    })();
    console.log(this.x); // console.log(object.x)
};

Результат: 5

2.3. obj.m();

var obj = {x: 4, 
    m: function() {
        // из пункта 1.3 следует, что this === obj,
        console.log(this.x); // console.log(obj.x)
    }
};

Результат: 4

2.4. new obj.m();

var obj = {x: 4, 
    m: function() {
        // из пункта 1.2 следует, что this ссылается на вновь создаваемый объект
        // но внутри данной функции не устанавливается значение для this.x, поэтому результат - undefined
        console.log(this.x);
    }
};


Результат: undefined

2.5. f.call(f);

var f = function() {
    // Функция f вызывается с помощью метода call
    // первым параметром в call указана сама функция (точнее объект) f, поэтому
    // поэтому this ссылается на f
    this.x = 5; // f.x = 5;
    
    // В пункте 1.1 также указано, что в самовызывающихся функциях this ссылается на глобальный объект
    (function() {
        this.x = 3;  // window.x = 3
    })();
    console.log(this.x); // console.log(f.x)
};

Результат: 5

2.6. obj.m.call(f);

var obj = {x: 4, 
    m: function() {
        // функция вызвана с помощью метода call
        // первым аргументом указана функция f
        // поэтому this вновь ссылается на f
        // в предыдущем примере f.x было присвоено значение 5, поэтому результат 5
        console.log(this.x); // console.log(f.x)
    }
};


Результат: 5

Внимание: Если данный пример рассматривать отдельно от остальных, то в логе будет не 5, а undefined. Попробуйте внимательно разобрать пример и объяснить поведение
var f = function() {
    this.x = 5;
     (function() {
        this.x = 3;
    })();
    console.log(this.x);
};

var obj = {x: 4, m: function() {
    console.log(this.x);
}};


obj.m.call(f);


Вместо заключения


Ответы все вместе
3
5
4
undefined
5
5


В статье я постарался описать, как работает ключевое слово this в javascript. В ближайшее время я скорее всего напишу статью, в которой описывается для чего нужно знать эти тонкости (например, jQuery.proxy)

P.S. Если вы заметили ошибки/неточности или хотите что-то уточнить/добавить — напишите в ЛС, поправлю.
Хайрулин Василий @Sirian
карма
85,7
рейтинг 0,0
Разработчик
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (121)

  • +1
    Добавлю небольшой комментарий с точки зрения ui-разработчика на довольно сложном проекте на extjs: за неочевидные фокусы с this нужно бить, бить, бить по рукам!
    • +1
      Не надо никого бить. Используйте this в конструкторах, и будет вам счастье.
      • +1
        Прибавлю к этому совет использовать самовызывающийся конструктор Джона Резига, а не то кто-нибудь непременно вызовет конструктор в качестве простой функции, и из этого не выйдет никакого добра.
        • 0
          Позволю с Вами не согласится.
          Не стоит потакать забывчивости разработчиков.

          Такой код
          (function(){
          "use strict";
          
          /** @constructor */
          function test(){ this.lol = 1 };
          
          test();
          })()
          

          Вывалится со вполне понятной и правильной ошибкой
          TypeError: Cannot set property 'lol' of undefined
          или
          TypeError: this is undefined
          , или
          Unhandled Error: Cannot convert 'this' to object

          Конечно для тех проектов, где невозможно использовать strict mode, самовызывающийся конструктор Джона Резига хорошее решение. Но я просто хочу сказать, что это не является панацеей и я бы не сказал, что это best practics.
          • 0
            Идея оператора new мне кажется лишней. В чем его смысловая нагрузка? В том, что мы возвращаем объект? Ну вот, пожалуйста, тоже возвращаем объект: function Lol() { return $('.lol'); }

            Поэтому непонятно, почему перед одними функциями нужно писать new, а перед другими нет. Конструктор Резига позволяет убрать это различие. Дело не в забывчивости, а в том, чтобы быть последовательным.

            Сам я подолжаю писать new, потому что лень добавлять по несколько строк в каждый конструктор.
            • 0
              Идея и смысловая нагрузка оператора new в том, что он возвращает новый объект. Принято что функции, названные с Заглавной буквы следует вызывать только с оператором new. А иначе (при вызове без new), я советую генерировать ошибку, и не поощерять незнание начинающих программистов.
              • 0
                JavaScript Core с вами не совсем согласен:
                console.log( new Number(42) );
                console.log(     Number(13) );
                
                • +3
                  да нет, new Number возвращает объект-обертку, а Number — native значение:
                  console.log(typeof new Number(42) );//object
                  console.log(typeof     Number(13) );//number
                  
                  • 0
                    Именно. Но не ошибку ;)
                  • 0
                    console.log(new Array() instanceof Array); // true
                    console.log(Array() instanceof Array);     // true
                    
                  • 0
                    console.log(!!(    Boolean(false))); //false
                    console.log(!!(new Boolean(false))); //true
                    

            • 0
              Смысловая нагрузка new в том, что функция возвращает новый экземпляр класса. Тк, пока что, в js нету классов, это единственная возможность отделить функции-конструкторы, от других функцию.
              • 0
                Спасибо, логично.
            • 0
              В Ecmascript 3, оператор 'new' это единственный способ создать объект, прототип которого мы можем контролировать через свойство функции(конструктора) 'prototype'. Т.е. в этом случае функция ведет себя именно как конструктор, а не как кусок кода, который возвращает произвольный объект(хотя такая возможность тоже есть).
          • 0
            А если использовать «typeof this»:
            var Vector = function(x, y, z) {
            	if (typeof this === "undefined") {
            		return new Vector(x, y, z);
            	}
            	this.__x = x;
            	this.__y = y;
            	this.__z = z;
            };
            
            • 0
              Неа. this будет указывать на window.
              • 0
                Ну это если не strict-режим :)
            • +1
              Вообще сама идея самовызывающегося конструктора порочна и выше я описал почему.
              • +1
                В чём-то вы правы. Но, к примеру, в Питоне new не надо писать и никто не страдает :)
                • 0
                  Вот! Доказательство.
                  • 0
                    Доказательство чего? Я например пишу new и не страдаю, это тоже доказательство? :)
                • +1
                  Я начал изучать JS после C++, поэтому по-привычке использую new для создания новых экземпляров «класса».
                  Конечно это дело привычки, но рекомендовать самовызывающейся конструктор в качестве best practic это слишком.
              • 0
                Вообще лично я для объектов которые подразумеваются как «неизменяемые» пишу конструкторы без new, а для изменяемых — с new. В том же примере сверху — Vector — как раз «неизменяемый».
    • +2
      Бить надо плохих фокусников, которые комментариев не пишут.
      • 0
        Не надо комментариев — они быстро устаревают.
        Лучше называть сущности говорящими именами.
        • 0
          Комменты все-таки надо. Сущности с говорящими именами тоже.
  • +5
    Неплохой пост, но если уж заговорили про контекст, то и про лексическую область видимости функций было бы неплохо рассказать тут же.
    Например что будет в таком примере и почему:

    var y = 5;
    var x = function(){
        return y;
    };
    var z = function(t){
        var y = 10;
        return t();
    }
    z(x);
    
    • –6
      Хорошая задачка для проведения собеседований.
      • +2
        за такие задачки на собеседованиях нужно одно место отрывать.
        я хоть ответ то и знаю, но когда устраиваешься на работу — волнуешься и на собеседовании точно бы всякую околесицу нес бы.
        • +1
          Я лично никого не собеседую, но ваших аргументов не понимаю. Пример то очень простой. Напишу-ка я маленький топик с разбором этого примера…
        • –2
          А по вашему от кандидата требуются только красивые глазки?

          Если на собеседовании человек, не смотря на волнение, отвечает на все вопросы, он стоит больших денег и его надо брать.

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

          А задачка действительно не сложная, но на внимательность.
          • 0
            «Задачка на внимательность, когда человек волнуется».
            Дальше сами 2 + 2 сложите?
            • 0
              Я не понял смысл этого комментария.
        • +1
          Пример то простейший. Зовём z и передаём в аргумент x. Та возвращает результат выполнения функции, которая пришла в параметре, т.е. результат x. Смотрим что возвращает функция x — 5. Для вакансии где нужно не jQuery плугины цеплять, а настоящий js — вполне ок задача.
          • 0
            В спокойных условиях я написал Singleton на JS за минут 5.
            На собеседовании же, у меня все в голове перемешалось. И банальный миксин через call не смог написать.
            ок?
            • 0
              вне контекста, немного глуповато звучит.
              суть в том, что никогда до этого момента не сталкивался с задачей Singleton в JS и решил реализовать паттерн сам.
            • +1
              На собеседовании же, у меня все в голове перемешалось. И банальный миксин через call не смог написать.

              Значит, ещё плаваете в языке. Это тоже показатель.
              Русский язык на собеседованиях не забываете ведь?
              • –1
                Забываю.

                А ваша оценка знаний просто потрясает.
                • 0
                  Ну если забываете, значить при любой выходящей за рамки ситуации не умеете держать себя в руках. Это тоже показатель.
                  Это ведь не какой-то выбивающий из колеи вопрос, обычный тест на знание основ JS. В школе каждую неделю подобные тесты писали.
                  • 0
                    значить при любой выходящей за рамки ситуации
                    Почему собеседование вылилось в «Любую за рамки выходящую ситуацию»?
                    Как это связано?
                    • 0
                      Я не могу понять. Если собеседование для вас — вполне обычная ситуация, почему вы на нём забываете русский язык и язык программирования? Пробовали обратиться к врачу?
                      • 0
                        Я могу сказать, что вы не волнуясь употребляете не верную терминологию.
                        Для меня это сродни забыванию Русского языка на собеседовании.

                        Этот пример затрагивает самые базовые понятия JS

                        Как пример может затрагивать базовые понятия?
                        Что вы подразумеваете под базовыми понятиями JS?
                        • 0
                          Демагог Вы наш, не цепляйтесь к словам. "Концентрация на частностях" — отвратительный приём.

                          Без глубокого понимания областей видимости не получится писать на JS серьёзные приложения. На такую задачу не сможет ответить или новичёк или человек, который вообще не может держать себя в руках. И тем и другим надо ещё учиться и рано устраиваться на работу по такой специальности.
                          • –1
                            Вы сами затронули тему про Русский язык.
                            Я ответил конкретно на ваш вопрос, может будете логичным?

                            Немного разверну ответ, что бы не осталось недопонимания.
                            Я считаю, что от волнения на собеседованиях начинаю сильно путаться в терминологии. Если я называю вещи не своими именами, то на мой взгляд — это и есть «забывать Русский язык».

                            p.s.
                            Не в тему.
                            А вообще, когда разговор идет в русле специальности, то терминологию данной специальности нужно использовать правильную. Посетите химическую конференцию и начните объяснять кому нибудь формулу в формате: «Беру бутылку с зеленой водичкой и туда желтенькую...»
                        • 0
                          Вам правильно советуют, учитесь управлять эмоциями. Собеседование не самая страшная вещь в жизни, и надо уметь взвешенно принимать решения вместо того что бы отдаваться эмоциям с головой.
                          • +1
                            Вот этого никогда не понимал, как выглядит обучение управлению эмоциями?
            • +1
              Можете показать как сделать через mixin и call? Я себе синглтон так представлял:

              function Boob(size) {
                  if (Boob.instance) {
                      return Boob.instance;
                  }
                  Boob.instance = this;
                  this.size = size;
              }
              
              a = new Boob(3);
              b = new Boob(4);
              alert(a.size == b.size);
              
              • 0
                Не «через миксин», а «миксин через кол»
        • +1
          за такие задачки на собеседованиях нужно одно место отрывать.
          я хоть ответ то и знаю, но когда устраиваешься на работу — волнуешься и на собеседовании точно бы всякую околесицу нес бы.

          Вы категорически не правы. Этот пример затрагивает самые базовые понятия JS. В нём нету ничего сложного или такого, что должно на собеседовании сбить. Единственное, что — отвратительные имена переменных. Куча одинаковых букв, которые мельтешат перед глазами и путаются. Надо было бы хоть как-то так:
          var value = 5;
          
          function returnValue () {
              return value;
          }
          
          function applyCallback(callback) {
              var value = 10;
              return callback();
          }
          
          applyCallback( returnValue );
          
          • 0
            В том, что затрагивает базовые принципы JS соглашусь.
            Не соглашаюсь лишь с тем, что на собеседованиях нужны вопросы на внимательность. Т.к. собеседование само по себе стресс, при чем достаточно хороший.

            Естественно, я рассматриваю сейчас собеседование на должность web-разработчика, который хочет устроится на данную должность.
            Т.к. если человек приходит на собеседование ради того, что бы прийти на собеседование(есть такая практика), то у него не будет волнения. А рез у него нет волнения, то и человек не очень то заинтересован в работе и HR-менеджеру стоит насторожиться… но это уже пошло из другой оперы.
            • 0
              Это не вопрос на внимательность. Это вопрос на знание языка.
              Этот пример у Вам тоже кажется через-чур?

              do {
                  console.log(1);
              } while (false);
              while (0) {
                  console.log(2);
              }
              // Output = ?
              
              • 0
                Ну раз вы считаете что ваша аналогия сопоставима с исходной, тогда я тоже могу сказать, что раз уж мы хотим задачку на «знание» языка, то нужно составлять что-то типа:

                +function start() {
                	console.log(z(x(z)));
                }()
                function x(a) {
                  return new y(a);
                }
                function y(b) {
                  if (d === 5) { 
                	this.z = b({z:1});
                  } else if (d === undefined) {
                	return {z:b({z:2})};  
                  }
                  return x(z);
                }
                function z(n) {
                   return ([]+{}).split.constructor('return arguments[0]'+([]+{})[0]+'"z"'+([]+{})[14])(n);
                }
                var d = 5;
                
                • 0
                  Я бы не устроился туда где так пишут )))
                • 0
                  Я считаю области видимости элементарным понятием, как и знание операторов языка.

                  А товарищ Yan_Alex все правильно написал. Вы бы для приличия потестили свой код, перед тем, как выкладывать.

                  Да и читабельность отсутствует. Вы бы еще прогнали через обусфакторы прогнали код…
                  • 0
                    Я старался написать пример, в котором реализовано несколько «базовых», на мой взгляд, принципов JavaScript. Тут нет ничего, что не может знать хороший js-разработчик. Как говориться «Must Know».
                    Но однако, я считаю, что такое задание предлагать для соискателя — глупость. Вы со мной не согласитесь?

                    Писал в блокноте. За именования, извините, лень было придумывать более читабельные, однако изначальный пример изобиловал этими же литералами в качестве переменных.
                    Сейчас прогнал код в браузерах, все работает на ура — что вам не понравилось? -))

                    • 0
                      странно, а у меня «ReferenceError: z is not defined»
                      • 0
                        Какой браузер?
                      • 0
                        Попробывал в Fx в Firebug, действительно ошибка.
                        Открыл в нем же jsfiddle.net, заменил d примере console.log на document.write и запустил. Все прошло на ура.

                        Ищите проблему в firebug.
                        • 0
                          Действительно.
                          Firebug не понимает hoisting функций.
                          Так что, похоже, со стандартами он не сильно дружит.
            • 0
              Не соглашаюсь лишь с тем, что на собеседованиях нужны вопросы на внимательность

              Зачем вы придумали, что я говорил о том, что нужны вопросы на внимательность? Опять демагогия. Зачем эта "Подмена тезиса"?
              Я наоборот сказал, что отвратительные имена переменных в примере. Их стоит заменить на более читабельные, чтобы задача свелась исключительно к понимаю областей видимости, а не внимательному изучению, какая буква что означает.
              • 0
                Как я мог что-то подменить, если я не спорил с вами?
                Извиняюсь, если я не верно выразил свою мысль.
                Фраза:
                Не соглашаюсь лишь с тем, что на собеседованиях нужны вопросы на внимательность.

                Относилась к исходному примеру и комментарию kolyuchii
            • 0
              Вы не правы. Далеко не все люди на собеседованиях волнуются, а многие если и волнуются, не дадут вам ни единого шанса понять это. К тому же подобные задачи даются обычно не для того что бы просто получить ответ, а для того что бы проследить ход рассуждений испытуемого. Если собеседование проводит грамотный специалист, решение может быть положительным, даже если ответ на вопрос (вопросы) неверный, но ход рассуждения верен.
              • –1
                Далеко не все люди на собеседованиях волнуются

                Соглашусь полностью. Но я подразумеваю лишь тех людей, кто заинтересован в устройстве «к нам». Если человек заинтересован, то он волнуется. В обратное, без предоставление опровергающих фактов, извините, не поверю.
                • +1
                  Все волнуются. Да. Но это никак не влияет на знания и способность вспоминать. Если кандидат крепок в знаниях, волнение почти не сказывается на его способности давать верные ответы.

                  Всё остальное — оправдание.
                  • –3
                    Кроме ваших слов, есть какие либо подтверждения?
                    Исследования?
                  • –3
                    А то, знаете, в соревнованиях по стрельбе, например, волнение одна из самых больших помех.
                    • +1
                      В соревновании по стрельбе волнуются все, но побеждает тот, кто может справиться с волнением, а не тот, кто просит не давать ему сложных заданий.
                      • –1
                        а не тот, кто просит не давать ему сложных заданий.

                        как вот сие воспринимать в контексте всей беседы?
                        Никаких доказательств нет.
                        Лишь словоблудие да передергивание.
                        • 0
                          В соревнованиях по стрельбе все в равных условиях. Следовательно есть два фактора, которые определяют лучшего стрелка (кроме исключений типа сломанного ружья и вчерашней пьянки) — это навык и умение справится с волнением.
                          • –2
                            Отлично, вы подтвердили мои слова, что волнение сказывается на результате.
                            • 0
                              Странный вы. Я давно говорил об этом. И на каких-то очень сложных задачах это может быть заметно. Я и сам когда очень волнуюсь могу не сделать какую-то очень сложную и запутанную фигню. Например, когда за 5 минут надо баг закрыть — могу глупостей написать.

                              А если человек с 10-ти метров не может попасть в мишень диаметром три метра из-за волнения — это плохой стрелок и значит ему надо или ещё тренироваться в стрельбе или справляться с излишним волнением.

                              Об этом я тоже говорил:

                              На такую задачу не сможет ответить или новичёк или человек, который вообще не может держать себя в руках. И тем и другим надо ещё учиться и рано устраиваться на работу по такой специальности.


                              А задача как раз из примитивных, ничего сложного. Самые основы.
                              • 0
                                Дамс, это вы странный. Может будем последовательными?
                                Открываем ветку беседы. (кнопка над каждым комментарием в виде раздвоенных стрелочек)
                                Читаем.

                                Доходим до комментария:
                                Все волнуются. Да. Но это никак не влияет на знания и способность вспоминать. Если кандидат крепок в знаниях, волнение почти не сказывается на его способности давать верные ответы.

                                Далее я отвечаю про то что волнение сказывается и не согласен с автором.

                                Затем вы подтверждаете мои слова:
                                В соревнованиях по стрельбе все в равных условиях. Следовательно есть два фактора, которые определяют лучшего стрелка (кроме исключений типа сломанного ружья и вчерашней пьянки) — это навык и умение справится с волнением.


                                И в конце концов вы отвечаете мне же, как будто спорите со мной дальше по поводу волнения и влияние их на возможности человека. Зачем? Почему?
                                Вы хотите поговорить о степени влияния волнения на способности?
                                Мне кажется, мы с вами не достаточно квалифицированны, что бы обсуждать это, но на мой взгляд, она сугубо индивидуальна и разница от человека к человеку.

                                Если все же, вы никак не можете отойти от темы с примером, то она у нас с вами раскрыта тут
                                • 0
                                  Вы придумали мне непоследовательность.
                                  Волнение сказывается только на пределе возможностей. Если человек попадает со ста метров прибилизительно в десятку, то как бы он не волновался с 10-ти метров в 10-ку он должен попасть.
                                  Если не может — значит он совершенно не контролирует свои эмоции.
                                  Или плохо стреляет.
                                  И в первом и во втором случае на соревнования его брать нельзя. И на работу. Я говорю об этом уже в пятый раз, а вы мне придумываете какой-то другой смысл слов.
                                  • 0
                                    Я не придумал.
                                    Вся логика не последовательности указана цитатами.

                                    Вы не указали степень волнения для того что бы человек попал в 10ку. Поставим монетку на голову дочери стрелка и посмотрим как он справится с задачкой.

                                    А ваше без апелляционное заключение вообще появляется из воздуха. Почему нельзя? С чего вы так решили и т.д.
                                    • +1
                                      Вы зануда. Контролировать свои эмоции важно, потому что в критической ситуации нужно думать как эту критическую ситуацию решить, а не о том как вам страшно.
                                      • –1
                                        Часто вы писали софт под дулом пистолета?
                                        • 0
                                          Под дулом пистолета ни разу. Но критические случае были.

                                          Например, однажды некие умельцы со стороны заказчика перенастроили сервер авторизации стоящий перед нашим софтом, а нас об этом предупредить забыли. Произошло это в разгар рабочего дня. Соответственно наш софт начал выдать всем подряд 403 (на мы то тогда еще не знали в чем причина). Так вот были люди которые бегали и истерили что всех уволят, а были люди которые методично анализировали проблему, искали ее источник и решали ее.

                                          И кстати, если уж на то пошло, вы что проходите собеседование под дулом пистолета? Относитесь к этому проще и у вас все получится.
                                          • 0
                                            там куда я не хочу попасть, я чувствую себя свободно.
                                            а там, куда стремлюсь — увы. как под дулом.
                                        • 0
                                          > Часто вы писали софт под дулом пистолета?
                                          Часто вы проходили собеседование под дулом пистолета?
    • +3
      Собственно топик на эту тему.
    • +1
      Похожий пример, с объяснением dmitrysoshnikov.com/ecmascript/ru-chapter-4-scope-chain/#zamyikaniya
  • +1
    Большое спасибо за статью. Все просто и хорошо объяснено.
    Думаю, что начинающим разработчикам она особенно полезна. На работе разошлю ссылку молодым коллегам.
  • +4
    Недавно в какой-то либе встретил интересный прием заполнения свойств объекта:

    return {
        // ... some properties,
        params: new function() {
            var pairs = url.search.slice(1).split('&');
            for (var i = 0; i < pairs.length; i++) {
                var pair = pairs[i].split('=');
                this[pair[0] || ''] = pair[1] || '';
            }
        }
    }
    

    'this[...] =' заполняет свойства объекта, созданного через new function. Более явно это можно было бы записать так:

        params: new function() {
            var pairs = url.search.slice(1).split('&'),
                result = {};
            
            for (var i = 0; i < pairs.length; i++) {
                var pair = pairs[i].split('=');
                result[pair[0] || ''] = pair[1] || '';
            }
            return result;
        }
    
    • 0
      очень похоже на пример синглтона
      • 0
        Блин, ну почему люди везде видят синглтон-синглтон-синглтон? Это прям какое-то НЛО программирования.
        Ну где здесь синглтон? И чем оно может быть похоже на синглтон? Это просто функция, которая создаёт объект.
        • 0
          похожим образом создаются объекты, которые желательно иметь в одном экземпляре, например App.popupManager = new function(){this.open = function(url){...}; this.closeAll = function(){...};}
          Что плохого вы видите в том, что я заметил аналогию?
          • 0
            Так впринципе создаются объект. Сингтон можно создать так:
            App.popupManager = {
              open: function (url) { },
              closeAll: function () { }
            }
            

            Но говорить о том, что создание объектов через {} — это прям как сигнлтон — моветон.
            Синглтон — отвратительный паттерн. Отвратительный не своей идеей, а тем, как её испаскудили его фанаты, пихая его везде, где надо и не надо.
            • 0
              нет, не тоже самое. В вашем случае не получится выделить «приватные функции» через просто объявление function myPrivateFunction(){} внутри конструктора.

              Странно, я не говорил что синглтон плохой или хороший. К чему эти рассужения от чего и насколько он паскуден?
              • 0
                нет, не тоже самое. В вашем случае не получится выделить «приватные функции» через просто объявление function myPrivateFunction(){} внутри конструктора.

                (function () {
                  function myPrivateFunction () {}
                
                  App.popupManager = {
                    open: function (url) { },
                    closeAll: function () { }
                  }
                })();
                


                Я сказал, что упоминание синглтона к месту и не к месту уже вызывает рвотные рефлексы.

                Создаём экземпляр класса:
                function MyClass() {};
                var instance = new MyClass();
                

                О! Прям как синглтон! Там тоже используется название instance!
                • 0
                  Если бы я заметил сходство с композитом, вам было бы менее тошно?
                  • 0
                    Это было бы просто странно и непонятно.
                    Но вся прелесть в том, что вы заметили сходство именно с синглтоном.
                    • +1
                      Потому что я читаю книжку по паттернам в жс и меня удивило сколько там вариантов написать какой-то простой синглтон, да и еще и неочевидно, а тут какраз один в один пример
    • 0
      Изящно, однако.
      Сейчас пишу небольшой тул, подзадалбывает постоянно писать эти var res=[]; for (...) {...} return res;
      • +1
        Так reduce же
        "qwe=123&asdfg=333&fasks=333".slice(1).split('&').reduce(function(result, value, index, array){
           var pair = value.split('='); result[pair[0] || ""] = pair[1] || ""; return result
        }, {})
        
        • 0
          В IE9 еще не поддерживается
          • +1
            В любом IE можно добавить этот метод в прототип массива.
          • +1
            Поддерживается всеми браузерами (в том числе IE6+) с помощью polyfills раз, два или даже с MDN.

            В любом случае, это лучше, чем написание своей функции, которую кто-то когда-нибудь забудет подключить, или методом копипаста код её использующий попадёт в другой проект, где эта функция не подключена.

            А реализацию Array.prototype.reduce пожно подключить за минуту гугления
        • 0
          На мой взгляд, такой монстр это как-то многовато для простой инициализации.
          Хотя как вариант решения обсуждаемой задачи — отлично, кто ж спорит.
          • 0
            Монстр? Что Вы имеете в ввиду?
            Самое элегантное решение, для обсуждаемой задачи и целого класса других задач.
    • 0
      Ну вообще [квадратные скобки] это стандартный для js способ использовать объект как ассоциативный массив. this здесь просто имя объекта.
      obj.value = 42; //когда название поля известно статически
      var valueName = "value"; // но может и не быть известно
      obj[valueName] = 42; // эквивалентно obj.value = 42
      
  • +1
    В ближайшее время я скорее всего напишу статью, в которой описывается для чего нужно знать эти тонкости (например, jQuery.proxy)

    Вот это было бы очень интересно почитать!
  • 0
    > В отличие от многих других языков программирования ключевое слово this в javascript не привязывается к объекту, а зависит от контекста вызова.

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

    Там, где функциями жонглировать можно — выкручиваются по-разному. Скажем в C# this запаковывается вместе с указателем, но там тоже есть способы дергать нужный метод с произвольным this. В C++ указатель на метод и функцию — разные штуки.
    • 0
      дополню для с++, если метод не статический
  • 0
    eval?
  • +1
    Плюсую пост.
    Весьма наглядно изложено.
  • +1
    Очень круто написано. Даже уже все зная чертовски интересно читать.
  • 0
    В ближайшее время я скорее всего напишу статью, в которой описывается для чего нужно знать эти тонкости (например, jQuery.proxy)

    jQuery.proxy достаточно убогая реализация Function.prototype.bind. После знакомства с bind, забыл про $.proxy. Да и вообще, в ES5+ много красивых функций, которые заменяют убогие аналоги из jQuery.
    • +1
      да, я знаю. про Function.prototype.bind я как раз тоже укажу в статье
      • +2
        Круто.
        Я надеюсь, Вы осветите вот такой момент с Function.prototype.bind
        function classA(a) {
          console.log(this.lolcat, a)
        }
        classA.prototype.lolcat = "=^__^=";
        
        var classB = classA.bind({lolcat : "=°__°="}, "x");
        
        classB.prototype = {lolcat : "=o__0=" }
        
        new classA("A");//"=^__^=", A
        new classB("B");//"=^__^=", x а не "=°__°=", x
        

        а то, даже опытные разработчики не знают об этой особенности
        • 0
          Жесть, никогда бы не подумал. А в реальном коде такое где-нибудь используется?
          • 0
            Собственно, эта особенность прописана в стандарте (тут надо вчитываться, лучше смотреть на MDN), специально для того, чтобы использовать в реальном коде функции-конструкторы, полученные через bind.

            developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
            thisArg
            The value to be passed as the this parameter to the target function when the bound function is called. The value is ignored if the bound function is constructed using the new operator.


            Многие библиотеки эмулирующие es5, забывают об этой особенности.
            В моей библиотеке я это учёл.
            А вот патч для es5-shim
          • 0
            Жесть, никогда бы не подумал. А в реальном коде такое где-нибудь используется?

            Да, но редко. Вообще вполне логичное поведение.
            А чего «жесть» то?
            • 0
              Если рассматривать binding целиком, то жесть.
              Например, мы имеем какое то API и получаем из него функцию. О том какая она, мы не имеем представления.
              Запуская его от нашего объекта мы получаем неадекватные результаты:

              // Где то объявлено
              function myFunc(a) {
                this.a = a;
                return this;
              }
              var BoundedFunc = myFunc.bind({z: 30}, 10);
              
               ...
              //Попытаемся использовать
              var res = BoundedFunc.call({z: 40});
              console.log(res.z); // 30 - вот вообще не неожиданно
              


              Я бы сказал, что это нарушение единого интерфейса вызова функций языка. Feature очень не продуманная и вредная.
              • 0
                Странное мнение. Вообще-то по идее BoundedFunc — это функция с другим интерфейсом.

                var magnitudeOrder = Math.pow.bind( Math, 10 );
                
                magnitudeOrder(2); // 100
                magnitudeOrder(5); // 10000
                


                Мы видим, что magnitudeOrder — это функция с другими целями и другим интерфейсом. Кто сказал, что у неё должны быть те же аргументы, что и у функции-предка? Почитайте вообще про каррирование.

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

                var binded = function () {
                    console.log( this.x );
                }.bind({ x: 100 });
                


                Внутри неё я должен быть уверен, что при вызове она будет прибиндена к тому объекту, к которому я её прибиндил. Если бы это было не важно, то я бы её просто не биндил. А вот смысл метода "Function.prototype.bindIfGlobalContext" был бы сомнительным.
                • 0
                  Странное мнение. Вообще-то по идее BoundedFunc — это функция с другим интерфейсом.

                  Вы меня не правильно поняли. Я говорю про то, что результат при использование одного и того же интерфейса в языке будет приводить к в корне различным результатам.
                  Вот цитирую себя, что бы ещё раз акцентировать внимание на проблеме:
                  Например, мы имеем какое то API и получаем из него функцию. О том какая она, мы не имеем представления.

                  Теперь мы должны проверять, функцию которую нам вернули является «чистой» или «bounded».

                  Это как переопределение undefined. Благо в strict стандарте эту проблему устранили, и «вот-те здрасте», новые забавы.

                  p.s.
                  последний абзац ваш, увы, не понял -((
        • +1
          Описал тут: habrahabr.ru/post/149581/
  • 0
    Для jQuery хороший видеоурок по сабжу:
    tutsplus.com/lesson/the-this-keyword/
  • 0
    Я всё отгадал правильно :-)
    • 0
      отгадал или решил задачу? :)
      • 0
        Решил, конечно. Трудно было бы методом тыка =)
  • +2
    Не уж то забыли:

    void function() {
    	alert([this == 1, this === 1]); // [true, false]
    }.call(1);
    


    void function() {
    	'use strict';
    	alert([this == 1, this === 1]); // [true, true]
    }.call(1);
    

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.