если передать null как параметр, он всегда выполняет первый метод, почему.? [Дубликат]

Что вы должны знать о this

this (иначе говоря, «контекст») - это специальное ключевое слово внутри каждой функции, и его значение зависит только от , как была вызвана функция, а не как / когда / где она была определена. Лексические области не затрагиваются, как и другие переменные. Вот несколько примеров:

function foo() {
    console.log(this);
}

// normal function call
foo(); // `this` will refer to `window`

// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`

// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`

Чтобы узнать больше о this, просмотрите документацию MDN .


Как сделать обратитесь к правильному this

Не используйте this

Фактически вы не хотите иметь доступ к this в частности, но объект, на который он ссылается на . Вот почему простое решение - просто создать новую переменную, которая также относится к этому объекту. Переменная может иметь любое имя, но общие - self и that.

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function() {
        alert(self.data);
    });
}

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

Явно установить this обратного вызова - часть 1

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

Каждая функция имеет метод .bind [docs] , который возвращает новую функцию с this, привязанную к значению. Функция имеет то же поведение, что и тот, который вы назвали .bind, только то, что this было установлено вами. Независимо от того, как и когда эта функция вызывается, this всегда будет ссылаться на переданное значение.

function MyConstructor(data, transport) {
    this.data = data;
    var boundFunction = (function() { // parenthesis are not necessary
        alert(this.data);             // but might improve readability
    }).bind(this); // <- here we are calling `.bind()` 
    transport.on('data', boundFunction);
}

В этом случае мы привязываем обратный вызов this к значению MyConstructor 's this.

Примечание. При связывании контекста для jQuery вместо этого используйте jQuery.proxy [docs] . Причина этого заключается в том, что вам не нужно сохранять ссылку на функцию при отмене обратного вызова события. jQuery обрабатывает это внутренне.

ECMAScript 6: Используйте функции стрелок

В ECMAScript 6 представлены функции стрелок , которые можно рассматривать как лямбда-функции. У них нет собственной привязки this. Вместо этого this просматривается в области видимости как обычная переменная. Это означает, что вам не нужно называть .bind. Это не единственное особое поведение, которое у них есть. Дополнительную информацию см. В документации MDN.

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', () => alert(this.data));
}

Установите this обратного вызова - часть 2

Некоторые функции / методы, которые принимают обратные вызовы, также принимают значение, к которому должен обращаться обратный вызов this. Это в основном то же самое, что и привязывать его самостоятельно, но функция / метод делает это за вас. Array#map [docs] - такой метод. Его подпись такова:

array.map(callback[, thisArg])

Первый аргумент - это обратный вызов, а второй аргумент - значение this. Вот надуманный пример:

var arr = [1, 2, 3];
var obj = {multiplier: 42};

var new_arr = arr.map(function(v) {
    return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument

Примечание. Можно ли передать значение для this, как правило, упоминается в документации этой функции / метода. Например, метод $.ajax jQuery [docs] описывает параметр, называемый context:

Этот объект станет контекстом всех обратных вызовов, связанных с Ajax.


Общая проблема: использование объектных методов в качестве обработчиков обратных вызовов / событий

Еще одно распространенное проявление этой проблемы - когда объектный метод используется как обработчик обратного вызова / события , Функции являются первоклассными гражданами в JavaScript, а термин «метод» - просто разговорный термин для функции, которая является значением свойства объекта. Но эта функция не имеет конкретной ссылки на ее «содержащий» объект.

Рассмотрим следующий пример:

function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = function() {
    console.log(this.data);
};

Функция this.method назначается как обработчик события click , но если щелкнуть document.body, зарегистрированное значение будет undefined, потому что внутри обработчика события this ссылается на document.body, а не на экземпляр Foo. Как уже упоминалось в начале, то, что относится к [49], зависит от того, как называется функция, а не от того, как она определена. Если код выглядит следующим образом, может быть более очевидно, что функция не имеет неявной ссылки на объект:

function method() {
    console.log(this.data);
}


function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = method;

Решение такое же, как указано выше: если доступно, используйте .bind явно привязать this к определенному значению

document.body.onclick = this.method.bind(this);

или явно вызвать функцию как «метод» объекта, используя анонимную функцию в качестве обработчика обратного вызова / события и назначить object (this) к другой переменной:

var self = this;
document.body.onclick = function() {
    self.method();
};

или использовать функцию стрелки:

document.body.onclick = () => this.method();
106
задан Jon Skeet 13 December 2015 в 18:50
поделиться

7 ответов

Java всегда будет пытаться использовать наиболее подходящую версию доступного метода (см. JLS §15.12.2 ).

Object, char[] и Integer могут принимать null в качестве действительного значения. Поэтому все 3 версии применимы, поэтому Java придется найти наиболее конкретный.

Поскольку Object является супертипом char[], версия массива более специфична, чем Object -версия. Поэтому, если существуют только эти два метода, будет выбрана версия char[].

Если доступны версии char[] и Integer, то оба они более специфичны, чем Object, но ни один более конкретный, чем другой, поэтому Java не может решить, какой из них вызывать. В этом случае вам придется явно указать, какой из них вы хотите вызвать, отвечая аргумент соответствующему типу.

Обратите внимание, что на практике эта проблема встречается гораздо реже, чем можно было бы подумать. Причиной этого является то, что это происходит только тогда, когда вы явно вызываете метод с null или с переменной довольно неспецифического типа (например, Object).

Напротив , следующий вызов будет совершенно однозначным:

char[] x = null;
doSomething(x);

Хотя вы все еще передаете значение null, Java точно знает, какой метод вызывать, поскольку он учитывает тип переменной .

178
ответ дан Jake Millington 21 August 2018 в 03:11
поделиться
  • 1
    Это указано для Java 7. Это относится также и к предыдущим версиям Java? Я имею в виду: если у вас есть несколько сигнатур методов с параметрами только по иерархии типов, чем на стороне сохранения с нулевым значением в качестве фактического значения? И если вы создали «иерархию для», как в примере здесь, значит, нет? – Christian Gosch 13 February 2015 в 13:29
  • 2
    Я уверен, что эти правила одинаковы для, по крайней мере, всего, начиная с Java 1.1 (за исключением добавления дженериков, очевидно). – Joachim Sauer 13 February 2015 в 16:04
  • 3
    Означает ли это, что если бы компилятор должен был выбирать между doSomething (String str) и doSomething (Object obj) во время выполнения с doSomething (null), будет вызываться doSomething (String str). – Sameer 10 November 2016 в 10:22
  • 4
    Большое спасибо, это спасло мое интервью :) – roottraveller 25 September 2017 в 10:34

Каждый класс в Java расширяет класс Object. Еще один класс Integer также расширяет Object. Следовательно, Object и Integer рассматриваются как экземпляр объекта. Поэтому, когда вы передаете значение null в качестве параметра, а компилятор запутывается, какой метод объекта вызывается, например, с параметром Object или параметром Integer, поскольку оба они являются объектами, а их ссылка может быть нулевой. Но примитивы в java не расширяют Object.

2
ответ дан Ankit 21 August 2018 в 03:11
поделиться

существует двусмысленность из-за doSomething (char [] obj) и doSomething (Integer obj).

char [] и Integer оба одинаковы выше для null, поэтому они двусмысленны.

0
ответ дан chitrendra chaudhary 21 August 2018 в 03:11
поделиться

Я пробовал это, и когда есть только одна пара перегруженных методов, и один из них имеет тип объекта Object, тогда компилятор всегда будет выбирать метод с более конкретным типом. Но когда существует более одного определенного типа, компилятор выдает ошибку неоднозначного метода.

Поскольку это событие времени компиляции, это может произойти только тогда, когда один намеренно передает null этому методу. Если это сделано намеренно, тогда лучше перегрузить этот метод снова без параметров или вообще создать другой метод.

1
ответ дан ItamarG3 21 August 2018 в 03:11
поделиться

Каждая пара этих трех методов является двусмысленной сама по себе при вызове с аргументом null. Поскольку каждый тип параметра является ссылочным типом.

Ниже перечислены три способа вызова одного вашего метода с нулевым значением.

doSomething( (Object) null);
doSomething( (Integer) null);
doSomething( (char[]) null);

Могу ли я предложить устранить эту двусмысленность, если вы на самом деле планируете называть эти методы с помощью null. Такой дизайн предлагает ошибки в будущем.

37
ответ дан jmg 21 August 2018 в 03:11
поделиться
  • 1
    Пара только Integer - char[] неоднозначна, потому что в других двух случаях компилятор Java может выбрать наиболее конкретный выбор, как описано в @JoachimSauer. – kajacx 11 August 2015 в 06:54
  • 2
    @kajacx: ​​исходный вопрос OPs касался вызова этих методов с параметром null в качестве параметра. При этом предварительном условии все три пары неоднозначны. В общем случае я согласен, что только пара Integer - char[] неоднозначна. – jmg 15 September 2015 в 05:51
  • 3
    как насчет doSomething(null) для public static void doSomething(String str) { System.out.println("String called"); } Это приведет к возврату строки. – Sameer 7 November 2016 в 16:13
  • 4
    Можно ли использовать такую ​​анотацию, как «нулевая», или "не обнуляемый" и настройте объявления таким образом, чтобы только один метод вы хотите получить нуль, чтобы явный «нулевой» (но неявный нулевой тип) аргумент всегда однозначно выбирает конкретную перегрузку ?? – peterk 18 July 2017 в 21:43

null является допустимым значением для любого из трех типов; поэтому компилятор не может решить, какую функцию использовать. Вместо этого используйте что-то вроде doSomething((Object)null) или doSomething((Integer)null).

4
ответ дан Lars Noschinski 21 August 2018 в 03:11
поделиться
  • 1
    Я удалил метод с помощью параметра Integer, он вызывает функцию и возвращает выход как «Array Called» , так что же является контрактом между массивом и объектом ? – Phani 8 March 2011 в 09:01
  • 2
    Массивы Java также являются объектами. – Zds 8 March 2011 в 09:53
class Sample{
  public static void main (String[] args) {
       Sample s = new Sample();
       s.printVal(null);

    } 
    public static void printVal(Object i){
        System.out.println("obj called "+i);
    }

    public static void printVal(Integer i){
        System.out.println("Int called "+i);
    }
}

Вывод Int называется NULL, и поэтому неопределенность с char [] и Integer

0
ответ дан nagarjuna chimakurthi 21 August 2018 в 03:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: