this指向-指向规则-箭头函数

114 阅读4分钟

this在全局作用域下

浏览器中指向为:window

node环境中指向:空对象

通常都是在函数中使用,所有的函数在被调用时,都会创建一个执行上下文:

这个上下文中记录着函数的调用栈、AO对象等;this也是其中的一条记录

  • 函数在调用时,JavaScript会默认给this绑定一个值;

  • this的绑定和定义的位置(编写的位置)没有关系;

  • this的绑定和调用方式以及调用的位置有关系

  • this是在运行时被绑定

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

//1.直接调用
foo() //window

//2.对象调用
var obj = {
  name: 'why',
  foo: foo
}
obj.foo() //foo函数

//apply
foo.apply('abc') //[String:'abc']

规则一:默认绑定

调用的位置

独立的函数调用 我们可以理解成函数没有被绑定到某个对象上进行调用;

function foo() {
  console.log(this)
}
foo()
function foo1() {
  console.log(this)
}
function foo2() {
  console.log(this)
  foo1()
}
function foo3() {
  console.log(this)
  foo2()
}
foo3()

var obj = {
  name: 'why',
  foo: function () {
    console.log(this)
  }
}

var bar = obj.foo()
//this指向依旧为全局
bar()

绑定二:隐式绑定;

通过某个对象发起的函数调用

隐式绑定有一个前提条件:

必须在调用的对象内部有一个对函数的引用(比如一个属性); 如果没有这样的引用,在进行调用时,会报找不到该函数的错误; 正是通过这个引用,间接的将this绑定到了这个对象上;

var obj = {
  name: 'why',
  foo: foo
}
obj.foo()

绑定三:显示绑定(apply,call,bind)

如果我们不希望在 对象内部 包含这个函数的引用,同时又希望在这个对象上进行强制调用,该怎么做呢? JavaScript所有的函数都可以使用call和apply方法(这个和Prototype有关)。

其实非常简单,第一个参数是相同的,后面的参数,apply为数组,call为参数列表;

这两个函数的第一个参数都要求是一个对象,这个对象的作用是什么呢?就是给this准备的。

在调用这个函数时,会将this绑定到这个传入的对象上。 因为上面的过程,我们明确的绑定了this指向的对象,所以称之为 显示绑定。

如果在显示绑定中,我们传入一个null或者undefined,那么这个显示绑定会被忽略,使用默认规则:

function foo() {
  console.log(this)
}
var obj = {
  name: 'obj'
}
//指定this绑定
foo.call(obj)
foo.call(null)
foo.call(undefined)
foo.apply({ name: 'apply' }) //{name:'apply'}
foo.call({ name: 'call' }) //{name:'call}
foo.bind({ name: 'bind' }) //{name:'bind'}

//call 和 apply 区别
function sum(sum1, sum2) {
  console.log(sum1 + sum2, this)
}

// 传参数不同  挨个传
sum.call('call', 20, 30)
// 数组传参
sum.apply('apply', [20, 30])

绑定四:new绑定

this = 创建出来的对象

JavaScript中的函数可以当做一个类的构造函数来使用,也就是使用new关键字。

使用new关键字来调用函数是会执行如下的操作:

1.创建一个全新的对象;

2.这个新对象会被执行prototype连接;

3.这个新对象会绑定到函数调用的this上(this的绑定在这个步骤完成);

4.如果函数没有返回其他对象,表达式会返回这个新对象;

function Person(name, age) {
  this.name = name
  this.age = age
  console.log(this)
}
var p1 = new Person('why', 18)
console.log(p1)

规则优先级

  • 1.默认规则的优先级最低

    毫无疑问,默认规则的优先级是最低的,因为存在其他规则时,就会通过其他规则的方式来绑定this

  • 2.显示绑定 优先级高于 隐式绑定

  • 3.new绑定 优先级高于隐式绑定

  • 4.new绑定 优先级高于bind

    new绑定和call、apply是不允许同时使用的,所以不存在谁的优先级更高

    new绑定可以和bind一起使用,new绑定优先级更高

间接函数引用

创建一个函数的 间接引用,这种情况使用默认绑定规则。

赋值(obj2.foo = obj1.foo)的结果是foo函数;

foo函数被直接调用,那么是默认绑定

function foo() {
  console.log(this)
}
var obj = {
  name: 'why',
  foo: foo
}
var obj2 = {
  name: 'obj2'
}
//函数间接调用
;(obj2.foo = obj.foo)()//window

箭头函数 arrow function [ ()=> ]

箭头函数不会绑定this、arguments属性;

箭头函数不能作为构造函数来使用(不能和new一起来使用,会抛出错误);

箭头函数不使用this的四种标准规则(也就是不绑定this),而是根据外层作用域来决定this。

var num = [1, 5, 6, 7]

//1.一个参数,省略小括号
num.forEach(item => {
  console.log(item)
})
//2.只有一行执行体,{}也可以省略,默认将这行代码的执行结果为返回值
 num.forEach(item => console.log(item))

var reult = num
  .filter(item => item > 2)
  .map(item => item * 2)
  .reduce((preValue, item) => preValue + item)
console.log(reult)