Комментарии 84
Следующим шагом к пониманию функциональной стороны JavaScript является изучение замыканий, о чем уже была подробная статья.
+5
Я бы все таки посоветовал книгу, одна хорошая книга будет полезнее пачки статей/переводов. А в статьях и блогах было бы интересно видеть что-то не стандартное, не из разряда справочной информации.
+4
В книгах информация бывает сгруппирована в другом порядке, по другой логике.
Или Вы имеете ввиду какую-то конкретную книгу, где информация по this в функциях сгруппирована именно так?
Или Вы имеете ввиду какую-то конкретную книгу, где информация по this в функциях сгруппирована именно так?
0
А группировка «именно так» претендует на единственную истину? Бывают книги, именно с подборками приемов и конструкций, для гиков, и от гиков ) книги Stefanov, Zakas, Resig и тп. Где не рассматриваются азы JS, а именно приемы, паттерны и тд. Прочитайте парочку, и на многие статьи не придется тратить время.
0
У меня в аське сегодня как раз был вопрос на эту тему. Удивительно, что многим людям таак тяжело даётся этот участок.
Ещё топику не хватает описания bind — возможности привязать функцию к определённому контексту.
Самое главное — помнить, что у функции контекст (this) — это то, от какого объекта она вызвана, а не то, возле какого она создана.
Ну и не забываем о '
Ещё топику не хватает описания bind — возможности привязать функцию к определённому контексту.
Самое главное — помнить, что у функции контекст (this) — это то, от какого объекта она вызвана, а не то, возле какого она создана.
Ну и не забываем о '
use strict
'+1
И ещё хотел бы добавить. Прочитал в твиттере вашего товарища, что он не понимает, для чего нужны call/apply. На самом деле они очень часто используются для создания изящного интерфейса, многие трюки базируются именно на этих методах. К примеру, можно очень легко сделать из объекта arguments — массив:
Магия jQuery-each применяется именно при помощи apply:
Конечно, в простых приложениях такая магия нужна редко. Но в фреймворках она используется очень часто и без неё было бы очень тяжело построить изящный интерфейс.
var array = [].slice.call(arguments);
Магия jQuery-each применяется именно при помощи apply:
$('div').each(function () {
$(this); // <== here
});
Конечно, в простых приложениях такая магия нужна редко. Но в фреймворках она используется очень часто и без неё было бы очень тяжело построить изящный интерфейс.
+1
НЛО прилетело и опубликовало эту надпись здесь
В древнем приложении, где все было построено на фреймах, приходилось использовать apply. А вообще — да, редко используется. Только на собеседованиях :)
0
а почему по стрелочке <== here я не вижу слова apply?
0
Реализация скрыта внутри jQuery.each. Она и использует call/apply
+1
Пункт 2 сформулирован неверно. Ничто не мешает вызвать функцию так: { func: function(){} }.func()
Ну сколько уже можно переводить статьи из серии «JS/PHP/Java/<любая другая технология> для чайников»?
Ну сколько уже можно переводить статьи из серии «JS/PHP/Java/<любая другая технология> для чайников»?
0
И что? Да, переменной нету, но ссылка будет на объект:
</source.
0
!{ x: 42,
func: function(){
console.log(this.x);
}
}.func() // 42
0
Ну такой способ порой бывает очень даже наруку.
— и объект создали, и он успел уже что-то сделать;), и код чище. Почему бы не использовать?
var foo = {
show: function() {
$('body').css('color', '#F');
return this;
}
/** ... */
}.show();
— и объект создали, и он успел уже что-то сделать;), и код чище. Почему бы не использовать?
0
пусть народ читает, а то развелось кодеров на «jquery» глаза б мои их кода не видели!!!
Вообще хорошо бы юзерам понимать что в js все есть объекты, каждая мелочь даже
function(){
var t,y,u;
}
t,y,u — это свойства объекта, а в качестве объекта, объект перменных данной функции.
Может написать статью по объектам в js? надо погуглить хабр есть ли тут такое
Вообще хорошо бы юзерам понимать что в js все есть объекты, каждая мелочь даже
function(){
var t,y,u;
}
t,y,u — это свойства объекта, а в качестве объекта, объект перменных данной функции.
Может написать статью по объектам в js? надо погуглить хабр есть ли тут такое
+5
Единственное применение конструктора Number:)
+1
Но не совсем rulez =(
var foo = 0, bar = new Number(0);
console.log( !foo, !bar ); // true, false
+1
:(
Только так:
Только так:
var bar = new Number(0);
console.log(!(bar + 0))
0
Вообще можно так:
Но всё-равно не айс. По этой причине в Modernizr костыльно делается проверка на video и audio. Если они присутствуют, то хранится
var bar = new Number(0);
console.log(!+bar);
Но всё-равно не айс. По этой причине в Modernizr костыльно делается проверка на video и audio. Если они присутствуют, то хранится
new Object(true)
, иначе — false
. Плохо, если в таком случае необходимо и в отрицательном варианте хранить дополнительные свойства.0
Я иногда жалею, что нет методов типа toBoolean
0
Категорически поддерживаю. Этим страдает что php, что js. Реализовано только String =(
ps. php __cast
ps. php __cast
0
Преобразование типа можно явным образом сделать через его название:
var test = Boolean(«something») // true
var test = Boolean(«something») // true
+1
Теоретически, можно «по соглашению» делать — функция toBoolean, которая вызывает метод .toBoolean у аргумента. Но это не так изящно, как если бы поддерживалось языком.
0
да можно Object.prototype.toBoolean = function а так каст в bool вшит в язык
0
Нельзя, не получится по объектам итерировать. Именно потому в MooTools не расширили прототип объекта. С нетерпением ждём Object.defineProperty с
enumerable = false
+1
Тут о том и речь, что хочется иметь возможность переопределять этот каст для своих объектов.
+1
Чем не угодил valueOf()? Проблема в том что object → boolean всегда true.
+2
foo — элементарный bar — объект естественно что он не интерпретируется в false при отрицании
0
0
ну примитивы нужны, но они преобразуются автоматически в объект «Хабр».length при вызове методов
0
Примитивы преобразуются в объекты с помощью дот-оператора, а объекты преобразуются в примитивы при помощи операторов +, -, <, >, !, etc.
Говорить, что всё в JS объекты (или преобразуются в объекты) — это всё равно что говорить что всё числа (или преобразуются в числа).
Не смущайте новичков.
Говорить, что всё в JS объекты (или преобразуются в объекты) — это всё равно что говорить что всё числа (или преобразуются в числа).
Не смущайте новичков.
0
Новичков, может, это и смущает, но знать стоит.
Были времена, когда всё было числами выражено. Всё выражалось двоичном кодом, что в памяти хранилось, поэтому и имело место говорить, что всё числа. Тогда же и обрабатывали мы их таким образом. Сейчас же другая ситуация: в JS нет (на соотв. уровне абстракции) понятия памяти, ея управления и др.; вместо этого нам предоставляется мощный инструмент для работы к объектами. Обратите внимание: только null и undefined не могут быть сведены к Object (что, кстати, было бы странно). Это дает нам полное право утверждать, что всякая структура данных выражается объектом. На практике, собственно, так и бывает: со всеми структурами можно проводить характерные «объектные» манипуляции.
Я, правда, соглашусь, что примитивы нужны. Сложно было бы осваивать язык, если б числа, строки и булевы величины вели себя «более объектно». А так на данный момент на них можно смотреть как на примитивы, так и как на объекты.
Были времена, когда всё было числами выражено. Всё выражалось двоичном кодом, что в памяти хранилось, поэтому и имело место говорить, что всё числа. Тогда же и обрабатывали мы их таким образом. Сейчас же другая ситуация: в JS нет (на соотв. уровне абстракции) понятия памяти, ея управления и др.; вместо этого нам предоставляется мощный инструмент для работы к объектами. Обратите внимание: только null и undefined не могут быть сведены к Object (что, кстати, было бы странно). Это дает нам полное право утверждать, что всякая структура данных выражается объектом. На практике, собственно, так и бывает: со всеми структурами можно проводить характерные «объектные» манипуляции.
Я, правда, соглашусь, что примитивы нужны. Сложно было бы осваивать язык, если б числа, строки и булевы величины вели себя «более объектно». А так на данный момент на них можно смотреть как на примитивы, так и как на объекты.
0
Примитивы может и не нужны, во многих языках их нет и всё в порядке. Стоит понимать разницу между примитивами и объектами и не валить всё в одну кучу.
Обратите внимание, что даже null и undefined могут быть сведены к Number. Это дает нам полное право утверждать, что всякая структура данных выражается числом. То же верно и про строку и про boolean.
{valueOf: function () { return 6; }} / 2 === 3
это то же самое что
«habr».length === 4
оператор преобразовал значение в нужный нам тип чтобы разделить его на два или взять свойство length.
Обратите внимание, что даже null и undefined могут быть сведены к Number. Это дает нам полное право утверждать, что всякая структура данных выражается числом. То же верно и про строку и про boolean.
{valueOf: function () { return 6; }} / 2 === 3
это то же самое что
«habr».length === 4
оператор преобразовал значение в нужный нам тип чтобы разделить его на два или взять свойство length.
0
не с помощью дот оператор а с помощью вызова метода. Возь пример из комментария выше
var num = 123;
num.test = 42;
console.log( num.test ); // undefined
Говорить, что все объекты можно, это сделано для удобства ибо в любой момент можно сделать «ааа».length и примитив будет вести себя как объект. Вот из-за этого и возникает термин «все объекты», так как разница между объектом и примитивом, а скажем в java заметна, хотя там тоже главная идеология объекты.
я бы мог только undefined назвать костылем, так как null в данном случае является нормальным значением в мире объектов, указывая на отсутствие оного
var num = 123;
num.test = 42;
console.log( num.test ); // undefined
Говорить, что все объекты можно, это сделано для удобства ибо в любой момент можно сделать «ааа».length и примитив будет вести себя как объект. Вот из-за этого и возникает термин «все объекты», так как разница между объектом и примитивом, а скажем в java заметна, хотя там тоже главная идеология объекты.
я бы мог только undefined назвать костылем, так как null в данном случае является нормальным значением в мире объектов, указывая на отсутствие оного
0
Нет подводных камней, говоришь?
0
Может написать статью по объектам в js? надо погуглить хабр есть ли тут такое
В общем, если есть что писать — пишите.
0
В JavaScript, неважно, выполняется ли скрипт в браузере или в ином окружении, всегда определен глобальный объект. Любой код в нашем скрипте, не «привязанный» к чему-либо (т.е. находящийся вне объявления объекта) на самом деле находится в контексте глобального объекта.
Это не справедливо для strict mode, this там будет undefined
6 способ вызова функции — косвенный вызов функции. Это когда мы вызываем функцию не напрямую someFunc(args), а через результат выполнения какой-нибудь операции, например используя запятую: (1, someFunc)(args). Такой вызов — единственный способ получить глобальный объект в strict mode, с помощью косвенного вызова eval
+1
А кто нибудь знает, как вызвать функцию одновременно с new и call/apply?
Т.е. у меня есть параметры в массиве, я не знаю что там в этом массиве, и нужно вызвать функцию как конструктор с этими параметрами.
Т.е. у меня есть параметры в массиве, я не знаю что там в этом массиве, и нужно вызвать функцию как конструктор с этими параметрами.
0
Никак :(
0
Можно вынести код из конструктора в прототип (например метод init) и после конструирования через new выполнить вынесенный метод с помощью apply. Конечно всё это не ручками хорошо бы делать, а написать обёртку какую-нибудь
0
eval?
-1
Если вы про создание объекта по массиву аргументов конструктора, то, например (но не работает для системных конструкторов, только для пользовательских):
// create objects with arbitrary-length args to constructor
var constructor_apply = function ( constructor, args )
{
function new_const( constructor, args )
{
return constructor.apply( this, args );
};
new_const.prototype = constructor.prototype;
return new new_const( constructor, args );
};
//…
var o = constructor_apply( MyClass, [ 42 ] );
Ждём штатный способ в новых версиях JS…
// create objects with arbitrary-length args to constructor
var constructor_apply = function ( constructor, args )
{
function new_const( constructor, args )
{
return constructor.apply( this, args );
};
new_const.prototype = constructor.prototype;
return new new_const( constructor, args );
};
//…
var o = constructor_apply( MyClass, [ 42 ] );
Ждём штатный способ в новых версиях JS…
0
В AtomJS я реализовал метод Class.factory так:
Потом можно вызывать метод factory:
Constructor.prototype.factory = new function() {
function Factory(args) { return Constructor.apply(this, args); }
Factory[prototype] = Constructor[prototype];
return function(args) { return new Factory(args || []); }
}
Потом можно вызывать метод factory:
Constructor.factory([1, 2, 3]) == new Constructor(1, 2, 3)
0
Ой, prototype там лишний. Там просто
Constructor.factory = new function() {
0
Тем не менее, это всё равно hack который не сработает для «нативных» конструкторов.
0
Array.factory = new function() {
function Factory(args) { return Array.apply(this, args); }
Factory.prototype = Array.prototype;
return function(args) { return new Factory(args || []); }
}
console.log( Array.factory([5]).length ); // 5
0
String? Number? Boolean? :)
0
Мне просто интересно, зачем оно может понадобиться для String, Number или Boolean =))
0
Ну я могу написать функцию которая будет по разному себя вести в зависимости от того как она вызывается, как конструктор или как функция.
Я к тому, что решение хорошее, но небезупречное. Это как if (a instanceof Array), в большинстве случаев сработает…
Я к тому, что решение хорошее, но небезупречное. Это как if (a instanceof Array), в большинстве случаев сработает…
0
Ну я могу написать функцию которая будет по разному себя вести в зависимости от того как она вызывается, как конструктор или как функция.
Угу, у меня в
atom.Class
такое реализовано. Был вдохновлён Number
Кстати, почему оно не работает с примитивными объектами?
0
Кстати, как обмануть такую фабрику? Обычный подход с
this instanceof Class
— не подходит:var Class = function () {
if ( this instanceof Class ) {
console.log('first');
} else {
console.log('second');
}
};
Class.factory = new function() {
function Factory(args) { return Class.apply(this, args); }
Factory.prototype = Class.prototype;
return function(args) { return new Factory(args || []); }
}
Class.factory();
0
Поправьте плиз
с
на
с
return [ this, arg1, arg 2];
на
return [ this, arg1, arg2 ];
+1
Как раз на днях пришлось разбираться с поведением this. К перечисленным четырём вариантам я бы, пожалуй, добавил ещё и пятый, который не то, чтобы совсем особенный, но всё же неочевидный.
Возьмём такой код:
Даже когда я прочёл описания всех четырёх механизмов (глобальный вызов, конструктор, метод объекта, call/apply), я был уверен, что при выполнении someFunc() значением this будет someObj. На самом деле — ничего подобного, он будет равен window. Чёткого и внятного объяснения в интернетах я найти не смог, но по обрывкам рассуждений понял, что в данном случае движок JS сохраняет для отложенного вызова лишь ссылку на функцию, после чего вызывает её из глобального контекста, а информация, что хотели вызвать не просто функцию, а именно метод объекта someObj, к этому моменту уже потеряна.
Возьмём такой код:
setTimeout(someObj.someFunc, 1000);
Даже когда я прочёл описания всех четырёх механизмов (глобальный вызов, конструктор, метод объекта, call/apply), я был уверен, что при выполнении someFunc() значением this будет someObj. На самом деле — ничего подобного, он будет равен window. Чёткого и внятного объяснения в интернетах я найти не смог, но по обрывкам рассуждений понял, что в данном случае движок JS сохраняет для отложенного вызова лишь ссылку на функцию, после чего вызывает её из глобального контекста, а информация, что хотели вызвать не просто функцию, а именно метод объекта someObj, к этому моменту уже потеряна.
+2
Объяснение этому следующее: функции в JS являются объектами первого класса и не имеют неявной привязки к объекту. Если вы передаёте куда-то в качестве аргумента функцию — вы передаёте только функцию и ничего больше.
+5
Все верно, представьте себе это так:
т.е. someFunc ссылается на ту же самую функцию, но вызывается уже в другом контексте.
Лечится например так:
или так:
var someFunc = someObj.someFunc;
someFunc();
т.е. someFunc ссылается на ту же самую функцию, но вызывается уже в другом контексте.
Лечится например так:
setTimeout( function(){ someObj.someFunc() }, 1000 );
или так:
setTimeout( "someObj.someFunc()", 1000 );
0
// или так:
setTimeout( someObj.someFunc.bind(someObj) , 1000 );
// или при помощи mootools:
someObj.someFunc.delay(1000, someObj);
0
Это не подойдёт, если используется только чистый JS, без сторонних фреймворков. (Первый вариант — это, я так понял, для jQuery?)
0
Первый вариант, как раз — это чистый Javascript.
Необходим маленький скрипт для того, чтобы заработало в старых браузерах.
Необходим маленький скрипт для того, чтобы заработало в старых браузерах.
0
Лечится например так:Именно так в конце концов и поступил (по первому способу, второй не прокатил бы, т.к. в качестве someObj выступал локальный объект, а не глобальный). Но с точки зрения незамутнённого сознания всё-таки не совсем логично создавать новую «пустую» функцию исключительно для того, чтобы сохранить привязку к объекту…
0
В данном случае, мы как бы скопировали всю функцию, включая список аргументов и тело, и присвоили получившийся объект свойству make объекта arrayMaker. Это равносильно такому объявлению:Не скопировали, а присвоили ссылку на созданную функцию новой переменной. И это не равносильно такому объявлению, так как в нем как раз создается новая аналогичная функция.
var arrayMaker = {
someProperty: 'Какое-то значение';
make: function (arg1, arg2) {
return [ this, arg1, arg 2];
}
};
Пы.Сы. Заголовок звучит как «Пять способов вызвать функцию», хотя описано только четыре (если конечно apply и call не считаются двумя принципиально разными способами).
+1
Не описан способ вызова анонимных функций.
или
или именованных функций
или для рекурсии
(function (x){ console.log(x);})('Hello world');
или
!function (x){ console.log(x);}('Hello world');
или именованных функций
(function f(x){ console.log(x); return f; })('Hello')('world');
// при этом прошу заметить
f('foo'); // exception
или для рекурсии
(function f(x){ console.log(x); if(x>0) f(x-1);})(10);
+5
Есть ещё несколько методов из будущего (неявный вызов функции):
С помощью
// 1. через ключевое слово get
var o = {
get pewpew () {
console.log('pass');
}
}
// неявно вызываем функцию pewpew
o.pewpew;
// 2. через __defineGetter__
var o = {};
o.__defineGetter__("pewpew", function blabla(){
console.log('pass');
});
// неявно вызываем функцию blabla
o.pewpew;
// 3. через __defineSetter__
Object.prototype.__defineSetter__("pew", function blabla(a){
console.log('pass');
});
// неявно вызываем функцию blabla
({}).pew = 152;
// 4. через Proxy (существует куча ловушек, обработчик каждой можно неявно вызвать)
var o = Proxy.create({
get: function () {
console.log('pass');
}
}, {});
// неявно вызываем функцию-ловушку get
o.pewpew1;
o.pewpew2;
o.pewpew3;
С помощью
__defineSetter__
, кстати, можно провернуть один трюк с JSONP. Вместо функции обработчика можно передать ({}).pew=
и настроить обработчик на «pew»:Object.prototype.__defineSetter__("pew", function pewHook(a){
console.log(a.aaa === 123);
// снимаем обработчик "pew" ...
});
// Сервер подчинится и отправит нам код в таком формате, как будто это вызывается какая-то функция:
({}).pew=({'aaa':123});
// Дальше отработает pewHook
Ничего полезного в этом нет (просто «финт ушами»), разве что не засоряются глобалы на время ожидания JSONP. Не все сервера принимают обработчик такого формата (проверял на Flickr — не заработало).+1
А можно буквально двумя словами, в чём практический смысл неявного вызова функции?
0
Для уменьшения объема кода (для js1k и прочих) — пример
0
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Пять способов вызвать функцию