dica
Primeiro de tudo, sei que este artigo é chato, nada mais é do que isso no JS, e houve milhares de artigos escrevendo essa parte;
No entanto, ainda quero escrever um artigo sobre isso no JS, que pode ser considerado um resumo; (Os deuses podem dar a volta e ler meus outros artigos)
No JS, o contexto disso é sempre imprevisível e muitas vezes os bugs estão sempre confusos. De fato, desde que você distingue claramente como executar em diferentes circunstâncias, tudo bem.
Execução global
Primeiro, vamos dar uma olhada no que isso é no ambiente global:
primeiro. Navegador:
console.log (this); // Window {SpeechSynthesis: SpeechSynthesis, Caches: CacheStorage, LocalStorage: Storage, SessionStorage: Storage, WebkitStorageInfo: DeprecatedStorageInfo…}Você pode ver que o objeto da janela está impresso;
segundo. nó:
console.log (this); // global
Você pode ver que o objeto global está impresso;
Resumo: No escopo global, ele executa o objeto global atual (janela no navegador, global no nó).
Executar na função
Chamadas de função pura
Esta é a maneira mais comum de usar a função:
function test () {console.log (this);}; test (); // janela {speechSynthesis: speechSynthesis, cache: cachestorage, localStorage: armazenamento, sessionStorage: armazenamento, webkitStorageInfo: deprecatedestorageInfo…}Podemos ver que, quando uma função é chamada diretamente, ela pertence a uma chamada global e, neste momento, isso aponta para o objeto global;
Modo rigoroso 'Use Strict';
Se as chamadas de função pura forem executadas no modo rigoroso, isso aqui não apontará para o global, mas é indefinido. Isso é para eliminar algum comportamento não revigoroso no JS:
'Use Strict'; function test () {console.log (this);}; test (); // indefinidoObviamente, colocá -lo em uma função de execução imediata seria melhor, evitando poluir a situação global:
(function () {"use Strict"; console.log (this);}) (); // indefinidoChamada de método como objeto
Quando uma função é chamada de método de um objeto:
var obj = {name: 'qiutc', foo: function () {console.log (this.name); }} obj.foo (); // 'qiutc'Neste momento, isso aponta para o objeto atual;
Claro, podemos fazer isso:
function test () {console.log (this.name);} var obj = {name: 'qiutc', foo: test} obj.foo (); // 'qiutc'Também inalterado, porque no JS tudo é um objeto, e uma função também é um objeto. Para teste, é apenas um nome de função, uma referência à função, que aponta para essa função. Quando foo = teste, Foo também aponta para essa função.
E se você atribuir o método do objeto a uma variável e, em seguida, chame essa variável diretamente:
var obj = {name: 'qiutc', foo: function () {console.log (this); }} var test = obj.foo; test (); // janelaPode -se observar que isso executa o mundo global neste momento. Quando colocamos teste = obj.foo, o teste aponta diretamente para uma referência a uma função. Neste momento, na verdade não tem nada a ver com o objeto OBJ, por isso é chamado diretamente como uma função comum; portanto, isso aponta para o objeto global.
Algumas armadilhas
Muitas vezes encontramos algumas armadilhas nas funções de retorno de chamada:
var obj = {name: 'qiutc', foo: function () {console.log (this); }, foo2: function () {console.log (this); setTimeout (this.foo, 1000); }} obj.foo2 ();Depois de executar este código, descobriremos que as impressões são diferentes uma da outra:
A primeira vez é imprimir isso diretamente no Foo2, apontando para o objeto OBJ aqui, não temos dúvidas;
No entanto, este.foo executado no setTimeout aponta para o objeto global. Não é usado como um método de função aqui? Isso muitas vezes intriga muitos iniciantes;
De fato, o setTimeout é apenas uma função e a função pode precisar de parâmetros. Passamos isso. Ao passar no parâmetro, na verdade fizemos essa operação divertida = this.foo. Vendo que não há, apontamos diretamente a diversão para a referência disso. Ao executar, Fun () é realmente executado, por isso não tem nada a ver com OBJ. É chamado diretamente como uma função comum, então isso aponta para o objeto global.
Esse problema é comumente encontrado em muitas funções assíncronas de retorno de chamada;
resolver
Para resolver esse problema, podemos usar o recurso de fechamento para lidar com ele:
var obj = {name: 'qiutc', foo: function () {console.log (this); }, foo2: function () {console.log (this); var _This = this; setTimeout (function () {console.log (this); // Window Console.log (_This); // Objeto {name: "qiutc"}}, 1000); }} obj.foo2 ();Você pode ver que usar isso diretamente ainda é janela; Como isso no Foo2 aponta para o OBJ, podemos primeiro usar uma variável _ Isso para armazená -la e depois usar _ Isso na função de retorno de chamada para apontar para o objeto atual;
Outro poço de Settimeout
Como mencionado anteriormente, se a função de retorno de chamada for executada diretamente sem o escopo vinculativo, é esse ponto para o objeto global (janela), que apontará indefinido no modo rigoroso. No entanto, a função de retorno de chamada no setTimeout mostra diferente no modo rigoroso:
'Use Strict'; function foo () {console.log (this);} setTimeout (foo, 1); // janelaLogicamente falando, adicionamos modo rigoroso e a chamada Foo não especificou isso, por isso deve ser indefinida, mas ainda existe um objeto global aqui. É porque o modo rigoroso falhou?
Não, mesmo no modo rigoroso, quando o método Settimeout chama a função de entrada, se a função não especificar isso, ela fará uma operação implícita - injetar automaticamente o contexto global, que é equivalente a chamar foo.apply (janela) em vez de foo ();
Obviamente, se já especificarmos isso ao passar na função, não seremos injetados no objeto global, como: setTimeout (foo.bind (obj), 1) ;;
Use como construtor
No JS, para implementar a classe, precisamos definir alguns construtores, e a palavra -chave nova é necessária para ser adicionada ao chamar um construtor:
função pessoa (nome) {this.name = name; console.log (this);} var p = nova pessoa ('qiutc'); // pessoa {name: "qiutc"}Podemos ver que, quando chamado como construtor, isso aponta para o objeto instanciado quando esse construtor é chamado;
Obviamente, o construtor é realmente uma função. Se o executarmos como uma função normal, isso ainda será executado globalmente:
função pessoa (nome) {this.name = name; console.log (this);} var p = pessoa ('qiutc'); // janelaA diferença é como chamar a função (nova).
Função de seta
Na nova especificação ES6, uma função de seta foi adicionada. A coisa mais diferente das funções comuns é isso. Você se lembra de que usamos fechamentos para resolver esse problema de apontamento? Se usarmos a função de seta, podemos resolvê -la mais perfeitamente:
var obj = {name: 'qiutc', foo: function () {console.log (this); }, foo2: function () {console.log (this); setTimeout (() => {console.log (this); // objeto {name: "qiutc"}}, 1000); }} obj.foo2 ();Como você pode ver, na função executada pelo setTimeout, ela deveria ter sido impressa na janela, mas isso aponta para o OBJ aqui. O motivo é que a função (parâmetro) passada para o setTimeout é uma função de seta:
Este objeto no corpo da função é o objeto definido, não o objeto que é usado.
Com base em exemplos, vamos entender esta frase:
Quando obj.foo2 () é executado, a corrente esse aponta para OBJ; Ao executar o setTimeout, primeiro definimos uma função de seta anônima e o ponto principal está aqui. O objeto na função de seta em que isso é executado ao definir essa função de seta é apontado para esse escopo ao definir essa função de seta, ou seja, isso em obj.foo2, ou seja, obj; Então, ao executar a função de seta, é isso -> obj em obj.foo2 -> obj;
Simplificando, isso na função de seta está relacionada apenas a isso no escopo ao defini -lo e não tem nada a ver com onde e como é chamado. Ao mesmo tempo, este apontando é imutável.
Ligue, aplique, vincule
No JS, as funções também são objetos e também existem alguns métodos. Aqui introduzimos três métodos, eles podem mudar este ponteiro na função:
chamar
fun.call (thisarg [, arg1 [, arg2 [, ...]]])
Ele executará a função imediatamente. O primeiro parâmetro especifica o contexto disso na função de execução, e o parâmetro subsequente são os parâmetros que precisam ser passados na função de execução;
aplicar
fun.apply (thisarg [, [arg1, arg2, ...]])
Ele executará a função imediatamente. O primeiro parâmetro especifica o contexto disso na função de execução, e o segundo parâmetro é uma matriz, que é o parâmetro passado para a função de execução (a diferença da chamada);
vincular
var foo = fun.bind (thisarg [, arg1 [, arg2 [, ...]]]);
Ele não executa a função, mas retorna uma nova função. Esta nova função especifica o contexto disso, e os parâmetros subsequentes são os parâmetros que precisam ser transmitidos para executar a função;
Essas três funções são realmente semelhantes. O objetivo geral é especificar o contexto de uma função (isso). Vamos assumir a função de chamada como exemplo;
Especifique isso para uma função normal
var obj = {name: 'qiutc'}; function foo () {console.log (this);} foo.call (obj); // objeto {name: "qiutc"}Pode -se observar que, ao executar foo.call (obj), isso na função aponta para o objeto OBJ, que é bem -sucedido;
Especifique um isto para o método no objeto
var obj = {name: 'qiutc', foo: function () {console.log (this); }} var obj2 = {nome: 'tcqiu2222222'}; obj.foo.call (obj2); // objeto {name: "tcqiu222222"}Você pode ver que, ao executar a função, isso aponta para o Obj2, que é bem -sucedido;
Especifique isso para o construtor
função pessoa (nome) {this.name = name; console.log (this);} var obj = {name: 'qiutc22222222'}; var p = new Person.Call (obj, 'qiutc'); // não -Esgotado TypeError: Person.Call não é um construtor (…)Um erro foi relatado aqui porque fomos à nova pessoa.
Mude para vincular e tentar:
função pessoa (nome) {this.name = name; console.log (this);} var obj = {name: 'qiutc22222222'}; var pessoa2 = pessoa.bind (obj); var p = new Person2 ('qiutc'); // pessoa {nome: "qiutc"} console.log (obj);O que é impresso é o objeto instanciado pela pessoa, que não tem nada a ver com OBJ, e o OBJ não mudou, indicando que especificamos esse contexto para a pessoa sem entrar em vigor;
Portanto, pode -se concluir que o uso do Bind para especificar isso para um construtor. Quando o novo construtor, este especificado pela função de ligação não entrará em vigor;
Obviamente, o BIND pode não apenas especificar isso, mas também passa parâmetros. Vamos tentar esta operação:
função pessoa (nome) {this.name = name; console.log (this);} var obj = {name: 'qiutc22222222'}; var pessoa2 = pessoa.bind (obj, 'qiutc111111'); var p = new Person2 ('qiutc'); // Pessoa {Nome: "Qiutc1111111111"}}Como você pode ver, apesar de especificar isso não funcionar, os parâmetros de entrada ainda funcionam;
Especifique isso para a função de seta
Vamos definir uma função de seta sob o global; portanto, isso nesta função de seta inevitavelmente apontará para o objeto global. E se isso for alterado usando o método de chamada:
var afoo = (a) => {console.log (a); console.log (this);} afo (1); // 1 // windowvar obj = {name: 'qiutc'}; afoo.call (obj, 2); // 2 // janelaComo você pode ver, a operação da chamada apontando para isso aqui não foi bem -sucedida; portanto, pode -se concluir que isso na função de seta já decidiu quando a definir (execute isso no escopo que o define) e não tem nada a ver com como chamá -lo e onde chamá -lo. Nenhuma operações, incluindo (ligue, aplicar, vincular) e outras operações, não pode alterar isso.
Lembre -se de que a função de seta é boa e isso permanece inalterado.
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.