JS 深入浅出This指向(精简)

Posted 木秀羽林

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS 深入浅出This指向(精简)相关的知识,希望对你有一定的参考价值。

从原理出发

首先我们围绕耳熟能详的“this始终指向它的调用者”开始。这句结论虽然没有什么问题,但是说得过于笼统,还是得深入到背后的执行原理才能举一反三解决问题。

举个简单的例子:

var obj = 
  num: 2;
  foo: function ()  console.log(this.num) 
;

var foo = obj.foo;
var num = 3;

obj.foo();//2

foo();//3

obj.foo();是对象obj调用自身的属性(方法)foothis指向调用者obj
②由var foo = obj.foo;获取函数,并用foo();在全局作用域中调用函数,所以this指向浏览器全局对象Window

内存数据结构的概述

JS之所以设计this,是因为其内存的数据结构的特征。

var obj =  foo:  5 ;

①上面的对象赋值给变量,其实质是JS引擎现在内存中生成foo: 5,然后再把该对象的内存地址赋值给变量obj。也就是说onj.foo实质上是先从obj获取对象的内存地址然后再从地址读取原始对象,最后返回对象属性foo的值。
②原始对象以词典结构保存,一个属性名对应一个属性描述对象。如下图,foo属性的描述对象就包含4个描述属性,而最重要的值保存在描述对象[[value]]中。

foo属性值为函数时,JS引擎同样会先将原始函数保存在内存中,然后把该函数的内存地址存放于foo属性的描述对象中的[[value]]里面。

从原理出发章节参考于JavaScript 的 this 原理——阮一峰的网络日志

为何造就this

我们需要JS在函数体内部可以引用当前环境的其他内部变量,就像这样:

var f = function () - 
  console.log(this.x)//内部引用当前调用者变量x
;

var x = 1;//实质给全局对象Window添加属性 x 并赋值 1
var obj = 
  x: 2,//调用者内部变量
  f: f


f();//结果为1,执行于全局环境,所以 this.x 指向 Window.x
boj.f();//结果为2,执行于 obj 内部环境,所以 this.x 指向 obj.x

这就说明了造就this的目的就是为函数内部的语句指定当前运行环境,而当前运行环境不一定就是该函数内部环境哈。

this的扩展延伸

构造函数与this

function name () 
  this.fne = "yulin"
;

var a = new name();
console.log(a.fne);//yulin

关于这个构造函数这里先笼统提一些,new关键字会创建一个空对象name ,并且会将函数name()的保留在[[Prototype]]原型中而且会执行该函数并返回执行结果(这里有几种情况下文会提到),最后整个对象name 赋值给变量aa即是对象实例。所以this.fne指向a.fne

thisreturn的问题

上文说到构造函数执行的返回结果的有几种情况:

  1. 返回对象时,this会指向返回的对象,null除外,否则指向起始调用者。
function name () 
  this.fne = "yulin";
  return 
;
var a = new name();
console.log(a.fne);//undefined,指向 

function name () 
  this.fne = "yulin";
  return function () 
;
var a = new name();
console.log(a.fne);//undefined,指向 function () 

function name () 
  this.fne = "yulin";
  return null
;
var a = new name();
console.log(a.fne);//yulin,指向 null,null是特殊的对象不会更改 this

function name () 
  this.fne = "yulin";
  return undefined
;
var a = new name();
console.log(a.fne);//yulin,指向 name 

更灵活的this指向方法

  1. 当我们需要在a对象中调用b对象的方法时,我们就需要用到call()方法指定目的运行环境。
const a = 
  name: \'yulin\',
  fn: function (e, q) 
  console.log(this.name);
  console.log(e + q);
  
;

const b = 
  name: \'yhh\'


var x = a.fn
x.call(b, 2, 3);//yhh 5
  1. apply()方法与call()类型,但传入apply的第二个参数必须是数组,就像[1, 2, 3], [a , b, c]以及数组变量。
const a = 
  name: \'yulin\',
  fn: function (e, q) 
  console.log(this.name);
  console.log(e + q);
  
;

const b = 
  name: \'yhh\'


var x = a.fn
x.apply(b, [2, 3]);//yhh 5

/*
以下代码效果一样
let arr = [2, 3];
x.apply(b, arr);
*/

请注意:a.call(null)a.apply(null)this指向都是Window
3. bind()call(), apply()完全不同,bind()改变this指向的同时还返回被调用的属性,方法。

const a = 
  name: \'yulin\',
  fn: function (e, q) 
  console.log(this.name);
  console.log(e + q);
  
;

const b = 
  name: \'yhh\'


var x = a.fn

x.bind(b);
/*ƒ (e, q) 
  console.log(this.name);
  console.log(e + q);
*/

let y = x.bind(b);
y(2, 3);//yhh 5

以上是关于JS 深入浅出This指向(精简)的主要内容,如果未能解决你的问题,请参考以下文章

关于js中this指向的理解总结!

彻底理解js中this的指向

JS引用类型 --- 函数(含this指向面试题)

深入理解JavaScript中的this关键字

Vue框架深入使用(V客学院知识分享)

深入解析JavaScript中的this关键字