javascript笔记之this到底指向哪里?

本文最最核心的一句话就是:this是在函数调用的时候确定的,一定要牢牢记住,其次,在函数执行过程中,this一旦被确定,就不可更改了。

var a = 10;
var obj = {
    a: 20
}

function fn(){
	this= obj;  // 这句话试图修改this,运行后会报错
	console.log(this.a);
}

fn();

this是什么

重点:this是一个对象,是对象和函数之间达成关联关系的纽带,是在函数调用的时候确定

怎么确定this的指向

因为this是在函数调用的时候确定的,所以this的指向是很灵活的,所以很多人对this的指向总是似懂非懂。那么这里可以告诉大家一个套路,也是本文唯一的套路,按照这个套路走,以后this的问题再也难不倒你了。

当你不能确定this指向哪里的时候,尝试把函数的调用转换为 call/apply 的形式,call/apply 的第一个参数就是this的指向!

call/apply手动指定this

call/apply可以自行手动设置this的指向。所有的函数都具有着两个方法,它们除了参数略有不同,其功能完全一样。它们的第一个参数都为this将要指向的对象。call/apply的具体使用这里就不讲了,如果不熟悉call/apply的用法 送你传送门

function fn(param) {
    console.log(this.a,param);
}
var obj = {
    a: "我是this的属性a"
}

fn.call(obj,"我是参数param"); // 我是this的属性a  我是参数param
  • call/apply第一个参数如果传入的是简单数据类型,会被自动包装为对象

    function f(){
      console.log(this)
    }
    f.call(10); 	// Number {10}
    f.call(true);   // Boolean {true}
    f.call("str");  // String {"str"}
    
  • call/apply第一个参数如果没传,或者传入的是null/undefined的时候,this的指向跟是否在严格模式下有关。

    • 非严格模式下,this指向全局对象(浏览器是window)。

      function f(){
        console.log(this)
      }
      f.call();    // Window {postMessage: ƒ,...}
      f.call(null);    // Window {postMessage: ƒ,...}
      f.call(undefined); // Window {postMessage: ƒ,...}
      
    • 严格模式下,this指向null/undefined

      "use strict"
      
      function f(){
       console.log(this)
      }
      f.call(); // undefined
      f.call(null);    // null
      f.call(undefined); // undefined
      

几个栗子

只要掌握call/apply,结合是否严格模式,你就会发现虚无缥缈的this已经有迹可循了,下面例子中的函数调用代码都可以通过转换的call模式代码直接替换。

  • 纯粹的函数调用

    // 非严格模式
    var x = 1;
    function test() {
       console.log(this.x);
    }
    
    // 在心里将test()翻译为call模式,test.call(),非严格模式
    // 所以this===window,所以输出window.x
    test();  // 1
    
    
    // 严格模式
    "use strict"
    var x = 1;
    function test() {
       console.log(this.x);
    }
    // 在心里将test()翻译为call模式,test.call(),严格模式
    // 所以this===undefined,所以输出window.x
    test();  // Uncaught TypeError: Cannot read property 'x' of undefined
    
  • 作为对象方法的调用

    function test() {
      console.log(this.x);
    }
    
    var obj = {
    	x:3,
    	m:test
    };
    // 在心里将test()翻译为call模式,obj.m.call(obj),这时this===obj,所以输出obj.x
    obj.m(); // 3
    
    • 作为构造函数调用, this就指向构造出来的新对象
    function Test() {
     this.x = 3;
    }
    // 在心里将test()翻译为call模式
    // var obj = {}; Test.call(obj); 
    // 这时this===obj,所以输出obj.x
    var obj = new Test();
    obj.x; // 3
    
  • 通过call/apply改变this指向,将类数组对象转换为数组,

    function exam(a, b, c, d, e) {
    
        // 先看看函数的自带属性 arguments 什么是样子的
        console.log(arguments);
    
        // 使用call/apply将arguments转换为数组, 返回结果为数组,arguments自身不会改变
        var arg = [].slice.call(arguments);
    
        console.log(arg);
    }
    
    exam(2, 8, 9, 10, 3);
    // { '0': 2, '1': 8, '2': 9, '3': 10, '4': 3 }
    // [ 2, 8, 9, 10, 3 ]
    // 也常常使用该方法将DOM中的nodelist转换为数组
    // [].slice.call( document.getElementsByTagName('li') );
    
  • 根据自己的需要灵活修改this指向

    var foo = {
        name: 'joker',
        showName: function() {
          console.log(this.name);
        }
    }
    var bar = {
        name: 'rose'
    }
    foo.showName.call(bar);
    

总结

我们可以将平时通过括号、通过.、通过new去使用函数的方式,看做是call/apply的语法糖,是简写版,想要深入理解函数的调用,就要学好call
关于this的部分已经总结完了,希望这篇文章有助于你准确的理解this关键字,能够真正学到东西。

参考

this 的值到底是什么?一次说清楚
你怎么还没搞懂 this?
JS 的 new 到底是干什么的?
Javascript 的 this 用法
全方位解读this

====================================================================================================
作者:星木
欢迎任何形式的转载,但请务必注明出处。
限于本人水平,如果有不当之处,还请不吝赐教。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值