JavaScript what is this?由浅入深理解透彻

this 关键字在 JavaScript 中是一个关键字,也是小升初的必考题。

函数的调用方式决定了 this 的值(运行时绑定)。 this 不能在执行期间被赋值,并且在函数每一次被调用时 this 的值也有可能不同
—MDN

我们初步可以理解为使用我,我 this 就指向谁, this 作为一个指针,始终指向调用者。

什么是 this ?

this 是函数在运行时,函数体内部自动生成的一个对象,只能在函数体内部使用

简单的函数调用:

function test() {
	this.name = "code"
  console.log(this === window)  
	console.log(this.name)
}
test() // code 

如果我们在 test 函数中打印 this === window,得到结果为 true ,展开 window 对象可以看到有个 name 属性,值是 code

作为对象方法的调用:

// demo1
function test() {
  console.log(this === window)
	console.log(this.name)
}
let obj = {name: 'wccode'}
obj.fun = test
obj.fun() // false, wccode

// demo2
let demo1 = {name:'demo1',fun:test}
let demo2 = {name:'demo2',fun:test}
demo1.fun() //demo1
demo2.fun() //demo2

this 的值取决于函数被调用的方式。

理解this?

JavaScript 语言之所以有 this 的设计,跟内存里面的数据结构有关系:

数据类型:

值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。
引用数据类型:对象(Object)、数组(Array)、函数(Function)。

数据结构:
**
在计算机科学中, 对象是指内存中的可以被 标识符引用的一块区域,在 Javascript 里,对象可以被看作是一组属性的集合。
**
数据属性的特性(Attributes of a data property)

特性数据类型描述默认值
[[Value]]任何Javascript类型包含这个属性的数据值。undefined
[[Writable]]Boolean如果该值为 false,则该属性的 [[Value]] 特性 不能被改变。false
[[Enumerable]]Boolean如果该值为 true,则该属性可以用 for…in 循环来枚举。false
[[Configurable]]Boolean如果该值为 false,则该属性不能被删除,并且 除了 [[Value]] 和 [[Writable]] 以外的特性都不能被改变。false

强烈建议阅读:JavaScript 数据类型和数据结构 | MDN

将一个对象赋值给变量 obj :

let obj = { name: "code" }
// 对象是引用类型,JS引擎在内存生成对象后,其实是把对象的内存地址赋值给了变量 obj 。也就是说,变量 obj 是一个地址(reference)
obj.name
// JS 引擎先从 obj 拿到内存地址,然后再从地址中读出原始对象,返回它的 name 属性

函数也属于引用类型,所以函数可以在不同的运行环境中执行,所以需要有一种机制,可以在函数体内部获得当前的运行环境(context), this 的出现就是为了这个需求,目的就是在函数体内部,获得函数当前的运行环境。 this 也很无辜~

理解this,使用场景

全局环境

全局环境使用 this ,this指向是顶层对象。

this === window // true

function f() {
  console.log(this === window);
}
f() // true

构造函数

构造函数中使用 this , this 指向实例对象。

var Obj = function (p) {
  this.p = p;
};
var o = new Obj('Hello World!');
o.p // "Hello World!"

对象内的方法

这条规则水很深,你把握不住的

正常情况:

var obj ={
  foo: function () {
    console.log(this);
  }
};

obj.foo() // obj obj.foo 执行,内部this指向obj

例外情况 01 :

参考的阮老师文章,阮老师这里写的有点不好理解

// 情况一
(obj.foo = obj.foo)() // window
// 情况二
(false || obj.foo)() // window
// 情况三
(1, obj.foo)() // window

上面三种情况可以理解为:

let test = obj.foo
test() // window

前面写过,函数是引用类型,对象内的函数也如此,obj 和 obj.foo 是两个储存地址。上面几种情况相当于将 foo 内存地址给到 test,test() 直接调用,运行环境就是全局环境,所以 this 指向全局环境。
例外情况 02:
对象包对象,this 不会像变量一样往上查找,牢记 this 指向调用者。

var a = {
  p: 'Hello',
  b: {
    m: function() {
      console.log(this.p);
    }
  }
};

a.b.m() // undefined

// 相当于 

var b = {
  m: function() {
   console.log(this.p);
  }
};

var a = {
  p: 'Hello',
  b: b
};

(a.b).m() // 等同于 b.m()

改造:

var a = {
  b: {
    m: function() {
      console.log(this.p);
    },
    p: 'Hello'
  }
};

var hello = a.b.m;
hello() // undefined

为什么 hello() 会是 undefined,画重点哈,又遇到了,function是引用类型,m 这个其实是函数的一个地址,直接使用 hello = a.b.m相当于将函数地址赋值给 hello 变量,执行 hello() 。这个时候在全局环境执行,所以 this.p 是 undefined。

箭头函数

箭头函数没有定义this绑定

用之前的例子作对比

var obj ={
  foo: ()=> {
    console.log(this);
  }
};

obj.foo() // window 

切换/绑定 this

JavaScript 提供了callapplybind这三个方法,来切换/固定this的指向,这里不多做介绍

call & apply

// 对象可以作为 bind 或 apply 的第一个参数传递,并且该参数将绑定到该对象。
var obj = {a: 'Custom'};

// 声明一个变量,并将该变量作为全局对象 window 的属性。
var a = 'Global';

function whatsThis() {
  return this.a;  // this 的值取决于函数被调用的方式
}

whatsThis();          // 'Global' 因为在这个函数中 this 没有被设定,所以它默认为 全局/ window 对象
whatsThis.call(obj);  // 'Custom' 因为函数中的 this 被设置为obj
whatsThis.apply(obj); // 'Custom' 因为函数中的 this 被设置为obj

bind

ECMAScript 5 引入了 Function.prototype.bind()。调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。

function f(){
  return this.a;
}

var g = f.bind({a:"azerty"});
console.log(g()); // azerty

bind使用要慎重
bind() 方法每次运行,都会创建一个新函数。
一是会有性能问题,二是会产生闭包,应用在事件绑定中,则无法取消。

最佳实践

  1. 通过将this值分配给封闭的变量,可以解决this问题。
  2. 避免使用全局变量,在局部作用域中保存其他对象的引用

参考链接:

红宝石 | javascript 高级程序设计
MDN | this
MDN | JavaScript 数据类型和数据结构
阮一峰 | Javascript 的 this 用法
阮一峰 | JavaScript 教程

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值