javascript中 this 指向问题

本文深入解析JavaScript中this关键字的指向规则,包括new调用、bind、call、apply、对象方法及直接调用等五种情况,并通过实例进行验证。

前言

this是执行上下文环境的一个属性,而不是某个变量对象的属性。

在全局代码中,this始终是全局对象本身,这样就有可能间接的引用到它了。

在通常的函数调用中,this是由激活上下文代码的调用者来提供的,即调用函数的父上下文(parent context )。this取决于调用函数的方式。

function函数里的this指向,由函数的调用方式决定:

  • 如果new关键词出现在被调用函数的前面,那么JavaScript引擎会创建一个新的对象,那么函数中的this指向的就是这个新创建的对象;
  • 如果通过bind的方式得到的函数,那么该函数中的this指向bind的第一个参数;
  • 如果通过applycall的方式触发函数,那么函数中的this指向传入函数的第一个参数;
  • 如果通过某个对象使用句点符号触发函数,那么函数中的this指向该对象;
  • 如果直接触发函数,那么函数中的this指向全局对象(在浏览器中指向window,在node.js中指向global);

非函数里的this指向:

  • 不在函数里的this指向全局对象(在浏览器中指向window,在node.js中指向global);

详细分析this指向的这5种情况:

1、new 关键字,作为构造器调用的函数中的this

如果new关键词出现在被调用函数的前面,那么JavaScript引擎会创建一个新的对象,那么函数中的this指向的就是这个新创建的对象;

function Cat(name) {
  var _this = this;
  this.name = name;
  this.test = function() {
    console.log(`this equal _this: ${_this === this}`);
    console.log(`this euqal window: ${this === window}`);
  }
}
var mi = new Cat('mi');
mi.test(); // "this equal _this: true"
           // "this euqal window: false"
var test1 = mi.test;
test1();// "this equal _this: false"
        // "this euqal window: true"
复制代码

2、bind 指定this

var obj2 = {};
function thisFunc2() {
  console.log(`this2 equal window: ${this===window}`);
  console.log(`this2 equal obj2: ${this===obj2}`);
};

var thisFunc22 = thisFunc2.bind(obj2);
thisFunc2();// "this2 equal window: true"
            // "this2 equal obj2: false"
thisFunc22();// "this2 equal window: false"
             // "this2 equal obj2: true"
复制代码

3、call、apply重定向this

如果通过applycall的方式触发函数,那么函数中的this指向传入函数的第一个参数;

var GlobalName = 'globalName';
var obj3 = 'sofia';
function thisFunc3(a) {
  console.log(`this3'Name: ${this}`);
  console.log(`a: ${a}`);
}

var thisFun33 = thisFunc3.bind(obj3, 4);
thisFun33.call(GlobalName, 3);// "this3'Name: sofia"
                              // "a: 4"

thisFun33();// "this3'Name: sofia"
            // "a: 4"
复制代码

4、对象属性的方法

var obj4 = {
  thisFunc4: function () {
  console.log(`this4 equal obj4: ${this===obj4}`);
  }
};
obj4.thisFunc4(); // "this4 equal obj4: true"
复制代码
var obj5 = {};
function thisFunc5 () {
  console.log(`this5 equal obj5: ${this===obj5}`);
}
obj5.thisFunc5 = thisFunc5;
obj5.thisFunc5(); // "this5 equal obj5: true"
复制代码
var obj6 = {};
obj6.thisFunc6 = function () {
  console.log(`this6 equal obj6: ${this===obj6}`);
}
obj6.thisFunc6(); // "this6 equal obj6: true"
复制代码
var obj7 = {}, obj77 = {};
obj7.thisFunc7 = function () {
  console.log(`this7 equal obj7: ${this===obj7}`);
  console.log(`this7 equal obj77: ${this===obj77}`);
}
var thisFunc77 = obj7.thisFunc7.bind(obj77)
thisFunc77(); 
// "this7 equal obj7: false"
// "this7 equal obj77: true"
复制代码

5、直接调用

function thisFunc1() { 
  console.log(`this1 equal window: ${this===window}`);
};
thisFunc1(); // "this1 equal window: true"
复制代码

或者换种写法:

var obj8 = {
  thisFunc8: function(){
    console.log(`this8 equal obj8: ${this===obj8}`);
    console.log(`this8 equal window: ${this===window}`);
  }
}
obj8.thisFunc9 = thisFunc77;
obj8.thisFunc9();
// "this7 equal obj7: false"
// "this7 equal obj77: true"

var thisFunc88 = obj8.thisFunc8;
thisFunc88();
// "this8 equal obj8: false"
// "this8 equal window: true"
复制代码

this指向了解测试

题目1. this指针

function logName(){
    console.log(this.name);
}
function doFun1(fn){
    fn();
}
function doFun2(o){
    o.logName();
}
var obj = {
    name: "LiLei",
    logName: logName
};
var name = "HanMeiMei";
doFun1(obj.logName); 
doFun2(obj);
复制代码

结果

HanMeiMei
--------------------------------------------
LiLei
复制代码

题目2.call、apply修改this指向

function fun(somthing) {
  console.log(`name: ${this.name}, somthing: ${somthing}`);
};

function bindFun(fn, obj) {
  return function () {
    return fn.apply(obj, arguments);
  }
}
var obj = { name: "LiLei" };
var bar = bindFun(fun, obj);
console.log(bar);
var b = bar('Sofia');
复制代码

结果

function () {
  return fn.apply(obj, arguments);
}
--------------------------------------------
name: LiLei, somthing: Sofia
复制代码

题目3.立即执行函数

function logName() {
    console.log(this);
    console.log(this.name);
}
var name = "XiaoMing";
var LiLei = { name: "LiLei", logName: logName };
var HanMeiMei = { name: "HanMeiMei" };
(HanMeiMei.logName = LiLei.logName)();
复制代码

结果

window
--------------------------------------------
XiaoMing
复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值