前言
this绑定是Javascript开发中老生常谈的问题了,但要彻彻底底弄的很明白的人应该不多,有时候我也会被this绑定题弄的晕头转向的,本人今天就从this绑定的五种场景 默认绑定
、隐式绑定
、显式绑定
、new绑定
、箭头函数绑定
详解
一) this默认绑定
看下面这个例子:
//非严格模式
var a = 2;
function fn(){
console.log(this.a); // 2
}
fn();
//严格模式
function foo(){
"use strict";
console.log(this.a); // TypeError: Cannot read property 'a' of undefined
}
foo();
- 非严格模式下,全局作用域中的函数调用时,函数词法作用域内的
this
指向全局对象window
- 严格模式下,函数调用时词法作用域内的
this
指向undefined
, 报TypeError
错误
以上仅仅是举例,在实际开发中,不应混用严格与非严格模式
二) 隐式绑定
看下面这个例子:
function foo() {
console.log(this.name);
};
let obj = {
name: '牧游',
func: foo
};
obj.func() //牧游
提出疑问: 如果函数前面存在多个调用它的对象,那么this会隐式绑定到哪个对象上呢?
function foo() {
console.log(this.name);
};
let obj = {
name: '牧游',
func: foo
};
let obj1 = {
name: '张三',
attr: obj
}
obj1.attr.func() //牧游
隐式丢失
在特定的场景下,隐式绑定也会存在丢失的问题,最常见的就是作为 参数传递
以及 变量赋值
,我们先看下参数传递这个例子:
var name = '张三';
let obj = {
name: '牧游',
fn: function () {
console.log(this.name);
}
};
function fn1(param) {
param();
};
fn1(obj.fn); // 张三
导致以上问题原因: obj.fn 被当做函数入参传递到fn1函数里去执行,obj.fn函数内部this并没有跟其所在对象绑定,所以this找不到就会指向window
第二个丢失问题:变量赋值
var name = '张三';
let obj = {
name: '牧游',
fn: function () {
console.log(this.name);
}
};
let fn1 = obj.fn;
fn1(); //张三
原因: 本质上与传参相同
三) 显示绑定
我们来看一下具体的例子:
let obj1 = {
name: '张三'
};
let obj2 = {
name: '李四'
};
let obj3 = {
name: '王五'
}
let name = '牧游';
function fn() {
console.log(this.name);
};
fn(); // 牧游
fn.call(obj1); // 张三
fn.apply(obj2); // 李四
fn.bind(obj3)(); // 王五
在上述代码中,分别通过call、apply、bind改变函数fn的this指向。其实这种做法,我们习惯称之为 函数调用
。
注意事项: 如果在使用call之类的方法改变this指向时,指向参数提供的是null 或者 undefined, 那么this将指向全局对象。比如下面这个例子:
let obj1 = {
name: '张三'
};
let obj2 = {
name: '李四'
};
let obj3 = {
name: '王五'
}
let name = '牧游';
function fn() {
console.log(this.name);
};
fn(); // 牧游
fn.call(undefined); // 牧游
fn.apply(null); // 牧游
fn.bind(undefined)(); // 牧游
另外, JS中部分API方法也内置了显示绑定,以forEach为例:
let obj = {
name: '牧游'
};
[1, 2, 3].forEach(function () {
console.log(this.name); //牧游 [3次]
}, obj);
四) new绑定
function Fn() {
this.name = '牧游';
}
let obj = new Fn();
console.log(obj.name);
五) this的绑定优先级
我们前面介绍this的四种绑定规则,这边提出一个问题,如果一个函数调用存在多种绑定方法,this最终指向谁呢?
这里我们直接先上答案,this绑定的优先级关系为:
显式绑定 > 隐式绑定 > 默认绑定
new绑定 > 隐式绑定 > 默认绑定
那么我们结合几个例子来验证下上面的规律,首先是 显示绑定 > 隐式绑定
:
//显式 > 隐式
let obj = {
name: '张三',
fn: function () {
console.log(this.name);
}
};
let obj1 = {
name: '牧游'
};
obj.fn.call(obj1);// 牧游
其次是 new绑定 > 隐式绑定
:
//new > 隐式
let obj = {
name: '张三',
fn: function() {
this.name = '牧游';
}
}
let echo = new obj.fn();
console.log(echo.name); // 牧游
提出问题: 为什么显示绑定不和new绑定比较呢?
答: 因为不存在这种绑定同时生效的情景,如果同时写这两种代码会直接抛错,比如:
// error
let obj = {
name: '张三',
fn: function() {
}
}
let obj1 = {
name: '牧游'
}
let echo = new obj.fn.call(obj1); // Uncaught TypeError: obj.fn.call is not a constructor
六) 箭头函数this
ES6的箭头函数是另类的存在,为什么要单独说呢,这是因为箭头函数中的this不适用上面介绍的四种绑定规则。
准备来说, 箭头函数中没有this, 箭头函数的this指向取决于外层作用域中的this, 外层作用域或函数的this指向谁, 箭头函数中的this便指向谁。比如下面这个例子:
function fn() {
return () => {
console.log(this.name);
};
}
let obj1 = {
name: '牧游'
};
let obj2 = {
name: '张三'
};
let bar = fn.call(obj1); // fn this指向obj1
bar.call(obj2); // 牧游
提出问题: 为什么我们第一次绑定this并返回箭头函数后,再次改变this指向没生效呢?
答: 1) 箭头函数的this取决于外层作用域的this, fn函数执行是this指向了obj1, 所以函数的this也指向obj1。 2) 箭头函数this还有一个特性,就是 一旦箭头函数的this绑定成功,无法再次被修改
再次提出问题: 如果箭头函数有多个外层作用域,那最终该指向谁呢?
答: 箭头函数的this仅取决其直接外层作用域的this, 通俗一点说就是直接上级
function fn() {
return function () {
return () => {
console.log(this.name);
};
}
}
let obj1 = {
name: '牧游'
};
let obj2 = {
name: '张三'
};
let obj3 = {
name: '李四'
};
let bar = fn.call(obj1);
let foo = bar.call(obj2);
let echo = foo.call(obj3); // 张三
我们上面说了, "箭头函数的this一旦绑定成功,无法再次被修改", 其实我们通过可以修改外层函数this 指向达到间接修改箭头函数this的目的。比如下面这个例子:
function fn() {
return () => {
console.log(this.name);
};
};
let obj1 = {
name: '牧游'
};
let obj2 = {
name: '张三'
};
fn.call(obj1)(); // fn this指向obj1,箭头函数this也指向obj1
fn.call(obj2)(); //fn this 指向obj2,箭头函数this也指向obj2
总结
通过上面的实例以及结合知识点讲解,总结了以下知识点:
- 【默认绑定】严格模式与非严格模式this指向有所不同
- 【隐式绑定】介绍了隐式丢失几种情况
- 详细说明了this几种绑定优先级关系
参考
掘金
木易杨前端进阶
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!