js 里面令人头疼的 this

JS中this相关问题梳理

this 就是 js 里的关键字,有特殊意义,代表函数执行主体

一、定义

  • 函数执行主体(不是作用域):意思是谁把函数执行了,那么执行主体就是谁

二、使用情况

  1. 全局作用域里的thiswindow , 全局作用域下相当于是window.fn() 执行只是把window 省略了(严格模式下是undefined )。
console.log(this === window); // true

window.a = 13;
console.log(this.a); // 13
  1. 函数里的this , 看执行主体前有没有 ,如果有 ,那 前面是谁,函数里的this 就是谁,如果没有 ,那函数里的this 就是window ,严格模式下是undefined
function fn() {
    console.log(this);
}
fn(); // window

let obj = {
    fn: function() {
        console.log(this);
    }
}
obj.fn(); // obj{...}

var f = obj.fn;
f(); // window
  1. 立即执行函数里的thiswindowundefined(严格模式下)
(function() {
    console.log(this); //==> window
})();
~function(){}(); //==> window
+function(){}(); //==> window
-function(){}(); //==> window
!function(){}(); //==> window
  1. 回调函数里的this一般情况下是window
let arr = [1, 2, 3];
arr.forEach(function(item, index) {
    console.log(this); // 打印了三个window
})

setTimeout(function(num) {
    console.log(num); // 1
    console.log(this); // window
}, 1000, 1)

function fn(m) {
    m();
}

fn(function() {
    console.log(this); // window
})
  1. 箭头函数没有this

但是要是在箭头函数里使用this,它就会往上一级作用域查找,如果上一级作用域也没有,那就继续查找,直到找到全局作用域window为止

let obj = {
    num: 2,
    fn: function() {
        // this --> obj
        let m = () => {
            // this --> obj
            console.log(this.num); // obj (要向上一级查找)
        }
        m();
    }
}
obj.fn();
  1. 构造函数里的this是当前的实例

  2. 实例原型上的公有方法里的this一般是当前实例(下面改变this的方法中有所体现)

  3. 给元素绑定事件行为,那事件里的this就是当前被绑定的元素本身

btn.onclick = function() {
    console.log(this); // btn
}

三、面向对象中有关私有/公有方法中的THIS问题

总结下来this在面向对象中,主要还是看谁执行的,也就是执行函数点前是谁

  1. 方法执行,看前面是否有点,点前面是谁this就是谁
  2. 把方法总的this进行替换
  3. 在基于原型链查找的方法确定结果即可

四、改变this指向:call/apply/bind

每一个函数(普通函数/构造函数/内置类)都是Function这个内置类的实例,所以函数.__proto__ === Function.prototype函数可以直接调取Function原型上的方法

  • call / apply / bind
  • 原型上提供的三个公有属性方法
  • 每一个函数都可以调用这个方法执行
  • 这些方法都是用来改变函数中的this指向的
  1. call

函数基于原型链扎找到Function.prototype.call这个方法,并且把它执行,在call方法执行的时候改变里面的this关键字

  • 让当前的函数执行
  • 把函数中的this指向改为第一个传递给call的实参
  • 把传递给call其余的实参,当做参数信息传递给当前函数

注意

  • 如果执行call一个实参都没有传递,非严格模式下是让函数中的this指向window,严格模式下指向的是undefined
  • fn.call(null);
  • //=> this.window
  • 严格下是this(第一个参数传递的是null/undefined/不传,非严格模式下this指向window,严格模式下传递的是谁this就是谁,不传thisundefined

使用方法

window.name = 'WINDOW';
let obj = {name: 'OBJ'};
function fn(n, m) {
	console.log(this.name);
}
fn(10, 20); // WINDOW --> 因为函数刚开始指向window
fn.call(obj); // OBJ --> 改变函数this指向,此时函数fn指向obj
fn.call(obj, 10, 20); // OBJ
fn.call(10, 20); // undefined

可以得出:

  • 一个 call 是让左边函数之后执行(this是传递的参数)
  • 多个 call 是让最后传参的函数执行(thiswindow/undefined

2、apply

call方法一样,都是把函数执行,并且改变里面的this关键字,唯一的区别就是传递给函数参数的方式不一样

  • call是一个个传参
  • apply是按照数组传参
let obj = {name: 'OBJ'};
let fn = function(n, m) {
console.log(this.name); // 
}
//=>让fn方法执行,让方法中的this变为obj,并传递1, 2给函数
fn.call(obj, 1, 2);
fn.apply(obj, [1, 2]);

3、bind

call/apply一样,也是用来改变函数中的this关键字,只不过基于bind改变this,当前方法并没有被执行,类似于预先改变this

  • bind是预处理this,他并不会让函数执行
  • bind方法的返回值是一个改变this之后的新函数

作用

  • 把函数中的this指向通过预处理的方式改为第一个传递给bind的实参

  • 一般使用在绑定点击事件,不让函数立即执行

let obj = {name: 'mary'};
function fn() {
  console.log(this.name);
}
btn.onclick = fn; // this --> btn// 想让this指向obj???
btn.onclick = fn.call(obj); // 这样也不行,call/apply只是把执行的结果返回给点击事件
btn.onclick = fn.bind(obj); // this --> obj// 如果非要用call/apply
btn.onclick = function() {
    return fn.call(obj); // 把函数返回给点击事件才可以
}

注意

  • 在IE6~8中不支持 bind 方法
  • 预先做啥事情的思想被称为“柯理化函数

优点

  • bind的好处是:通过bind方法只是预先把fn中的this修改为obj,此时fn并没有执行,当点击事件触发才会执行fncall/apply都是通过改变this的同时立即把方法执行)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值