Ключевое слово "this" в деталях
Ключевое слово this в javascript работает своеобразно, не так, как в других языках.
В отличие от PHP, Java, C++ и т.п, значение this в javascript не привязывается статически ни к какому объекту, а зависит от контекста вызова.
Разберем все 4 возможных случая.
Если функция вызывается через new как конструктор объекта, то this ставится на создаваемый объект:
function Animal(name) {
this.name = name
}
В результате получается объект, инициализированный конструктором, с заполненным свойством name .
Если функция запущена как свойство объекта, то в this будет ссылка на этот объект.
obj.func(параметры)
// или
obj['func'](параметры)
При этом совершенно неважно, откуда эта функция взялась. Важно лишь, какой перед func стоит объект.
Создадим два любых объекта:
vasya = {
name: "Василий"
}
dima = {
name: "Дмитрий"
}
Определим никак не связанную с ними функцию say :
say = function() {
alert("Привет, я "+this.name)
}
Присвоим функцию свойству sayHi для обоих объектов:
vasya.sayHi = say
dima.sayHi = say
И теперь тестовый запуск:
vasya.sayHi() // => "Привет, я Василий"
dima.sayHi() // => "Привет, я Дмитрий"
// или так
dima['sayHi']()
В обоих случаях запускается одна и та же функция say , которая получает в this объект до точки.
Функцию можно вызвать, используя методы call и apply .
func.apply(obj, [параметры])
func.call(obj, параметр)
При таком вызове this будет установлен в obj .
Оба метода работают одинаково, но для call аргументы подставляются в вызов, а для apply - передается массив.
function sum(a,b) {
this.c = a + b
}
var obj = {}
sum.call(obj, 1,2)
// или
sum.apply(obj, [1,2])
alert(obj.c) // => 3
Вызов через apply удобен тем, что можно самостоятельно сформировать массив аргументов или модифицировать существующий.
say()
При таком вызове this ставится равным глобальному объекту (в браузере это window ). Обычно, если функция использует this , то она не подразумевает запуск в таком виде, так что в 90% случаев такое значение this - результат ошибки в программе, глюк.
Если кратко срезюмировать все вышесказанное, то получится такая вот шпаргалка:
|
[a href="#" onclick="myFunction(this)"]
при таком вызове this будет указывать на [a] я так понимаю
Да
[a href="#" onclick="myFunction(this)"]
при таком вызове this будет указывать на [a] я так понимаю
А если [a href="javascript:myFunction(this);"]? У меня почему-то при таком вызове this ведет "на Марс".
Я тоже сталкивался с такой проблемой, href="javascript: func(this);" в this был window
Да, но вот переменная this внутри myFunction буде указывать на window
Допустим у нас есть такой набор функций
тогда как сделать чтобы внутри вызова
this указывало на объект полученный через $('id')?
Этот вопрос очень подробно разобран в статье про замыкания. Там в конце разобран пример, очень похожий на ваш.
По моему надо так:
Так в listener this точно тот obj, который получен внутри функции $()
а вообще у всех событий и так this это элемент на котором событие произошло... то есть и без apply this будет тоже самое что getElementById.
Заменить на
Спасибо.
Собственно проблема была только в ИЕ, изменил код следующим образом:
только теперь непонятно как реализовать detachEvent, может существует какойто другой способ?
Также как attach, только тот же обработчик события надо передать. А вообще - для работы с событиями кроссбраузерной существуют обвязки специальные.
думаю без ещё одного проверочного тэста -- не доконца всё ясно.
вот этого :
ато может показаться непонятно как себя поведёт this в случае с ЦЕПОЧКОЙ объектов ..
в результате приведёного примера -- появляется "I am A->B->C!!!" и затем "I am A->B!!" (но небыло ниразу "I am A!" , а также заметим что this не приклеивался к телу "функции" . а подставлялся динамически) ...
.. это значит что в приведёном случае -- this работает также как this и в C++ , PHP и определённых других языках.....
Данный код подтверждает, что this ведет как раз себя не так в PHP и С++.
"I am A!" и не выведется никогда, поскольку вы не запрашивали вывод сообщения с переменной из а
Разберемся с вашими тестами:
Будет выведено "I am A->B->C!!!", поскольку this ссылается на a.b.c.who
Вне зависимости от того, где описана ваша функция в этой случае this будет ссылаться на a.b.who
Так, что все верно. А чтобы вывелось "I am A!", необходимо
добавить строку:
Здравствуйте.
Подскажите плиз, как избавиться от переполнения стэка... Я головой понимаю, что что-то глупое делаю, но найти второй день не могу.
Аналог кода:
Чтобы вопросов лишних не было - int1 изменяется пользователем вне функции, функция считает время. Я понимаю, что там чего-то с кавычками делать, но: а) без кавычек, ессесно, недопустимый аргумент, б) с ними оверфлоу, в) единственное, как оно работает - это прописать setTimeout('obj.b();' 100);<...> т.е. ссылка напрямую на еще не созданный объект. Но это есть уродство , тем более хотелось бы универсальный объект. Выносить функцию вне объекта тоже не очень хочется.
Заранее спасибо)
Кавычки двойные ...("...",...) поставь... мож поможет...
Прошу прощения, уже нашел, здесь же, на сайте, так что все равно еще раз спасибо)) (сделал через
вар селф = зис;
сетТаймаут(функция () {селф.б()}, 100)
)
есть ява функция
к ней обращщается объект TABLE:
Но this все равно определяется,как window. Почему?
Это частая ошибка. this правильный в самом обработчике:
Если ты вызываешь функцию из него, то у нее будет свой this. Можно явно указать нужный this через
call
:[quote]При таком вызове this ставится равным глобальному объекту window.[/quote]
Есть тут, imho, две ошибки, причем первая по всей статье прослеживается.
1) Конечно хорошо быть лаконичным, но имеющуюся ввиду фразу "присваивает this указатель на ... " лучше не произносить как "this ставится на ...", что может у многих новичков (у меня в т.ч.) вызвать неверное понимание с точностью до наоборот (русский язык это позволяет) , как содержимое this кладется в ... Лучше лаконично говорить "this указывает на ..." или вот в случае выше "ставит на него this" - "направляет на него this"
2) this в этом случае уазывает на глобальный объект, но глобальный объект в разных реализациях ECMA script, который в народе называют Javascript не есть window, это тоже затеняет смысл, который заключается в следующем :
Первоначально у глобального объекта срели прочих могут быть свойства, значением которых является сам глобальный объект
Так в наиболее распространенных браузерных javascript - глобальный объект имеет одно из свойств window, которое указывает на глобальный объект. В JScript реализации ECMAScript'а в WSH, например нет вообще свойства window, там глобальный объект имеет среди прочих пару полезных свойств WScript и WSH, но это не глобальный объект. В ActiveScript реализации ECMA script - не знаю, есть ли свойство window и свойство , указывающее на глобальный объект.
PS. просто сейчас пытаюсь разобраться в некоторых связанных с this и контекстами вопросах, не всегда удается ...
Про глобальный объект добавил упоминание и поправил фразу про указатель.
Респект автору, достойная инфа по теме.
Спасибо за труд!
По-моему, этот код из примера надо исправить:
Параметр phrase лишний. Так же?
Ерунда, но для читабельности полезным будет.
Подскажите, пожалуйста, не могу понять, как мне получить в функции ссылку на объект?
Всё зависит от того, откуда эта функция вызывается. В данном случае она вызывается не как imgCorp.prototype.func(), а как obj.onclick() - соответственно this ссылается на obj.
Если очень надо, можно поменять конструктор:
и ссылаться в функции на this.self.
Подскажите пожалуйста, почему не работает такой код:
function closer(){
this.showsec= 15;
}
closer.prototype= {
progress: function(){
alert(this);
},
start: function(){
alert(this);
setTimeout.call(this, this.progress, 1000 );
}
}
var cl= new closer();
cl.showsec= 20;
cl.start();
Правильно будет не так
а так:
Потому что, даже если мы функции setTimeout подсунем свой this вместо окна, это не повлияет на this при срабатывании таймера.
(надеюсь, понятно изложил)
Извините, очепятался во втором варианте:
Возможно я ошибаюсь, но на мой взгляд должно быть так:
P.S. Я пробовал похожий код на 'setInterval' и с this пример не работал.
Почитал статью про замыкания, переписал так:
но вреравно интересно, почему не работает
хотя такой вариант работает
Работает, потому что здесь объектом this во всех случаях является глобальный объект, и он же используется при срабатывании таймера.
Здравствуйте!
А, если можно, объясните, пожалуйста, в чём разница между конструкцией из примера про "Васю и Диму":
и конструкцией:
Или это два идентичных способа сделать одно и тоже действие, просто первый - короче?
хорошее начало
подскажите пожалуйста как в этих случаях работает this
извините пожалуйста, подскажите код, удаляющий строку, например в таблице на которую нажали?
если использовать jquery
то проще некуда
а вот так удалится что угодно
Помогите пожалуйста разобраться
результат -ошибка this.txt is udefined
сам разобрался, может кому еще поможет
say = function() {
alert("Привет, я "+this.name)
}
vasya = {
name: "Василий"
}
dima = {
name: "Дмитрий"
}
vasya.sayHi = say
dima.sayHi = say
не работает, подскажите плз где у меня ошибка
он работает...
Работаю с JavaScript уже более трёх лет. Хотелось бы поделиться опытом по этой теме. Может, это уже известно вам, но не отнеситесь критически, потому что это полезно для новичков.
Уменьшаем расход памяти
Я заметил, что есть тенденция использовать замыкания, там, где без них можно и обойтись. На самом деле замыкания - это очень плохо при неправильном использовании. Всё дело в памяти. Несмотря на концепцию, что скриптовый программист (наш любимый JS, например) чаще всего не должен задумываться об используемой памяти (все автоматизировано и происходит без его участия), стОит думать, сколько выделено на ту или иную вкладку памяти, потому что механизм замыканий может скушать a lot of memory. Для оптимизации использована именно особенность слова this.
Возьмём всё тот же пример из темы замыканий, где каждому [div] (в моём случае - [a] и их в 100 раз больше) присваивается вызов alert() с номером в цикле. Тестировал я в хроме, потому что там удобное отображение расхода памяти для каждой из вкладок.
Первый пример:
(function init(){
for(var i=1000,a;i--;){
a=document.body.appendChild(document.createElement("a"));
a.href="#";
a.innerHTML="сообщение: "+i+";";
a.onclick=(function init(x){
return function onclick(){
alert(x);
return false;
};
})(i);
}
})();
На оптимизацию в виде обратного прохода не обращайте внимания - это не ключевой момент.
В этот примере использован механизм замыканий. Т.е. для каждого элемента браузер создаёт НОВУЮ функцию с ЗАМЫКАНИЕМ (если быть точнее, то с обращением к замкнутой переменной) внутри неё. Хром показал расход памяти в 23,2 МБ для данной вкладки.
Вариант 2:
(function init(){
for(var i=1000,a;i--;){
a=document.body.appendChild(document.createElement("a"));
a.href="#";
a.innerHTML="сообщение: "+i+";";
a.$data=i;
a.onclick=function onclick(){
alert(this.$data);
return false;
};
}
})();
Механизм замыканий исключён, память больше не расходуется на так называемую [[closure scope]]. Использована возможность присваивать элементам (как и любым объектам) пользовательские свойства (я назвал его $data, но это дело уже лично каждого). Согласно спецификации внутри функции onclick this показывает на элемент, на котором произошло событие, с которого [элемента], собственно, и берём данные. Хром показывает 20,5 МБ. Для меня - это существенный выигрыш (а что, если объектов несколько миллионов?). Но функций, как и в предыдущем примере создаётся тоже 1k.
Третий пример:
(function init(){
var f=function onclick(){
alert(this.$data);
return false;
};
for(var i=1000,a;i--;){
a=document.body.appendChild(document.createElement("a"));
a.href="#";
a.innerHTML="сообщение: "+i+";";
a.$data=i;
a.onclick=f;
}
})();
На моё мнение оптимизировано максимально, т.е. улучшать уже некуда: одна функция для тысячи элементов, она использует механизм this. Хром показывает 20,0 МБ. Всего-то 500k, но оптимизация тоже проихошла. Напомню, что в пользовательские свойства можно вписывать любые значения: числа, строки, объекты.
Настоятельно рекомендую пользоваться именно таким механизмом в подобных случаях. Как пример - реализация модели MVC.
P.S. Извиняюсь за поехавшие в коде табы.
20мб на 1000 элементов? 20кб на элемент — не много ли?
В том же CDT можно сделать снимок кучи, и её размер в Ваших примерах не превосходит 4мб.
Но в целом, идея верная, замыкания кушают память.
Имелось в виду, что 20Мб - это целая вкладка. По крайней мере, я не знаю, как узнать точный размер в физической памяти объекта JavaScript, поэтому и указал размер целой вкладки. Чтобы узнать, сколько приблизительно занимает вся эта "каша", нужно запустить эту же страницу, но уже без данного скрипта и вычесть указанный размер от 20Мб (у вас может быть и не 20Мб, а другое число).
Замыкания не просто кушают память. Они просто "пожирают её". Как-нибудь попытаюсь выяснить (сейчас нету времени), является ли в примере:
переменная document замыканием. Не спешите с ходу опровергать этот тезис, лучше приведите убедительные доказательства, если это действительно неправда.
>> "P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью."
- Джон Рейсиг "Профессиональные приёмы программирования на JavaScript".
Как говорится, прочитал всё от корки до корки. Касательно только JavaScript на этом сайте.
Замечательный сайт в плане общего ознакомления с тем, что такое JavaScript. И всё же скажу, что об ООП здесь сказано на очень низком уровне. Статьи про объекты и ООП здесь читателям позволят научиться лишь не блуждать в коде, который они читают. Сами они навряд ли смогут после прочтения этих статей что-либо сделать.
И всё же сайт на столько же хорош в своей тематики, на сколько в своей htmlbook.ru.
Для тех же, кто желает продолжить изучение и научиться хорошо(профессионально) программировать на JavaScript, хотел бы посоветовать книгу Джона Рейсига(главного разработчика библиотеки jquery) под названием "Профессиональные приёмы программирования". Хорошая книга, которая позволит вникнуть в суть JavaScript, познакомит с технологией Ajax и, что немаловажно, научит мыслить в режиме ООП.
В данной книге напрочь отсутствуют введение в JavaScript и прочие обучающие детали. Поэтому эта книга очень хороша для того, чтобы продолжить изучать JavaScript сразу после прочтения статей на этом сайте. =)
P.S. отсутствие введения и прочей шелухи для новичков сократило объём книги с стандартных 700-1000 страниц для книг схожей тематики, до 250.
Прошу прощения, всё работает! Комент удалить бы.
Подскажите пожалуйста в моём случае
Как мне обойти эту ситуацию и обратиться к свойству b ..... можно конечно перед этим поставить var self = this и обращаться уже к self, а есть ли более изящный способ ?
Как бы на клиентской стороне выяснить в скрипте путь до самого этого скрипта-ну то, что на серверной стороне выглядит как WScript.ScriptFullName ? Сунулась сюда в надежде, что this и есть оно, так нет :-)
Имеем:
В IE8 - [object.Window]
В FF 3.6.8 - [object.Window]
В FF 13 (Linux64) - undefined
В Chromium (Linux64) 19.0.1084.56 - undefined
Вопрос: и как это понимать?
Отвечаю сам себе:
This - MDN
this должна быть undefined, т.к. f2 была вызвана без предоставления контекста (например window.f2() )
Можно еще дописать, на всякий случай, что в такой-вот конструкции:
this будет obj2, и, как я понял, это единственная ситуация, где следует вызывать функцию через call/apply, а не напрямую.
(объясняю, если нужно вызвать функцию, которая находится в каком-то объекте, но как this передать ей не этот объект, а другой. В принципе, нужный объект можно и параметром передать, но иногда такой вариант удобнее, в особенности если у Вас смоделированы "абстрактные классы", как тот же Math)
Всем привет...
Как заставить работать a.b.say() ?
т.е требуется сохранить вложенность b в а, b должен тянуть уже определенную функцию say в "родителе"
Как вариант
Но это зацикливание ссылок, браузер не ругается.. но это не гуд...
Всем привет...
Как заставить работать a.b.say() ?
т.е требуется сохранить вложенность b в а, b должен тянуть уже определенную функцию say в "родителе"
Как вариант
Но это зацикливание ссылок, браузер не ругается.. но это не гуд...
Свойства, методы события объектов доступные в коде для элементов, где нибудь водятся здесь ?... Или все попутались в атрибутах HTML тегов, DOM...
Вы бы разделили все: 1.атрибуты и теги HTML и CSS, 2.DOM, 3.атрибуты/свойства, методы, события и объектов в коде JavaScript.
Например, событие onreadystatechange или свойства complete || readyState, для img, вообще нигде нет.
Привели бы общий список событий, свойств, методов, доступных в кодe JavaScript.
Ну, в общем вам еще писать и писать...))
как правильно описать картинку с помощью объектов которые есть?
Вопрос к гуру js.
Имеется код (это всего лишь удобный пример, но суть вопроса остается)
Нужно обратиться к свойству Country.name изнутри объекта capital. Есть ли какие более-менее элегантные способы это сделать? Кроме переделывания всего кода с созданием двух классов Country, Capital, и специального поля country внутри Capital (для хранения к какой стране принадлежит) и с последующим присваиванием в виде
Так код становится намного больше, появляется перекрестная ссылка, а главное - для моей задачи классы вовсе не нужны, по сути только 2 "статичных" объекта, а то и 1.
Похожий вопрос уже задавался в комментарии чуть выше, но ответа не было. Тут либо возможности js особо не позволят развернуться, чтоб так сделать, либо найдется спец, который решит данную задачку.
Можно попробовать так
Очевидно, на этом сайте не тусят специалисты в js)) Одни кодеры, что и умеющие так только добавить в html событие onclick)
Помогите разобраться, вообщем есть такой код:
$(document).ready(function(){
function Boxs(width,height,bgColor){
this.width = width;
this.height = height;
this.bgColor = bgColor;
}
var box = new Boxs(250,250,'green');
var box2 = new Boxs(200,200,'yellow');
//Создание коробки
Boxs.prototype.createBox = function(width,height,bgColor){
$('#idDiv').append('
');
$('.clBox').css({'width' : this.width+'px', 'height' : this.height+'px', 'background-color' : this.bgColor, 'margin' : '80px'});
}
box.createBox();
box2.createBox();
});
Когда я вызываю метод "createBox()" оно создает блок с заданными параметрами в объекте "box", но если я после этого вызову тот же метод но уже для другого объекта который имеет другие параметры, то "this" будет брать параметры из "box2", и сделает 2 блока со свойствам "box2".
Как сделать так что бы у меня вышли 2 блока с разными параметрами (только осваиваю js).
Просьба помочь.
В строке:
Boxs.prototype.createBox = function(width,height,bgColor){
(width,height,bgColor) были пусты вначале, это я экспериментировал хД.