Javascript - this

Javascript - this

  • 1,调用分类
    • 1.1,独立调用
      • 1,纯粹的函数调用
      • 2,匿名函数调用
    • 1.2,隐式调用
      • 隐式丢失
      • 1,函数通过别名调用
      • 2,参数传递
      • 3,匿名函数调用
      • 4,条件判断后调用
    • 1.3,显示绑定调用
    • 1.4,new 调用
      • 1,new 做了什么
      • 2,new 调用的返回值
    • 1.5,箭头函数调用
  • 2,调用优先级
  • 3,this 原理
    • 内存的数据结构
    • 函数

this是在函数运行时,在函数体内部自动生成的一个对象,并只能在函数体内部使用。

总的来说,this 就是函数运行时所在的环境对象

1,调用分类

1.1,独立调用

1,纯粹的函数调用

函数在浏览器全局环境中被直接调用

  • 非严格模式下 this 指向 window
  • 严格模式下 this 指向 undefined
function f1() {
  console.log(this) // window
}

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

2,匿名函数调用

setTimeout(function () {
  console.log(this) // window
})

setTimeout(function () {
  'use strict'
  console.log(this) // 注意是 window
})

1.2,隐式调用

作为对象的方法调用

在执行函数时,如果函数的 this 是被上一级的对象调用,那么this指向上一级对象。

举例 1:

const person = {
  name: '下雪天的夏风',
  brother: {
    name: '路飞',
    fn: function () {
      return this.name
    }
  }
}

console.log(person.brother.fn()) // 路飞

举例 2:

const obj1 = {
  name: '1',
  fn: function () {
    return this.name
  }
}

const obj2 = {
  name: '2',
  fn: function () {
    return obj1.fn()
  }
}

const obj3 = {
  name: '3',
  fn: obj1.fn
}

const obj4 = {
  name: '4',
  fn: function () {
    const fn = f1.fn
    return fn()
  }
}

var name = 'global'

console.log(obj1.fn()) // 1
console.log(obj2.fn()) // 1
console.log(obj3.fn()) // 3
console.log(obj4.fn()) // global
  1. this指向上一级对象obj1
  2. this指向上一级对象obj1
  3. obj1.fn 是函数的引用,obj3.fn()this指向上一级对象obj3
  4. const fn = f1.fn赋值后,fn()变成独立调用,this指向window

隐式丢失

隐式绑定的函数丢失了绑定的对象,实质上都是变成了独立调用this指向了window

const obj = {
  name: '下雪天的夏风',
  foo: function () {
    console.log(this.name)
  }
}

下面这4种,都可以理解为将 obj.foo 赋值给一个新的变量来调用。

1,函数通过别名调用

const bar = obj.foo
bar()

2,参数传递

function doFoo(foo) {
  foo()
}
doFoo(obj.foo)

3,匿名函数调用

setTimeout(obj.foo)

4,条件判断后调用

(false || obj.foo)()

1.3,显示绑定调用

call,apply,bind 的调用

三者异同点:

const targetObj = {}
function fn() {}

fn.call(targetObj, 'arg1', 'arg2')

fn.apply(targetObj, ['arg1', 'arg2'])

fn.bind(targetObj, 'arg1', 'arg2')() // 返回一个新函数来调用。

如果第 1 个参数是null | undefined,此时 this 绑定给 window

1.4,new 调用

作为构造函数调用

构造函数:可以通过这个函数生成有一个新的对象,此时 this 指向这个新对象。

function test() {
  this.x = 1
}

const obj = new test()
obj.x // 1

1,new 做了什么

对于构造函数Foo来说,执行 new Foo() 会进行如下操作

  1. 创建一个新对象 const context = {}
  2. 使 context.__proto__ = Foo.prototype

前 2 步可以合并为

const context = Object.create(Foo.prototype)
  1. 改变 Foothis指向新对象context,并执行Foo
const result = Foo.apply(context, arguments)
  1. 如果执行结果是对象,则直接返回,否则返回创建的新对象 context
return typeof result === 'object' && result !== null ? result : context

2,new 调用的返回值

new 命令始终返回一个对象。

  • 构造函数内部有return语句,并且后面跟着对象,则会返回这个对象。否则不管这个return语句,返回this对象。
  • 构造函数内部没有return语句,则返回this对象。

1.5,箭头函数调用

箭头函数没有自己的this对象,内部的this就是定义时上层作用域中的this
也就是说,箭头函数内部的this指向是固定的。

function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 }); // id: 42

2,调用优先级

new > 显示绑定 > 隐式

显示绑定 > 隐示,比较容易理解。

我们来举个 new > 显示绑定 的例子:

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

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

相比于bar()直接调用,通过 new 调用时,返回的实例已经与 obj1 解绑。

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

3,this 原理

我们在一开始说:this 就是函数运行时所在的环境对象

以下面的代码为例(隐示丢失):

const obj = {
  name: '下雪天的夏风',
  foo: function () {
    console.log(this.name)
  }
}
var name = '2'

obj.foo() // '下雪天的夏风'
const foo = obj.foo
foo() // 2

所以,

  • 对于obj.foo来说,foo运行在obj环境,所以this指向obj
  • 对于foo来说,foo运行在全局环境,所以this指向全局环境。

那为什么会这样?

内存的数据结构

const obj = { name: '下雪天的夏风' }

将一个对象赋值给变量 obj 时:js 引擎会先在内存中生成对象{ name: '下雪天的夏风' },再将对象的内存地址赋值给变量obj

之后在读取obj.name 时,js引擎先在obj拿到内存地址——>从内存地址获取原始对象——>从对象获取name属性。

函数

而属性的值可能是一个函数:

const obj = { foo: function() {} }

当对象的属性是函数时:js引擎会将函数单独保存在内存中,然后再将函数的地址赋值给foo属性。

obj: {
  foo: 函数的地址
}

此时函数是一个单独的值,所以它可以在不同的环境(上下文)执行。

由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。
所以,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。

const foo = function () {};
const obj = { foo };

// 单独执行
foo ()

// obj 环境执行
obj.foo ()

以上。

你可能感兴趣的:(js,javascript,前端,js)