JavaScript isso aponta para o princípio

Cenário 1: isso no ambiente global

Essa situação é relativamente simples e direta. A função é simplesmente chamada no ambiente global do navegador e thisapontada em modo não restrito window; no use strictcaso de especificar o modo estrito, é undefined:

function f1 () {
    console.log(this)
}
function f2 () {
    'use strict'
    console.log(this)
}
f1() // window
f2() // undefined 

Essas perguntas são relativamente básicas, mas se você estiver entrevistando, os candidatos precisam prestar atenção especial às suas variantes (por que sempre existem perguntas chatas e pervertidas), leia novamente:

const foo = {
    bar: 10,
    fn: function() {
       console.log(this)
       console.log(this.bar)
    }
}
var fn1 = foo.fn
fn1()

Aqui thisainda está apontando para o arquivo window. Embora fna função fooseja referenciada como um método no objeto, após ser atribuída a ela fn1, fn1sua execução ainda ocorre no windowambiente global. Portanto, a saída windowe undefined, ainda o problema acima, se a chamada for alterada para:

const foo = {
    bar: 10,
    fn: function() {
       console.log(this)
       console.log(this.bar)
    }
}
foo.fn() 

irá produzir:

{bar: 10, fn: ƒ}
10

Na verdade, isso pertence ao segundo caso, porque neste momento thisele aponta para o objeto que o chamou por último e aponta para o objeto foo.fn()na instrução . Lembre-se: Ao executar uma função, se o objeto na função for chamado pelo objeto de nível superior, ele apontará para o objeto de nível superior; caso contrário, ele apontará para o ambiente global.thisfoothisthis

Cenário 2: isso na chamada de objeto de contexto

Vamos olhar diretamente para o "difícil": quando há uma relação de chamada mais complicada,

const person = {
    name: 'Lucas',
    brother: {
        name: 'Mike',
        fn: function() {
            return this.name
        }
    }
}
console.log(person.brother.fn())

Nesse relacionamento aninhado, thisele aponta para o objeto que o chamou por último , então a saída será:Mike

Vejamos outro tópico mais complicado, por favor, prepare-se para o "exame" comigo:

const o1 = {
    text: 'o1',
    fn: function() {
        return this.text
    }
}
const o2 = {
    text: 'o2',
    fn: function() {
        return o1.fn()
    }
}
const o3 = {
    text: 'o3',
    fn: function() {
        var fn = o1.fn
        return fn()
    }
}

console.log(o1.fn())
console.log(o2.fn())
console.log(o3.fn())

A resposta é: o1, o1, undefined, você acertou?

Vamos analisá-los um por um.

  • O primeiro consoleé o mais fácil, o1sem problemas. A dificuldade está no segundo e terceiro, a chave é olhar para thisa função chamada.
  • O segundo consoleé o2.fn()eventualmente chamado o1.fn(), então a resposta ainda é sim o1.
  • A última, var fn = o1.fndepois de fazer a atribuição, é a chamada "streaking", então o here thisaponta window, é claro, para a resposta undefined.

Se for na entrevista, como entrevistador, vou perguntar: Se precisar:

console.log(o2.fn())

saída o2, o que fazer?

Desenvolvedores gerais podem pensar em usar bind/call/applypara thisintervir na direção, o que é de fato uma forma de pensar. Mas aí eu perguntei, se não pode ser usado bind/call/apply, tem outro jeito?

const o1 = {
    text: 'o1',
    fn: function() {
        return this.text
    }
}
const o2 = {
    text: 'o2',
    fn: o1.fn
}

console.log(o2.fn())

Ainda aplique a conclusão importante: thisaponte para o objeto que o chamou por últimofn , apenas pendure-o no objeto durante a execução o2e realizamos operações de atribuição semelhantes com antecedência.

Cenário 3: bind/call/apply muda a direção deste

O bind/call/apply mencionado acima:

const foo = {
    name: 'lucas',
    logName: function() {
        console.log(this.name)
    }
}
const bar = {
    name: 'mike'
}
console.log(foo.logName.call(bar))

will output mike, o que não é difícil de entender. Mas um exame avançado de call/apply/bind geralmente combina construtores e herança de implementação composicional. Falaremos sobre o tópico de implementação de herança separadamente. Para o caso de uso do construtor, nós o analisamos em combinação com os seguintes cenários.

Cenário 4: Construtor e este

Os exemplos mais diretos disso são:

function Foo() {
    this.bar = "Lucas"
}
const instance = new Foo()
console.log(instance.bar)

A resposta será emitida Lucas. Mas esse cenário geralmente é acompanhado pela próxima pergunta: new o que exatamente o operador chama o construtor? O seguinte é para referência:

  • criar um novo objeto;
  • Aponte o construtor thispara este novo objeto;
  • Adicione propriedades, métodos, etc. a este objeto;
  • Finalmente retorna o novo objeto.

O processo acima também pode ser expresso em código:

var obj  = {}
obj.__proto__ = Foo.prototype
Foo.call(obj)

Claro que newa simulação aqui é uma versão simples e básica, e não vou entrar em detalhes sobre esse assunto em casos mais complicados.

Cabe ressaltar que se houver uma situação explícita no construtor return, então é necessário atentar para dois cenários:

function Foo(){
    this.user = "Lucas"
    const o = {}
    return o
}
const instance = new Foo()
console.log(instance.user)

será a saída undefined, caso em que instanceé o objeto vazio retornado o.

function Foo(){
    this.user = "Lucas"
    return 1
}
const instance = new Foo()
console.log(instance.user)

será a saída Lucas, o que significa que neste momento instanceé a instância do objeto de destino retornado this.

Conclusão: Se o construtor retornar explicitamente um valor e um objeto, então thisaponta para o objeto retornado; se não retornar um objeto, thisainda aponta para a instância.

Cenário 5: isso na função de seta aponta para

O uso de funções de seta thisnão se aplica às regras padrão acima, mas é determinado de acordo com o escopo de contexto externo (função ou global).

Vejamos o tópico:

const foo = {  
    fn: function () {  
        setTimeout(function() {  
            console.log(this)
        })
    }  
}  
console.log(foo.fn())

Nesta questão, thisaparece na função anônimasetTimeout() em , então aponta para o objeto. Se você precisar apontar para este objeto objeto, poderá usar a função de seta para resolvê-lo:thiswindowthisfoo

const foo = {  
    fn: function () {  
        setTimeout(() => {  
            console.log(this)
        })
    }  
} 
console.log(foo.fn())

// {fn: ƒ}

Na função de seta simples,this é muito simples, mas considerando todas as situações e considerando this a prioridade, this não é fácil determinar a direção neste momento. Leia.

Cenário Final 6: Esta prioridade está relacionada

Frequentemente nos referimos à situação de ligação por meio de call, apply, bind, newpara thiscomo ligação explícita; thiso apontar para determinado de acordo com o relacionamento de chamada é chamado de ligação implícita.

Então, qual deles tem maior prioridade, ligação explícita ou ligação implícita?

Veja exemplo:

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

const obj1 = {
    a: 1,
    foo: foo
}

const obj2 = {
    a: 2,
    foo: foo
}

obj1.foo.call(obj2)
obj2.foo.call(obj1)

A saída é 2, 1, respectivamente, ou seja call, applya ligação explícita de , geralmente tem prioridade mais alta que a ligação implícita.

function foo (a) {
    this.a = a
}

const obj1 = {}

var bar = foo.bind(obj1)
bar(2)
console.log(obj1.a)

O código acima passa binde vincula bara função thiscomo obj1um objeto. Após a execução bar(2), obj1.ao valor é 2. Ou seja, bar(2)após a execução, obj1o objeto é: {a: 2}.

Quando reutilizado barcomo construtor:

var baz = new bar(3)
console.log(baz.a)

produzirá 3. Vemos que bara função em si é binduma função construída pelo método, que foi ligada dentro de this, obj1e é usada como construtor.Quando newchamada por , a instância retornada foi obj1desvinculada de . Quer dizer:

new A vinculação modifica as vinculações no binding , portanto, as vinculações têm precedência maior do que as vinculações explícitas.bind this new bind

Vejamos novamente:

function foo() {
    return a => {
        console.log(this.a)
    };
}

const obj1 = {
    a: 2
}

const obj2 = {
    a: 3
}

const bar = foo.call(obj1)
console.log(bar.call(obj2))

produzirá 2. Como foo()o of thisestá vinculado a obj1, baro of (referindo-se a uma função de seta) thistambém está vinculado a obj1, e a associação de uma função de seta não pode ser modificada.

Se foototalmente escrito como uma função de seta:

var a = 123
const foo = () => a => {
    console.log(this.a)
}

const obj1 = {
    a: 2
}

const obj2 = {
    a: 3
}

var bar = foo.call(obj1)
console.log(bar.call(obj2))

irá produzir 123.

Aqui vou "agitar meu cérebro" novamente, apenas mude a atribuição da primeira variável no código acima apara:

const a = 123
const foo = () => a => {
    console.log(this.a)
}

const obj1 = {
    a: 2
}

const obj2 = {
    a: 3
}

var bar = foo.call(obj1)
console.log(bar.call(obj2))

A resposta será gerada undefinedporque constas variáveis ​​declaradas com não são montadas windowno objeto global. Portanto, ao thisapontar para window, naturalmente aa variável não pode ser encontrada.

おすすめ

転載: blog.csdn.net/pidanl/article/details/127629524