Вы покупаете ложку, и ваш сосед покупает такую же ложку. Ваш пятилетний ребенок достает вашу ложку из вашего ящика, выходит из дома и спрашивает инопланетянина: «Это папина ложка?» - пожимает плечами инопланетянин. Следующая сцена, инопланетянин в вашем доме, ваш пятилетний ребенок открывает ящик и снова спрашивает; «да» говорит инопланетянин.
На ложке нет ваших инициалов. Он не знает, что это ваша ложка. Не может и не должно. Ну, только пока вы не поставите на нее свои инициалы, и после этого она больше не будет «той ложкой, которую купил ваш сосед».
Ваша функция canJoin
в том, что ложка, у вашего соседа детский сад, а инопланетянин - это JS время выполнения.
let kindergarten = {
minAge: 2,
maxAge: 6
};
function canJoin(user) {
return user.age >= this.minAge && user.age < this.maxAge;
}
army.canJoin = canJoin; kindergarten.canJoin = canJoin;
Вы говорите в своем вопросе «canJoin был вызван с армией» - это ошибка.
Если вы сделали army.canJoin({user: 9999})
, то canJoin
вызвали с армией - ложка у вас в ящике. Если вы сделали kindergarten.canJoin({user: 9999})
, то canJoin
звонили с детского сада - ложка лежит в ящике вашего соседа. И если вы вызовете какую-то функцию, например Array.filter
, и передадите в качестве аргумента либо army.canJoin
, либо kindergarten.canJoin
, либо просто canJoin
, то ложка окажется вне ящика. Иначе и быть не могло. Наберите kindergarten.canJoin === army.canJoin
в консоль. Получается true
. Если вы хотите, чтобы инопланетяне не разводили руками, вы просите невозможного. Подумай об этом. иначе и быть не могло - информации нет.
army.canJoin=canJoin
не изменяет (' ставит инициалы на ') canJoin
не работает и kindergarten.canJoin=canJoin
- точно так же, как кладя что-то в ящик, на нем не ставятся инициалы. В institution.canJoin(...)
мы знаем, что this
равно institution
- здесь происходит вызов функции. Если, с другой стороны, скобки нет, вызов функции не выполняется. ложка извлечена из ящика .
Как указано в других ответах, вы можете использовать bind
, чтобы «нанести свои инициалы на ложку». Лично я никогда не использую bind
. Я сторонник того лагеря, который рассматривает все this
хитроумное изобретение JS (this
= «сам-знаешь-что-я-имею в виду-объект» (кроме случаев, когда вы этого не сделаете)) как слабое место. языка. Я предпочитаю конструировать закрытие, как описано ниже (следующий код заставит Array.filter
работать без второго аргумента)
function createAgeFilter(min,max){
return function(item){
return item.age>=min && item.age<max;
};
}
army.canJoin = createAgeFilter(army.minAge, army.maxAge);
kindergarten.canJoin = createAgeFilter(kindergarten.minAge, kindergarten.maxAge);
С помощью приведенного выше, так сказать, вы делаете ложки с инициалами на их с самого начала, вместо того, чтобы надевать их позже, с помощью bind
.
Вероятно, вы можете подтвердить, что новички считают, что намного легче читать по сравнению с чем-либо с использованием bind
.
ОБНОВЛЕНИЕ
Использование классов ES6 не не меняет характер проблемы .
class Army {
constructor(t){
this.tankCount=t;this.minAge=18;this.maxAge=27
}
canJoin(user){
return user.age >= this.minAge && user.age < this.maxAge;
}
}
class Kindergarten {
constructor(t){
this.toyCount=t;this.minAge=2;this.maxAge=6
}
}
Kindergarten.prototype.canJoin = Army.prototype.canJoin;
var myArmy = new Army(5);
var myKG = new Kindergarten(5);
var cast=[{name:'Susie',age:3},{name:'Agamemnon',age:5},{name:'Salome',age:18},{name:'Herod',age:40}]
function getName(u){ return u.name; }
var e1 = document.getElementById('one');
var e2 = document.getElementById('two');
var e3 = document.getElementById('three');
var e4 = document.getElementById('four');
e1.textContent = cast.filter(Army.prototype.canJoin, myArmy).map(getName).join(',');
e2.textContent = cast.filter(Army.prototype.canJoin, myKG).map(getName).join(',');
e3.textContent = cast.filter(Kindergarten.prototype.canJoin, myArmy).map(getName).join(',');
e4.textContent = cast.filter(Kindergarten.prototype.canJoin, myKG).map(getName).join(',');
<div id='one'></div>
<br>
<div id='two'></div>
<br>
<div id='three'></div>
<br>
<div id='four'></div>
Salome = {name:'Salome',age:18};
myArmy.canJoin(Salome); // true
myKG.canJoin(Solame); // false
f = myArmy.canJoin;
f(Salome); // error
обратите внимание на эту ошибку. f
равно по-прежнему не привязан к классу Army
! Просто потому, что вы использовали классы ES6, не устраняет эту ошибку go, а не связывает (как вы видите) так, как вы могли подумать. И вам все равно нужен второй аргумент для функции фильтрации, если вы используете такие классы ES6.