一、前言
this关键字是JavaScript中最复杂的机制之一。它是一个很特别的关键字,被自动定义在所有函数的作用域中。对于那些没有投入时间学习this机制的JavaScript开发者来说,this的绑定一直是一件非常令人困惑的事。
二、了解this
随着函数使用场合的不同,this的值会发生变化。但总有一条原则就是JS中的this代表的是当前行为执行的主体,在JS中主要研究的都是函数中的this,但并不是说只有在函数里才有this,this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用
三、this到底指向谁
1. 函数执行时首先看函数名前是否有“.”
- 有:"." 前是谁,this就指向谁
- 无:this均指向window
function fn() {
console.log(this);
};
//函数无“.”
fn();//this->window
//函数有“.”
let obj = {fn};
obj.fn();//this->obj
//嵌套函数
function fn1() {
fn();
};
fn1();//this->window
//混合
let f2={
sum:function() {
console.log(this);//this->f2
fn();//this->window
}
}
f2.sum();
2.自执行函数种的this永远都是window
(function() {
console.log(this);
})();
~ function() {
console.log(this);
}();
~
立即执行函数表达式(IIFE)的一种写法,通过~/+/-等运算符将函数体转换成函数表达式,最后加上()就能立即执行
3. 给元素的某事件绑定方法,当事件触发的时候,this指向的是当前元素
<button id="btn">按钮</button>
<script type="text/javascript">
let onBtn = document.getElementById("btn")
onBtn.onclick = function() {
console.log(this);
}
</script>
4.在构造函数模式中,类中(函数体中)出现的this.xxx=xxx中的this是当前类的一个实例
function fn(name, age) {
//浏览器默认创建的对象就是我们的实例fn1->this
this.name = name; //->fn1.name=name
this.age = age;
this.writeJs = function() {
console.log( this.name + this.age);
};
//浏览器再把创建的实例默认的进行返回
}
var fn1 = new fn("CSDN", 20);
console.log(fn1.name);//CSDN
fn1.writeJs();//CSDN20
- 类中某属性值(方法)的this需要看方法执行的时候,前面是否有".",才能知道this是谁;
function Fn() {
this.x = 100; //this->f1
this.getX = function() {
//this->需要看getX执行的时候才知道
console.log(this.x);
}
}
var f1 = new Fn();
f1.getX(); //->方法中的this是f1,所以f1.x=100
var f2 = f1.getX;
f2(); //->方法中的this是window ->undefined
5.call、apply、bind
call(fn, n1, …)
- 第一个参数指定了函数体内this对象的指向;
- 第二个参数及以后为函数调用的参数
//在非严格模式下
let data={name:"CSDN "};
function fn(num1,num2){
console.log(num1+num2);
console.log(this);
}
fn.call(100,200);//this->100 num1=200 num2=undefined
fn.call(data,100,200);//this->obj num1=100 num2=200
fn.call();//this->window
fn.call(null);//this->window
fn.call(undefined);//this->window
//严格模式下
fn.call();//在严格模式下this->undefined
fn.call(null);// 在严格模式 下this->null
fn.call(undefined);//在严格模式下this->undefined
apply(fn, arr)
- apply和call方法的作用是一模一样的,都是用来改变方法的this关键字并且把方法执行,而且在严格模式下和非严格模式下对于第一个参数是null/undefined这种情况的规律也是一样的。
- 区别:call第二个参数开始接受一个参数列表,apply第二个参数开始接受一个参数数组
fn.call(param,100,200);
fn.apply(param,[100,200]);
bind(fn, n1, …)
- 事先把fn的this改变为我们想要的结果,并且把对应的参数值也准备好,以后要用到了,直接的执行即可;
var a = {
name: "Cherry",
fn: function(a, b) {
console.log(a + b)
}
}
var b = a.fn.bind(a, 1, 2);
b();
call、apply、bind优先级要高于其他四种
四、箭头函数this的指向
- 箭头函数没有自身的this,箭头函数的this不是调用的时候决定的,而是在定义的时候处在的对象就是它的this;
- 换句话说,箭头函数的this看外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有,则this是window。
<button id="btn1">btn1</button>
<button id="btn2">btn2</button>
<script type="text/javascript">
let btn1 = document.querySelector("#btn1");
let data = {
name: 'GGG',
age: 3,
getName: function() {
btn1.onclick = () => {
console.log(this);
}
}
}
data.getName();
</script>
1. 箭头函数外层存在函数
- 由于箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this
2.箭头函数外层不存在函数
- 虽然存在两个箭头函数,其实this取决于最外层的箭头函数,由于data是个对象而非函数,所以this指向为Window对象
let btn2 = document.querySelector("#btn2");
let data2 = {
name: 'xxx',
age: 3,
getName: () => {
btn2.onclick = () => {
console.log(this);
}
}
}
data2.getName();