彻底理解this的指向

this的指向到底是什么,我们学习之前要知道以下知识:

  • 函数在调用时,JavaScript会默认给this绑定一个值;
  • this的绑定和函数定义的位置和方式没有关系;
  • this的绑定与函数的调用方式和调用位置有很大关系;
  • this是在函数运行时被绑定的;

先学习this的四种绑定规则,再研究一些规则之外的特殊情况:

  • 默认绑定(普通函数被独立调用时)
  • 隐式绑定(通过某个对象发起的函数调用时)
  • new绑定(用new关键字创建一个类的对象实例时)
  • 显式绑定(使用callapplybind调用时)
  • 四种规则的优先级
  • 内置函数中的this绑定
  • 规则之外1——忽略显式绑定
  • 规则之外2——间接函数引用
  • 规则之外3——箭头函数中this
1. 默认绑定

普通函数被独立的调用this指向window,严格模式下this指向undefined,例子如下:

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

function foo1() {
  console.log(this)
}
var bar1 = obj.foo
foo1() // window
bar1() // window

function foo2(func) {
  func()
}
foo2(obj.foo) // window
2. 隐式绑定

当一个函数作为对象的方法调用时this绑定到该对象,因为该对象内部有对函数的引用,是这个引用间接的将this绑定到了这个对象上。严格模式下无异,例子如下:

var obj1 = {
  name: 'obj1',
  foo: function () {
    console.log(this)
  },
}
var obj2 = {
  name: 'obj2',
  obj1: obj1,
}
obj1.foo() // obj1对象
obj2.obj1.foo() // obj1对象
3. new绑定

使用new关键字创建一个类的对象实例时this指向这个对象,严格模式下无异,例子如下:

/* 
  new关键字做了什么?
    1.创建一个空对象:使用 new 关键字时,首先会创建一个空对象。
    2.设置原型:新对象的原型会被设置为构造函数的 prototype 属性。
    3.绑定 this:构造函数中的 this 会绑定到新创建的对象上。
    4.执行构造函数:执行构造函数中的代码,this 指向新创建的对象。
    5.返回对象:如果构造函数没有显式返回对象,new 表达式会自动返回新创建的对象
*/
function Person(name, age) {
  this.name = name
  this.age = age
  console.log(this)
}
var person1 = new Person('好好', 18) // person {name: '好好',age: 18}
4. 显式绑定

当我们不想使用隐式绑定那样在对象内部包含函数的引用,但又想强制的改变this绑定时就要使用显示绑定了

使用callapplybind(例子中可以看出三者区别)明确改变this指向时,this指向你传入的对象,传入的若不是对象时可看以下例子,严格模式下则是传入什么绑定什么不传对象也是如此,例子如下:

// "use strict";
function foo(name, age, talk) {
  console.log(this, name, age, talk);
}
var obj = {
  name: "obj",
  foo: function () {
    console.log(this);
  },
};

foo.call(obj, "小韩", 18, true); // {name: 'obj', foo: ƒ} '小韩' 18 true
foo.apply({ name: "apply" }, ["大韩", 28, true]); // {name: 'apply'} '大韩' 28 true

foo.apply("abc"); // 包装类 String {'abc'}
foo.apply(123); // 包装类 Number {123}
foo.apply(true); // 包装类 Boolean {true}
// 下面代码解释具体看规则之外1的知识
foo.apply(null); // window
foo.apply(undefined); // window

/* 
  bind方法:
    当this总是绑定到一个对象上,我们不想每次调用都使用apply和call, 这时就要使用到bind改变this指向了。
    当使用bind方法时,它返回一个新的函数,这个新函数保留了构造函数的特性,可以使用new调用这个新函数。
*/
var baz = foo.bind(obj, "小小", 18, true); // bind()创建一个新的绑定函数
baz(); // {name: 'obj', foo: ƒ} '小小' 18 true
5. 四种规则的优先级
  1. new绑定优先级最高
  2. bind(可以和new一起使用)
  3. apply/call(不可以和new一起使用)
  4. 隐式绑定
  5. 默认绑定(默认最低,存在其他规则就会使用其他规则绑定this

例子如下:

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

obj.foo.call({ name: "apply" }); // 显式比隐式高: { name: "apply" }
var bar = foo.bind("bind");
bar.call("call"); // bind比call高  String {'bind'}
bar.apply("apply"); //bind比apply高  String {'bind'}
new bar("new"); // new绑定比bind高 foo {} 'new'
6. 内置函数中的this绑定
var obj = {
  name: "obj",
  foo: function () {
    console.log(this);
  },
};

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

var nums = ["123", "344", "577"];
nums.forEach(function (f) {
  console.log(this, "this"); // 三次window
});
nums.forEach(function (f) {
  console.log(this, "this"); // 三次obj对象,是你第二个参数传入的this值
}, obj);

var box = document.querySelector(".box");
box.onclick = function () {
  console.log(this); // box
  console.log(this === box); // true
};
7. 规则之外1——忽略显式绑定

显式绑定中我们传入nullundefined时,这个显式绑定会被忽略,使用默认绑定(严格模式下无此规则它是传什么绑定什么)

function foo() {
  console.log(this);
}
foo.apply(null); // window
foo.apply(undefined); // window
8. 规则之外2——间接函数引用

间接函数引用this指向window,严格模式下为undefined

function foo() {
  console.log(this);
}
var obj1 = {
  name: "obj1",
  foo: foo,
};
const obj2 = {
  name: "obj2",
};
obj2.foo = obj1.foo;
obj2.foo(); // 隐式绑定 {name: 'obj2', foo: ƒ}
(obj2.foo = obj1.foo)(); // 间接函数引用 window  

(obj2.foo = obj1.foo) 返回为foo函数,因为这是一个赋值表达式,赋值表达式会返回被赋的值即obj1.foo,然后再进行调用时就相当于独立函数调用

9. 规则之外3——箭头函数中this

箭头函数不绑定this,它在自己的作用域中无this,打印this时会向外层作用域一级级查找

var obj = {
  name: "obj",
  foo: function () {
    return () => {
      console.log(this);
    };
  },
};
obj.foo.apply("apply")(); // String {'apply'} 打印的是foo函数的this
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值