кончик
Прежде всего, я знаю, что эта статья скучна, это не что иное, как в JS, и были тысячи статей, написавших эту часть;
Тем не менее, я все еще хочу написать статью об этом в JS, которая может рассматриваться как краткое изложение; (Боги могут ходить и прочитать другие мои статьи)
В JS контекст этого всегда непредсказуем, и часто ошибки всегда запутываются. На самом деле, пока вы четко различаете, как выполнять в разных обстоятельствах, все будет в порядке.
Глобальное исполнение
Во -первых, давайте посмотрим на то, что это в глобальной среде:
первый. Браузер:
console.log (this); // window {SpeechSyntheesis: SpeechSyntheesis, Caches: Cachestorage, LocalStorage: Storage, SessionStorage: Storage, WebkitStorageInfo: устаревший storageInfo…}Вы можете видеть, что окно -объект напечатан;
второй. узел:
console.log (это); // глобальный
Вы можете видеть, что глобальный объект напечатан;
Резюме: В глобальном объеме это выполняет текущий глобальный объект (окно в браузере, Global in Node).
Выполнять в функции
Чистые вызовы функций
Это наиболее распространенный способ использовать функцию:
Функциональный тест () {console.log (this);}; test (); // window {speechSyntheesis: SpeechSyntheesis, Caches: Cachestorage, LocalStorage: Storage, SessionStorage: Storage, WebKitStorageInfo: OperecatedStorageInfo…}Мы видим, что когда функция называется напрямую, она принадлежит к глобальному вызову, и в настоящее время это указывает на глобальный объект;
Строгий режим «использовать строго»;
Если чистые функциональные вызовы выполняются в строгом режиме, то это здесь не указывает на глобальный, но не определен. Это должно устранить некоторое необычное поведение в JS:
'Использовать strict'; function test () {console.log (this);}; test (); // не определенноеКонечно, поставить его в непосредственную функцию выполнения было бы лучше, избегая загрязнения глобальной ситуации:
(function () {"strict"; console.log (this);}) (); // не определенноеМетод вызов в качестве объекта
Когда функция называется методом объекта:
var obj = {name: 'qiutc', foo: function () {console.log (this.name); }} obj.foo (); // 'Qiutc'В настоящее время это указывает на текущий объект;
Конечно, мы можем сделать это:
Function test () {console.log (this.name);} var obj = {name: 'qiutc', foo: test} obj.foo (); // 'qiutc'Также неизменно, потому что в JS все является объектом, а функция также является объектом. Для теста это просто имя функции, ссылка на функцию, которая указывает на эту функцию. Когда Foo = test, Foo также указывает на эту функцию.
Что если вы назначите метод объекта переменной, а затем напрямую вызовите эту переменную:
var obj = {name: 'qiutc', foo: function () {console.log (this); }} var test = obj.foo; test (); // windowВидно, что это выполняет глобальный мир в это время. Когда мы размещаем тест = obj.foo, тест напрямую указывает на ссылку на функцию. В настоящее время это на самом деле не имеет ничего общего с объектом OBJ, поэтому он называется непосредственно как обычная функция, поэтому эта точка для глобального объекта.
Некоторые подводные камни
Мы часто сталкиваемся с некоторыми ловушками в функциях обратного вызова:
var obj = {name: 'qiutc', foo: function () {console.log (this); }, foo2: function () {console.log (this); setTimeout (this.foo, 1000); }} obj.foo2 ();После выполнения этого кода мы обнаружим, что распечатки отличаются друг от друга:
В первый раз - печатать это непосредственно в FOO2, указывая на объект OBJ здесь, у нас нет сомнений;
Тем не менее, это. Разве это не используется в качестве метода функции здесь? Это часто зажигает много новичков;
На самом деле, SetTimeout - это просто функция, и функции могут потребоваться параметры. Мы передаем это. POO в качестве параметра функции SetTimeout, точно так же, как это требует забавный параметр. При прохождении параметра мы фактически сделали такую операцию Fun = this.foo. Видя, что нет, мы прямо указываем на ссылку на это. При выполнении Fun () фактически выполняется, поэтому это не имеет ничего общего с OBJ. Он называется непосредственно как обычная функция, поэтому это указывает на глобальный объект.
Эта проблема обычно встречается во многих асинхронных функциях обратного вызова;
решать
Чтобы решить эту проблему, мы можем использовать функцию закрытия, чтобы справиться с ней:
var obj = {name: 'qiutc', foo: function () {console.log (this); }, foo2: function () {console.log (this); var _this = это; setTimeout (function () {console.log (this); // window console.log (_this); // Object {name: "qiutc"}}, 1000); }} obj.foo2 ();Вы можете видеть, что использование этого напрямую все еще окно; Поскольку это в FOO2 указывает на OBJ, мы можем сначала использовать переменную _this для ее хранения, а затем использовать _this в функции обратного вызова, чтобы указывать на текущий объект;
Еще одна яма Settimeout
Как упоминалось ранее, если функция обратного вызова выполняется непосредственно без привязки привязки, то это эта точка для глобального объекта (окно), что будет указывать на неопределенную в строгом режиме. Тем не менее, функция обратного вызова в SetTimeout показывает разные в строгом режиме:
'Использовать strict'; function foo () {console.log (this);} settimeout (foo, 1); // windowГоворя по логике, мы добавили строгий режим, и вызов Foo не указал это, поэтому он должен быть не определен, но здесь все еще есть глобальный объект. Это потому, что строгий режим не удался?
Нет, даже в строгом режиме, когда метод SetTimeout вызывает входящую функцию, если функция не указывает это, он выполнит неявную операцию - автоматически вводить глобальный контекст, который эквивалентен вызову foo.apply (window) вместо foo ();
Конечно, если мы уже указываем это при прохождении в функции, то мы не будем введены в глобальный объект, такой как: settimeout (foo.bind (obj), 1) ;;
Используйте в качестве конструктора
В JS, чтобы реализовать класс, нам нужно определить некоторые конструкторы, и при вызове конструктора необходимо добавить ключевое слово, новое слово:
Функция человека (имя) {this.name = name; console.log (this);} var p = new Person ('qiutc'); // person {name: "qiutc"}Мы можем видеть, что, когда называется конструктором, это указывает на объект, созданный при создании этого конструктора;
Конечно, конструктор на самом деле является функцией. Если мы выполним его как обычную функцию, это все равно будет выполняться глобально:
Функция человека (имя) {this.name = name; console.log (this);} var p = person ('qiutc'); // windowРазница в том, как вызвать функцию (новую).
Функция стрелки
В новой спецификации ES6 была добавлена функция стрелки. Самое отличное от обычных функций - это указание. Вы помните, что мы используем закрытие для решения этой проблемы с указанием? Если мы используем функцию стрелки, мы можем решить ее более идеально:
var obj = {name: 'qiutc', foo: function () {console.log (this); }, foo2: function () {console.log (this); setTimeout (() => {console.log (this); // Object {name: "qiutc"}}, 1000); }} obj.foo2 ();Как вы можете видеть, в функции, выполненной SetTimeout, она должна была быть распечатана в окне, но это указывает на OBJ здесь. Причина в том, что функция (параметр), передаваемая в Settimeout, является функцией стрелки:
Этот объект в корпусе функции - это определенный объект, а не объект, который используется.
Основываясь на примерах, давайте поймем это предложение:
Когда выполняется obj.foo2 (), текущий это указывает на OBJ; При выполнении SetTimeout мы сначала определяем функцию анонимной стрелки, и ключевой момент здесь. Объект в функции стрелки, в которой это выполняется при определении этой функции стрелки, указывает на это по объему при определении этой функции стрелки, то есть в obj.foo2, то есть obj; Таким образом, при выполнении функции стрелки это -> obj в obj.foo2 -> obj;
Проще говоря, это в функции стрелки связано только с этим в области применения при ее определении, и не имеет ничего общего с тем, где и как она называется. В то же время, это указание неизменно.
позвонить, применить, привязать
В JS функции также являются объектами, а также есть некоторые методы. Здесь мы вводим три метода, они могут изменить этот указатель в функции:
вызов
fun.call (thisarg [, arg1 [, arg2 [, ...]]])
Он немедленно выполнит функцию. Первый параметр указывает контекст этого в функции выполнения, а последующий параметр - это параметры, которые необходимо пройти в функции выполнения;
применять
fun.apply (thisarg [, [arg1, arg2, ...]])
Он немедленно выполнит функцию. Первый параметр указывает контекст этого в функции выполнения, а второй параметр - это массив, который является параметром, передаваемым функции выполнения (разница от вызова);
связывать
var foo = fun.bind (thisarg [, arg1 [, arg2 [, ...]]]);
Он не выполняет функцию, но возвращает новую функцию. Эта новая функция указывает контекст этого, и последующие параметры - это параметры, которые необходимо передавать для выполнения функции;
Эти три функции на самом деле похожи. Общая цель - указать контекст функции (это). Давайте возьмем функцию вызова в качестве примера;
Укажите это для нормальной функции
var obj = {name: 'qiutc'}; function foo () {console.log (this);} foo.call (obj); // Object {name: "qiutc"}Можно видеть, что при выполнении foo.call (obj) это в функции указывает на объект OBJ, который является успешным;
Укажите это для метода в объекте
var obj = {name: 'qiutc', foo: function () {console.log (this); }} var obj2 = {name: 'tcqiu2222222'}; obj.foo.call (obj2); // Object {name: "tcqiu222222"}Вы можете видеть, что при выполнении функции это точки для OBJ2, что является успешным;
Укажите это для конструктора
Функция человека (имя) {this.name = name; console.log (this);} var obj = {name: 'qiutc22222222'}; var p = new Person.call (obj, 'qiutc'); // uncauthЗдесь сообщалась об ошибке, потому что мы ходили на новое лицо. Функция, а не на человека, и функция здесь не является конструктором;
Изменить, чтобы связать и попробовать:
Функция человека (имя) {this.name = name; console.log (this);} var obj = {name: 'qiutc22222222'}; var person2 = person.bind (obj); var p = new Person2 ('qiutc'); // person {name: "qiutc"} console.log (obj); // objТо, что напечатано, является объектом, созданным человеком, который не имеет ничего общего с OBJ, и OBJ не изменился, указывая на то, что мы указываем этот контекст человеку, не вступая в силу;
Следовательно, можно сделать вывод, что использование BIND для указания этого для конструктора. Когда новый конструктор, это указано по функции связывания, не вступит в силу;
Конечно, BIND может не только указать это, но и передавать параметры. Попробуем эту операцию:
Функция человека (имя) {this.name = name; console.log (this);} var obj = {name: 'qiutc22222222'}; var person2 = person.bind (obj, 'Qiutc1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111Как вы можете видеть, хотя указание этого не работает, входящие параметры все еще работают;
Укажите это для функции стрелки
Давайте определим функцию стрелки в глобальном уровне, поэтому эта функция стрелки неизбежно будет указывать на глобальный объект. Что если это изменилось с помощью метода вызова:
var afoo = (a) => {console.log (a); console.log (this);} afoo (1); // 1 // windowvar obj = {name: 'qiutc'}; afoo.call (obj, 2); // 2 // окноКак вы можете видеть, операция вызова, указывающего на это здесь, не была успешной, поэтому можно сделать вывод , что это в функции стрелки уже решило при его определении (выполняйте это в области, которая определяет его), и не имеет ничего общего с тем, как его назвать и куда его назвать. Никакие операции, включая (вызов, применение, привязку) и другие операции не могут изменить это.
Просто помните, что функция стрелки хороша, и это остается неизменным.
Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.