Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   помогите понять (https://javascript.ru/forum/events/28787-pomogite-ponyat.html)

cyber 02.06.2012 19:46

помогите понять
 
прочитал эту статью http://learn.javascript.ru/arguments
и заинтересовала возможность:
Цитата:

Передача вызова при помощи call/apply

вот линк http://learn.javascript.ru/arguments...и-call-apply
но я не совсем понимаю как это работает, помогите ответить на пару возникших вопросов :
  1. передается только this, или можно получить доступ к переменным который находятся в функции из которой вызвали?
  2. .call - это метод или функция? и зачем он нужен?
заранее спс

DreamTheater 02.06.2012 19:59

https://developer.mozilla.org/en/Jav.../Function/call
https://developer.mozilla.org/en/Jav...Function/apply

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

Это по сути одно и тоже, только в call аргументы передаются по одному через запятую, а в apply - массивом. Второе удобно использовать когда количество аргументов заранее неизвестно.

cyber 02.06.2012 20:02

Цитата:

Сообщение от DreamTheater (Сообщение 178305)
https://developer.mozilla.org/en/Jav.../Function/call
https://developer.mozilla.org/en/Jav...Function/apply

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

Это по сути одно и тоже, только в call аргументы передаются по одному через запятую, а в apply - массивом. Второе удобно использовать когда количество аргументов заранее неизвестно.

это получается как arguments если из него массив получить..
а что насчет первого вопроса?

DreamTheater 02.06.2012 20:05

Первый вопрос я не понял.

cyber 02.06.2012 20:10

вот не совсем понимаю как работает данный код

var user = {
  log: function() {
logService.add.apply(logService, arguments);
  }
}

var logService = {
  add: function() {
    alert( this.format(arguments) );
  },

  format: function(args) {
    return [].join.call(args, ' ');
  }
}

user.log("Вася", "сказал", "что-то умное..");

DreamTheater 02.06.2012 20:16

Цитата:

Сообщение от cyber (Сообщение 178315)
вот не совсем понимаю как работает данный код

Что именно непонятно?

cyber 02.06.2012 20:26

logService.add.apply(logService, arguments);

что передается в logService ?
в arguments я так понял псевдо массив arguments.

но в

add: function() {

    alert( this.format(arguments) );
  },

передается arguments через this - вот тут я не пойму как это работает
Цитата:

Обратите внимание, что вызов logService.add.apply(logService, arguments) передал аргументы в функцию logService.add, но при этом сохранил this.
кстати можете обьяснить что такое псевдо массив

devote 02.06.2012 20:33

при вызове функции у нее есть скрытый аргумент arguments
тоесть
function myfunc() {
    alert( arguments ); // тут массив переданных аргументов
}
myfunc( arg1, arg2 );

при вызове myfunc обычным образом ей передается в качестве контекста то что стоит слева от метода, в нашем случаем:
myfunc();

не имеет ничего слева и по умолчанию функция получает контекст window в обычном режиме или null в строгом режиме.
тоесть:
function myfunc() {
    alert( this ); // window в обычном режиме, null в строгом режиме
}

И что бы функция получила нужный нам контекст, для этого есть два метода, особо сильно они не отличаются, например вызвать функцию и передать ей нужный контекст можно так:
myfunc.call( "Я новый контекст", arg1, arg2 );

и при вызове мы получим:
function myfunc() {
    alert( this ); // "Я новый контекст"
    alert( arguments ); // массив аргументов
}

другой метод apply отличается тем что в него не нужно передавать аргументы списком, а достаточно передать массив аргументов:
myfunc.apply( "Я новый контекст", [ arg1, arg2 ] );

и при вызове мы получим тоже самое:
function myfunc() {
    alert( this ); // "Я новый контекст"
    alert( arguments ); // массив аргументов
}

тоесть apply нам дает возможность вызвать функцию не зная точного количества аргументов, допустим мы перехватываем нашу функцию myfunc но мы не знаем сколько в нее аргументов должно придти
function proxyMyfunc() {
    // делаем нужное действие
    // и вызываем оригинал
    myfunc.apply( this, arguments );
}

cyber 02.06.2012 20:44

спасибо за развернутый ответ.
чет голова плохо варит уже, пойду отдохну и вникну=)
еще раз спасибо

cyber 02.06.2012 21:37

function proxyMyfunc() {
    // делаем нужное действие
    // и вызываем оригинал
    myfunc.apply( this, arguments );
}

в данном случае передастся ссылка на обьект proxyMyfunc и псевдо массив arguments!?
и в качестве this в myfunc будет использоваться обьект proxyMyfunc я правильно понял?=)

devote 02.06.2012 21:42

Цитата:

Сообщение от cyber
и в качестве this в myfunc будет использоваться обьект proxyMyfunc я правильно понял?=)

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

cyber 02.06.2012 21:47

Цитата:

Сообщение от devote (Сообщение 178348)
нет, не правильно. передастся контекст тот же что использует функция proxyMyfunc но не сама функция

а теперь?=)

function fnc (){
      
      alert(this.t)
      }
      
      (function ()
      {
      this.t = "ну и олень";
      fnc.apply(this, arguments)
      
      }());

devote 02.06.2012 21:58

Цитата:

Сообщение от cyber
а теперь?=)

ну и теперь и вы передаете контекст, но контекст скорее всего равен объекту window:
function fnc() {
    alert( "Наш контекст внутри функции fnc: " + this );
    alert(this.t);
}
       
(function () {
    alert( "Наш контекст внутри безымянной функции: " + this );

    this.t = "ну и олень";
    fnc.apply( this, arguments );
}());
Другой вариант:
function fnc() {
    alert( "Наш контекст внутри функции fnc: " + this );
    alert(this.t);
}
       
(function () {
    alert( "Наш контекст внутри безымянной функции: " + this );

    var context = {
        t: "ну и олень"
    };

    fnc.apply( context, arguments );
}());

cyber 02.06.2012 22:12

Цитата:

Сообщение от devote (Сообщение 178352)
ну и теперь и вы передаете контекст, но контекст скорее всего равен объекту window:
function fnc() {
    alert( "Наш контекст внутри функции fnc: " + this );
    alert(this.t);
}
       
(function () {
    alert( "Наш контекст внутри безымянной функции: " + this );

    this.t = "ну и олень";
    fnc.apply( this, arguments );
}());
Другой вариант:
function fnc() {
    alert( "Наш контекст внутри функции fnc: " + this );
    alert(this.t);
}
       
(function () {
    alert( "Наш контекст внутри безымянной функции: " + this );

    var context = {
        t: "ну и олень"
    };

    fnc.apply( context, arguments );
}());

а теперь дошло
var user = {
  log: function() {
logService.add.apply(logService, arguments);
  }
}

var logService = {
  add: function() {
    alert( this.format(arguments) );
  },

вместо this тут logService и вызывается его метод format ,а в качестве аргументов передаются аргументы переданные user.log
format: function(args) {
    return [].join.call(args, ' ');
  }
}

user.log("Вася", "сказал", "что-то умное..");

devote 02.06.2012 22:36

Цитата:

Сообщение от cyber
вместо this тут logService и вызывается его метод format ,а в качестве аргументов передаются аргументы переданные user.log

верно

cyber 02.06.2012 22:43

Цитата:

Сообщение от devote (Сообщение 178364)
верно

спасибо за то что помогли разобратся:thanks:

cyber 02.06.2012 23:38

еще один вопросик возник подскажите как устроен метод sort
смотрел тут но что то не нашел https://developer.mozilla.org/en/Jav...cts/Array/sort

melky 02.06.2012 23:48

Цитата:

Сообщение от cyber (Сообщение 178372)
еще один вопросик возник подскажите как устроен метод sort
смотрел тут но что то не нашел https://developer.mozilla.org/en/Jav...cts/Array/sort

Т.е. алгоритм работы? Да тысячи их.
Точно сказать можно, только взглянув на исходный код этого метода.

cyber 02.06.2012 23:51

Цитата:

Сообщение от melky (Сообщение 178373)
Точно сказать можно, только взглянув на исходный код этого метода.

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

cyber 02.06.2012 23:56

вот к примеру таже статья ссылку на которую я давал в начале поста, там приведен пример join
function join(separator) {
  if (!this.length) return '';

  var str = this[0]; 

  for (var i = 1; i<this.length; i++) {
    str += separator + this[i]; 
  }
  
  return str;
}

или автор сам писал этот код исходя из спецификации?

melky 02.06.2012 23:56

Цитата:

Сообщение от cyber (Сообщение 178374)
мне именно он и нужен , тот который браузер использует когда вызвается sort

ArrayPrototype.cpp
Удачи :)
Код:

EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
{
    JSObject* thisObj = exec->hostThisValue().toObject(exec);
    unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
    if (!length || exec->hadException())
        return JSValue::encode(thisObj);

    JSValue function = exec->argument(0);
    CallData callData;
    CallType callType = getCallData(function, callData);

    if (thisObj->classInfo() == &JSArray::s_info && !asArray(thisObj)->inSparseMode()) {
        if (isNumericCompareFunction(exec, callType, callData))
            asArray(thisObj)->sortNumeric(exec, function, callType, callData);
        else if (callType != CallTypeNone)
            asArray(thisObj)->sort(exec, function, callType, callData);
        else
            asArray(thisObj)->sort(exec);
        return JSValue::encode(thisObj);
    }

    // "Min" sort. Not the fastest, but definitely less code than heapsort
    // or quicksort, and much less swapping than bubblesort/insertionsort.
    for (unsigned i = 0; i < length - 1; ++i) {
        JSValue iObj = thisObj->get(exec, i);
        if (exec->hadException())
            return JSValue::encode(jsUndefined());
        unsigned themin = i;
        JSValue minObj = iObj;
        for (unsigned j = i + 1; j < length; ++j) {
            JSValue jObj = thisObj->get(exec, j);
            if (exec->hadException())
                return JSValue::encode(jsUndefined());
            double compareResult;
            if (jObj.isUndefined())
                compareResult = 1; // don't check minObj because there's no need to differentiate == (0) from > (1)
            else if (minObj.isUndefined())
                compareResult = -1;
            else if (callType != CallTypeNone) {
                MarkedArgumentBuffer l;
                l.append(jObj);
                l.append(minObj);
                compareResult = call(exec, function, callType, callData, jsUndefined(), l).toNumber(exec);
            } else
                compareResult = (jObj.toUStringInline(exec) < minObj.toUStringInline(exec)) ? -1 : 1;

            if (compareResult < 0) {
                themin = j;
                minObj = jObj;
            }
        }
        // Swap themin and i
        if (themin > i) {
            thisObj->methodTable()->putByIndex(thisObj, exec, i, minObj, true);
            if (exec->hadException())
                return JSValue::encode(jsUndefined());
            thisObj->methodTable()->putByIndex(thisObj, exec, themin, iObj, true);
            if (exec->hadException())
                return JSValue::encode(jsUndefined());
        }
    }
    return JSValue::encode(thisObj);
}


cyber 03.06.2012 00:01

спасибо это мне на долго :blink:

melky 03.06.2012 00:06

Цитата:

Сообщение от cyber (Сообщение 178377)
спасибо это мне на долго :blink:

Неа.

Этот комментарий даёт наводку.
Цитата:

// "Min" sort. Not the fastest, but definitely less code than heapsort
// or quicksort, and much less swapping than bubblesort/insertionsort
Похож же исходный код?
Код:

template <class Item>
void selection(Item a[],int l,int r){
    for(int i=l;i<r;i++){
        int min=i;
        for(int j=i+1;j<r+1;j++){
            if( a[j]< a[min])
                min=j;
        }
        if(a[min]!=a[i]) /* эта проверка делается только в устойчивых реализациях */
            exch(a[i],a[min]);
    }
}

Значит это Сортировка выбором.

cyber 03.06.2012 00:28

я это хотел немного по другой причине узнать , а не сам алгоритм=)
document.getElementById("bt_Block").childNodes

данный код возвращает object Nodelist и у меня возникла идея сделать так
var obj = document.getElementById("bt_Block").childNodes;
var s = [].sort;
s.call.sort (obj, func);

Раед 03.06.2012 00:38

Цитата:

Сообщение от melky
Похож же исходный код?

Ага, похож: ни там ни там ничё непонятно :D

Раед 03.06.2012 00:40

Цитата:

Сообщение от cyber
данный код возвращает object Nodelist и у меня возникла идея сделать так

cyber,
Это делается так
var obj = document.getElementById("bt_Block").childNodes;
obj = Array.prototype.slice.call(obj);

cyber 03.06.2012 00:42

Цитата:

Сообщение от Раед (Сообщение 178386)
cyber,
Это делается так
var obj = document.getElementById("bt_Block").childNodes;
obj = Array.prototype.slice.call(obj);

спс, до прототипного программирования я еще не дошел=)

cyber 03.06.2012 00:56

я так понимаю такой фокус не прокатит избавить от текстовых узлов
<div class="bt_inp_Block" id="bt_Block" >
<input type="text"  class="inp_Out_color"  value='выбор цвета >>' disabled="disabled" />
<input type="button" value="Color" class="start_Button" >
</div>
    <script>

      function sortChild (obj){
      
        if (obj.nodeType == 1)return obj;
       }
     var obj = document.getElementById("bt_Block").childNodes;
	obj = Array.prototype.slice.call(obj);

     alert(obj.sort(sortChild))
 



    </script>

Раед 03.06.2012 02:43

<div class="bt_inp_Block" id="bt_Block" >
<input type="text"  class="inp_Out_color"  value='выбор цвета >>' disabled="disabled" />
<input type="button" value="Color" class="start_Button" >
</div>
    <script>
 
      function sortChild (obj){
       
        if (obj.nodeType == 1) return true;
        return false
       }
     var obj = document.getElementById("bt_Block").childNodes;
    obj = Array.prototype.filter.call(obj, sortChild);
 
     alert(obj)
  
 
    </script>

cyber 03.06.2012 03:50

Цитата:

Сообщение от Раед (Сообщение 178397)
<div class="bt_inp_Block" id="bt_Block" >
<input type="text"  class="inp_Out_color"  value='выбор цвета >>' disabled="disabled" />
<input type="button" value="Color" class="start_Button" >
</div>
    <script>
 
      function sortChild (obj){
       
        if (obj.nodeType == 1) return true;
        return false
       }
     var obj = document.getElementById("bt_Block").childNodes;
    obj = Array.prototype.filter.call(obj, sortChild);
 
     alert(obj)
  
 
    </script>

filter

это типо ссылка на стандартный метод?
спс что помогаете=)

cyber 04.06.2012 18:29

продолжаю изучение по учебнику http://learn.javascript.ru и снова столкнулся с проблемой и вот в этой
http://learn.javascript.ru/using-closures
статье есть задача для самостоятельного решения вот задача
http://learn.javascript.ru/task/funk...trokovyj-bufer
и все ок задачу решил он не сложная но сначала все работало , а потом вместо результат начало возвращать содержимое тела функции
function makeBuffer() {
var buff = "";

  return function (param){
  if(!param)return buff;
   
    buff += param;
    
  }

}

var buffer = makeBuffer();

// добавить значения к буферу
buffer('Замыкания'); 
buffer(' Использовать'); 
buffer(' Нужно!'); 
// получить текущее значение
alert(buffer);

помогите понять почему так?

Раед 04.06.2012 18:35

function makeBuffer() {
var buff = "";
 
  return function (param){
  if(!param)return buff;
    
    buff += param;
     
  }
 
}
 
var buffer = makeBuffer();
 
// добавить значения к буферу
buffer('Замыкания');
buffer(' Использовать');
buffer(' Нужно!');
// получить текущее значение
alert(buffer*!*()*/!*);

cyber 04.06.2012 18:42

Цитата:

Сообщение от Раед (Сообщение 178859)
function makeBuffer() {
var buff = "";
 
  return function (param){
  if(!param)return buff;
    
    buff += param;
     
  }
 
}
 
var buffer = makeBuffer();
 
// добавить значения к буферу
buffer('Замыкания');
buffer(' Использовать');
buffer(' Нужно!');
// получить текущее значение
alert(buffer*!*()*/!*);

ой протупил, пасиб :)

cyber 04.06.2012 18:50

и еще маленький вопрос
зачем в это коде
function summ (a)
      {
      var summa = a ;
      
        function f(b){
  	  summa += b;    
      return f;
        };
        f.toString = function() { return summa; };
       return f; 
      };
   alert(summ (5)(3)(-8))

строчка
f.toString = function() { return summa; };

и когда он срабатывает?

Раед 04.06.2012 18:56

Метод toString вызывается автоматически, когда необходимо привести объект к строке.
В данном случае alert(summ (5)(3)(-8)) - это сокращённая запись alert(summ (5)(3)(-8).toString())

cyber 04.06.2012 19:04

Цитата:

Сообщение от Раед (Сообщение 178876)
Метод toString вызывается автоматически, когда необходимо привести объект к строке.
В данном случае alert(summ (5)(3)(-8)) - это сокращённая запись alert(summ (5)(3)(-8).toString())

:thanks:

cyber 06.06.2012 19:25

дошел до последней главы функций и на удивление благодаря вашим подсказкам много нового узнал=)
но возник вопрос по последнему уроку Декораторы
http://learn.javascript.ru/decorators
вот к примеру есть код
function work(a) { 
  /* ... */ // work - произвольная функция, один аргумент
}

function makeLogging(f, log) {

  return function (a){
  
 log.push(a);
  f.call(null,a);  
  
  }

}

var log = [];
work = makeLogging(work, log);

work(1); // 1, добавлено в log
work(5); // 5, добавлено в log

for(var i=0; i<log.length; i++) {
  alert( 'Лог:' + log[i] ); // "Лог:1", затем "Лог:5"
}

в общем код просто но вот чего не могу понять
return function (a){
  
 log.push(a);// это понятно добавление в массив лог
   return f.call(null,a);  // но смысел от этой сточки? и без нее работает
  
  }

вот код решение задачи из учебника (выше это мое ришение)
function work(a) { 
  /*...*/ // work - произвольная функция, один аргумент
}

function makeLogging(f, log) {

function wrapper(a) {
    log.push(a);
    return f.call(this, a);   
  }

  return wrapper;
}

var log = [];
work = makeLogging(work, log);

work(1); // 1
work(5); // 5

for(var i=0; i<log.length; i++) {
  alert( 'Лог:' + log[i] ); // "Лог:1", затем "Лог:5"
}

Раед 06.06.2012 19:34

Цитата:

Сообщение от cyber
return f.call(null,a); // но смысел от этой сточки? и без нее работает

Ну дык она же функцию вызывает. Без неё весь смысл декораторов теряется.

cyber 06.06.2012 19:40

Цитата:

Сообщение от Раед (Сообщение 179508)
Ну дык она же функцию вызывает. Без неё весь смысл декораторов теряется.

не ну это я понимаю:yes:
но в данном примере нет смысла от нее так как функция пустая?=)

Раед 06.06.2012 19:58

Цитата:

Сообщение от cyber
но в данном примере

Вот именно, это всего лишь пример и функция может быть любой
Цитата:

Сообщение от cyber
work - произвольная функция



Часовой пояс GMT +3, время: 01:00.