Не стоит недооценивать себя, но этот вопрос действительно сложный

JavaScript

Сегодня друг передал мне вопрос и попросил помочь объяснить его.

Когда я увидел заголовок, то на первый взгляд подумал, что он простой, но чем больше я читал вопрос, тем больше запутывался.

var age = 10;
var person={
   age:20,
   getAge(){
       var age = 30;
       return this.age;
    },
};
alert(age,age*2);

person.getAge(); 

var b = person.getAge;
b(); 

(person.getAge)(); 

(1,person.getAge)();

(1,person.getAge.bind(person))();

(person.getAge,person.getAge)();

(person.getAge=person.getAge)();

person.getAge.call(); 

person.getAge.call(person);

function getAge2() {
    this.age = 40;
    console.log(person.getAge());
};
getAge2();
console.log(age);

function getAge3(){
    this.age = 50;
    this.getAge4 = ()=>{
        console.log(person.getAge.call(this));
    }
}
new getAge3().getAge4();
console.log(age);

function getAge4(){
    this.age = 60;
    this.getAge5 = ()=>{
    console.log(person.getAge.call(this));
    }
}
new getAge4().getAge5();
console.log(age);

var age2 = 10;
var person2={
   age2:20,
   getAge2:()=>{
       var age2 = 30;
       return this.age2;    
    },
};
console.log(person2.getAge2.call());
console.log(person2.getAge2.call(person2));

Конечно, я получил много неправильных ответов...

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

Ключом к ответу на эти вопросы является глубокое понимание this и выражений с запятыми.

Во-первых, мы кратко рассмотрим эти два очень важных знания. Наконец, посмотрите на всеобъемлющую тему в конце статьи.

this

это очень важно в js. В письменном тесте, если есть проверка базовых знаний, то вероятность его появления, как правило, невысока.

Обычная функция

Одним словом: тот, кто это называет, указывает на кого угодно.

var person={
   age:20,
   getAge(){
       var age = 30;
       return this.age;
    },
};
person.getAge(); // 20

Метод getAge вызывается человеком, поэтому он указывает на человека, а вывод person.age равен 20;

стрелочная функция

Одним словом: на кого указывает звонящий, на кого указывает.

var age = 10;
var person={
   age:20,
   getAge:()=>{
       var age = 30;
       return this.age;
    },
};
person.getAge(); // 10

Этот метод getAge вызывается человеком, затем getAge и person указывают на одну и ту же точку, person вызывается окном (обратитесь к приведенной выше обычной функции), поэтому человек указывает на окно, поэтому getAge также указывает на окно и выводит 10.

Принудительно изменить это, чтобы указать на

Одним словом: вы указываете на того, кого вы говорите.

Чтобы изменить эту точку, существует несколько методов вызова, применения и привязки.

var age = 10;
var person={
   age:20,
   getAge:function(){
       var age = 30;
       return this.age;
    },
};
person.getAge.call(person);

Здесь, когда выполняется метод getAge, передается человек, затем this из getAge указывает на человека, поэтому выводится 20.

запятая выражение

Оператор запятой

(http://www.ecma-international.org/ecma-262/#sec-abstract-operations)

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

function test(){
    let a=1;
    return ++a,a++,a++;
}
console.log(test());

Здесь запятые используются для разделения выражений, что эквивалентно:

function test(){
    let a=1;
    ++a;
    a++;
    return a++;
}
console.log(test());

Естественно ответ само собой, это 3, т.к. за return следует a++, если это ++a, то результат 4 (тут я не совсем понял, учите "оператор ++" сами) .

Посмотрите еще раз на оригинальное название

Далее, давайте ответим на вышеуказанные вопросы один за другим, и я опубликую вопрос снова.

var age = 10;
var person={
   age:20,
   getAge(){
       var age = 30;
       return this.age;
    },
};

alert(age,age*2)

Список, разделенный запятыми, — это списки аргументов, поскольку alert принимает только один параметр, первый параметр, а остальные игнорируются. Таким образом, всплывающее окно равно 10.

var b = person.getAge; b();

Выходной результат равен 10, в основном для того, чтобы отличить person.getAge(), разница в том, что в данный момент он присваивается переменной b, а затем выполняет b().

Эквивалентно:

var b = person.getAge; 
window.b(); 

Возвращаясь к предыдущему пункту знаний, [кто звонит, кто указывает на], после присвоения переменной здесь, это окно вызывает метод b, так что это указывает на окно, и ответ равен 10.

(person.getAge)();

Скобки здесь служат только для разделения и не имеют практического значения, они эквивалентны person.getAge(). Итак, ответ 20;

(1,person.getAge)();

Отличие этой темы от предыдущей заключается во введении запятых. Мы знаем, что выражение с запятой возвращает последнее значение — person.getAge.Обратите внимание, что это возвращаемое значение выражения.

Эквивалентно:

var a = (1,person.getAge);
a();

или:

var a = (false||person.getAge);
a();

Очевидно, что здесь вызывает окно, поэтому ответ равен 10. Обратите внимание, что это нестрогий режим.

Если следующие темы связаны с различиями в режимах, они обычно относятся к нестрогому режиму.Важное различие между нестрогим режимом и строгим режимом заключается в том, будет ли он изменен, чтобы указывать на окно, когда оно равно null или не определено. В нестрогом режиме он будет изменен, чтобы указывать на окно, а строгий режим по-прежнему останется нулевым или неопределенным.

"use strict"; 
var age = 10;
var person={
   age:20,
   getAge(){
       var age = 30;
       return this.age;
    },
};
console.log(person.getAge());// 输出仍然是 20,this 指针指向 person
var a = (1,person.getAge);
a();//  Cannot read property 'age' of undefined , this 是 undefined

(1,person.getAge.bind(person))();

Этот вопрос является точкой знания выражения запятой и привязки.Ссылаясь на приведенный выше анализ, он эквивалентен:

var a =(1,person.getAge.bind(person));
a();

Разница между этим и предыдущим заключается в том, что после привязки возвращается функция, а метод a был вынужден указывать на человека, поэтому он эквивалентен:

person.getAge.bind(person)()

Ответ 20, это указывает на человека.

(person.getAge,person.getAge)();

На самом деле это выражение с запятой, которое возвращает значение последнего элемента.Здесь два person.getAge устанавливаются последовательно, что является просто ловушкой.Предыдущее person.getAge не влияет на результат. Он настаивал на том, чтобы гора Циншань не расслаблялась, и твердо устранил ловушку.

Эквивалентно:

(1,person.getAge)();

Ответ, как и выше, равен 10.

(person.getAge=person.getAge)();

Здесь немного по-другому, то есть: для объекта person установите для него свойство getAge (если есть свойство getAge, переназначьте его), и назначьте это свойство getAge с помощью person.getAge .

Внутри круглых скобок находится выражение присваивания, а возвращаемое значение выражения — это свойство getAge в объекте person, который был переназначен person.getAge .

Эквивалентно:

var person.getAge = person.getAge // 赋值
var a = person.getAge;  // 表达式返回值
a();

Это было объяснено выше, поэтому выход равен 10.

person.getAge.call();person.getAge.call(person);

Здесь функция вызова используется для изменения указателя this. Когда параметр области не передается, это не определено в строгом режиме, здесь нестрогий режим.

call, apply, bind могут изменить указатель this следующим образом:

// 10  call 为空,this 为 undefined,重新指向为 window
person.getAge.call();
// 20 this 指针指向 person
person.getAge.call(person); 

Большая тема в конце

Тема 1

function getAge2() {
    this.age = 40;
    console.log(person.getAge());// 20
};
getAge2();
console.log(age);// 40

Person.getAge внутри по-прежнему указывает, кто вызывает и кого выполняет, this метода person.getAge указывает на человека, а вывод равен 20. Но внутри есть задание this.age=40.

Так что же это? Конечно кто кому звонит, getAge2 здесь вызов окна, так это здесь окно.

Тогда это эквивалентно изменению возраста внешнего слоя на 40, поэтому console.log(age) стал 40.

Тема 2

function getAge3(){
    this.age = 50;
    this.getAge4 = ()=>{
        console.log(person.getAge.call(this));// 50
    }
}
new getAge3().getAge4();
console.log(age); // 40

В getAge3 определен общедоступный метод getAge4, но здесь есть стрелочная функция, которая использует call для изменения указателя this функции person.getAge, чтобы он указывал на текущий this, так где же текущая точка this?

Еще предстоит узнать, кто вызвал getAge4, вот экземпляр new getAge3(), который вызывает getAge4, так что this, переданный вызовом, указывает на new getAge3(), где this.age=50 присваивается 50, поэтому вывод 50.

Но глобальный возраст не изменился.В отличие от вопроса 1, здесь он указывает на экземпляр объекта, а не на окно, поэтому глобальный возраст по-прежнему равен 40.

Вопрос 3

Читая это, вы, возможно, вдруг стали просветленными и почувствовали, что очень хорошо это понимаете, поэтому вы ответите на этот вопрос?

var age2 = 10;
var person2={
   age2:20,
   getAge2:()=>{
       var age2 = 30;
       return this.age2;
    },
};
console.log(person2.getAge2.call()); // 10
console.log(person2.getAge2.call(person2)); // 10

Основное отличие состоит в том, что функция getAge2 использует функцию стрелки. Как было сказано выше, стрелочная функция this указывает на person2 ?

неправильно! Не так.

На самом деле у стрелочной функции нет собственного this, а раз его нет, то как вызов может изменить свой указатель this?

Справочная документация: (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)

Таким образом, ни call(), ни call(person2) выше не могут изменить указатель this, поэтому оба выводят глобальное значение 10.

End

Давайте рассмотрим другой вопрос, это функции стрелок.

var age = 10;
var person={
   age:20,
   child:{
    age:40,
    getAge:function(){
       return this.age;
    },
   },
   child2:{
    age:40,
    getAge:()=>{
       return this.age;
    },
   },
   child3:function(){
    this.getAge = ()=>{
        return this.age;
    }
   }
};
console.log(person.child.getAge());// 40
console.log(person.child2.getAge()); // 10
console.log((new person.child3()).getAge()); // undfined

Согласно нашим знаниям выше, мы можем знать, что this из person.child.getAge() — это кто кому звонит, вот дочерний вызов, поэтому он указывает на дочерний элемент и выводит 40 .

Мы знаем, что у стрелочных функций нет собственного this, так что же это такое?

То есть, текущая стрелочная функция ищется вверх уровень за уровнем, и если это значение области действия функции найдено, то это значение текущей стрелочной функции.

Таким образом, родительский объект, вызывающий функцию person.child2.getAge, здесь — это child2, но child2 — это объект и не имеет собственного this и области видимости, поэтому продолжайте поиск человека, а затем найдите, что этот человек также является объектом, и затем продолжайте смотреть вверх, чтобы найти окно «Этот большой босс», так что это указывает на окно, и результат равен 10.

(это new person.child3()). не имеет атрибута возраста, поэтому выведите undefined.

Эти вопросы, действительно трудно! Если вы не понимаете, посмотрите на несколько ответов, я верю, что вы вдруг увидите свет! Или количество общественного внимания, плюс микро-канал, один ответ.

Добро пожаловать в мое общественное число WeChat, сделайте это вместе!

follow-me