Помните классический предварительный вопрос

JavaScript

Темы следующие:

function Foo() {
    getName = function() { alert(1); }
    return this
}
Foo.getName = function() { alert(2); }
Foo.prototype.getName = function() { alert(3); }
var getName = function () { alert(4); }
function getName() { alert(5); }

// 输出值
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName()
new Foo().getName()
new new Foo().getName()

// 输出结果为
// 2
// 4
// 1
// 1
// 2
// 3
// 3

Выходное значение анализируется следующим образом:

  1. Foo.getName()Выход равен 2, осуществляется доступ к статическому свойству функции Foo, и выход равен 2.

    Теперь, пытаясь определить функцию getName внутри функции и привязать функцию getName к прототипу Foo, оба не смогли успешно выполниться.Foo.getName(), а после создания объекта в буквальном виде его можно выполнить нормальноgetName()функция.

尝试

Запустить, создав объектgetName()Определение внутри функции не работает должным образом, даже если это глобальная переменная.

尝试

Вывод: поскольку функции сами по себе являются объектами, связывание свойств и методов через функции принадлежитстатический метод, который можно вызвать напрямую. Свойства и методы, привязанные к прототипу, можно вызывать только после создания объекта, а методы, определенные внутри объекта-конструктора, нельзя вызывать через объект.

  1. getName();Результат 4 вместо 5. Это потому, что JS существуетПодъем объявления переменной(Все объявленные переменные или объявленные функции поднимаются на вершину текущей функции).

    Таким образом, порядок выполнения кода следующий:

    var getName;
    function getName() { alert(5); }
    // ... 省略代码
    getName = function () { alert(4) }
    

    окончательное исполнениеgetNameвыход 4

    Расширенная тема:

    console.log( Foo )
    function Foo() {
        console.log(1);
    }
    var Foo = 1
    

    Каков результат Foo?

  2. Foo().getName();Выходное значение равно 1, сначала выполните функцию Foo(), определите глобальную переменную getName, а затем вызовите функцию глобального объекта.getName()метод возвращает 1.

    Уведомление,Foo()возвращается функциейthisОн указывает на окно глобального объекта, поэтому глобальный объект вызываетсяgetName(). getName в функции привязан к глобальному объекту, и вызов его через Foo сообщит об ошибке.

    Выполнение этого оператора в узле сообщит об ошибке, поскольку узел не имеет окна глобального объекта, поэтому нельзя вызвать getName.

  3. getName()вызвать глобальную функцию, потому что выполнениеFoo(), обновляет значение getName, поэтому оно возвращает 1.

  4. new Foo.getName()Проверяется приоритет операторов..имеет более высокий приоритет, чем новый, что эквивалентно выполнениюnew (Foo.getName)(), что эквивалентно выполнению конструктора getName, возвращающего 2

  5. new Foo().getName()Метод выполнения(new Foo()).getName()Сначала создайте объект Foo, затем выполнитеgetName()функция. существуетnew Foo()Возвращается только что созданный пустой объект.Поскольку объект еще не связал свойство getName, в это время вызывается getName на прототипе, и результат возвращает 3

    Примечание: конструкторreturn this, при выполнении new возвращается только что созданный объект.

    Расширенная тема:

    function A() {
        this.a = 2;
        function B() {
            this.a = 1;
        }
        return B();
    }
    console.log(new A());
    

    Каково значение a? Еслиreturn new B();Какова ценность а?

  6. new new Foo().getName()можно переписать какnew ((new Foo()).getName)()Сначала инициализируйте экземпляр, затем выполните getName() для объекта-прототипа в качестве конструктора, и результат вернет 3.

Окончательный код может быть оптимизирован для

var getName;
function getName() { alert(5); }
function Foo() {
    getName = function() { alert(1); }
    return this
}
Foo.getName = function() { alert(2); }
Foo.prototype.getName = function() { alert(3); }
getName = function () { alert(4); }

Foo.getName(); // 2
getName(); // 4
Foo();
getName(); // 1
getName(); // 1
Foo.getName(); // 2
(new Foo()).getName(); // 3
(new Foo()).getName(); // 3