js中this对象的理解

一、定义
函数的 this 关键字在 JavaScript 中的表现略有不同,此外,在严格模式和非严格模式之间也会有一些差别
在绝大多数情况下,函数的调用方式决定了 this 的值(运行时绑定)
this 关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用它的对象
举个例子:
function baz() {
// 当前调用栈是:baz
// 因此,当前调用位置是全局作用域
console.log( "baz" );
bar(); // <-- bar的调用位置
}
function bar() {
// 当前调用栈是:baz --> bar
// 因此,当前调用位置在baz中
console.log( "bar" );
foo(); // <-- foo的调用位置
}
function foo() {
// 当前调用栈是:baz --> bar --> foo
// 因此,当前调用位置在bar中
console.log( "foo" );
}
baz(); // <-- baz的调用位置
同时,this在函数执行过程中,this一旦被确定了,就不可以再更改
var a = 10;
var obj = {
a: 20
}
function fn() {
this = obj; // 修改this,运行后会报错
console.log(this.a);
}
fn();
二、绑定规则
根据不同的使用场合,this有不同的值,主要分为下面几种情况:
默认绑定
隐式绑定
new绑定
显示绑定
默认绑定
全局环境中定义person函数,内部使用this关键字
var name = 'Jenny';
function person() {
return this.name;
}
console.log(person()); //Jenny
上述代码输出Jenny,原因是调用函数的对象在浏览器中为window,因此this指向window,所以输出Jenny
注意:
严格模式下,不能将全局对象用于默认绑定,this会绑定到undefined,只有函数运行在非严格模式下,默认绑定才能绑定到全局对象
隐式绑定
函数还可以作为某个对象的方法调用,这时this就指这个上级对象
function test() {
console.log(this.x);
}
var obj = {};
obj.x = 1;
obj.m = test;
obj.m(); // 1
这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象
var o = {
a:10,
b:{
fn:function(){
console.log(this.a); //undefined
}
}
}
o.b.fn();
上述代码中,this的上一级对象为b,b内部并没有a变量的定义,所以输出undefined
这里再举一种特殊情况
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j();
此时this指向的是window,这里的大家需要记住,this永远指向的是最后调用它的对象,虽然fn是对象b的方法,但是fn赋值给j时候并没有执行,所以最终指向window
new绑定
通过构建函数new关键字生成一个实例对象,此时this指向这个实例对象
function test() {
this.x = 1;
}
var obj = new test();
obj.x // 1
上述代码之所以能过输出1,是因为new关键字改变了this的指向
这里再列举一些特殊情况:
new过程遇到return一个对象,此时this指向为返回的对象
function fn()
{
this.user = 'xxx';
return {};
}
var a = new fn();
console.log(a.user); //undefined
如果返回一个简单类型的时候,则this指向实例对象
function fn()
{
this.user = 'xxx';
return 1;
}
var a = new fn;
console.log(a.user); //xxx
注意的是null虽然也是对象,但是此时new仍然指向实例对象
function fn()
{
this.user = 'xxx';
return null;
}
var a = new fn;
console.log(a.user); //xxx
显示修改
apply()、call()、bind()是函数的一个方法,作用是改变函数的调用对象。它的第一个参数就表示改变后的调用这个函数的对象。因此,这时this指的就是这第一个参数
var x = 0;
function test() {
console.log(this.x);
}
var obj = {};
obj.x = 1;
obj.m = test;
obj.m.apply(obj) // 1
关于apply、call、bind三者的区别,我们后面再详细说
三、箭头函数
在 ES6 的语法中还提供了箭头函语法,让我们在代码书写时就能确定 this 的指向(编译时绑定)
举个例子:
const obj = {
sayThis: () => {
console.log(this);
}
};
obj.sayThis(); // window 因为 JavaScript 没有块作用域,所以在定义 sayThis 的时候,里面的 this 就绑到 window 上去了
const globalSay = obj.sayThis;
globalSay(); // window 浏览器中的 global 对象
虽然箭头函数的this能够在编译的时候就确定了this的指向,但也需要注意一些潜在的坑
下面举个例子:
绑定事件监听
const button = document.getElementById('mngb');
button.addEventListener('click', ()=> {
console.log(this === window) // true
this.innerHTML = 'clicked button'
})
上述可以看到,我们其实是想要this为点击的button,但此时this指向了window
包括在原型上添加方法时候,此时this指向window
Cat.prototype.sayName = () => {
console.log(this === window) //true
return this.name
}
const cat = new Cat('mm');
cat.sayName()
同样的,箭头函数不能作为构建函数
四、优先级
隐式绑定 VS 显式绑定
function foo() {
console.log( this.a );
}
var obj1 = {
a: 2,
foo: foo
};
var obj2 = {
a: 3,
foo: foo
};
obj1.foo(); // 2
obj2.foo(); // 3
obj1.foo.call( obj2 ); // 3
obj2.foo.call( obj1 ); // 2
显然,显示绑定的优先级更高
new绑定 VS 隐式绑定
function foo(something) {
this.a = something;
}
var obj1 = {
foo: foo
};
var obj2 = {};
obj1.foo( 2 );
console.log( obj1.a ); // 2
obj1.foo.call( obj2, 3 );
console.log( obj2.a ); // 3
var bar = new obj1.foo( 4 );
console.log( obj1.a ); // 2
console.log( bar.a ); // 4
可以看到,new绑定的优先级>隐式绑定
new绑定 VS 显式绑定
因为new和apply、call无法一起使用,但硬绑定也是显式绑定的一种,可以替换测试
function foo(something) {
this.a = something;
}
var obj1 = {};
var bar = foo.bind( obj1 );
bar( 2 );
console.log( obj1.a ); // 2
var baz = new bar( 3 );
console.log( obj1.a ); // 2
console.log( baz.a ); // 3
bar被绑定到obj1上,但是new bar(3) 并没有像我们预计的那样把obj1.a修改为3。但是,new修改了绑定调用bar()中的this
我们可认为new绑定优先级>显式绑定
综上所述,this的绑定规则 new绑定优先级 > 显示绑定优先级 > 隐式绑定优先级 > 默认绑定优先级
js中this对象的理解的更多相关文章
- 在js中arguments对象的理解
一.在函数调用的时候,浏览器每次都会传递进两个隐式参数 函数的上下文对象this 封装实参的对象arguments 二.arguments 对象 arguments 对象实际上是所在函数的一个内置类数 ...
- 深入理解JS中的对象(一)
目录 一切皆是对象吗? 对象 原型与原型链 构造函数 参考 1.一切皆是对象吗? 首先,"在 JavaScript 中,一切皆是对象"这种表述是不完全正确的. JavaScript ...
- 深入理解JS中的对象(二):new 的工作原理
目录 序言 不同返回值的构造函数 深入 new 调用函数原理 总结 参考 1.序言 在 深入理解JS中的对象(一):原型.原型链和构造函数 中,我们分析了JS中是否一切皆对象以及对象的原型.原型链和构 ...
- 深入理解JS中的对象(三):class 的工作原理
目录 序言 class 是一个特殊的函数 class 的工作原理 class 继承的原型链关系 参考 1.序言 ECMAScript 2015(ES6) 中引入的 JavaScript 类实质上是 J ...
- 浅解析js中的对象
浅解析js中的对象 原文网址:http://www.cnblogs.com/foodoir/p/5971686.html,转载请注明出处. 前面的话: 说到对象,我首先想到的是每到过年过节见长辈的时候 ...
- JS中的对象和方法简单剖析
众所周知,在js中对象就是精髓,不理解对象就是不理解js. 那么什么事js中的对象呢? 在js中,几乎一切皆对象: Boolean ,String,Number可以是对象(或者说原生数据被认作对象): ...
- js中判断对象具体类型
大家可能知道js中判断对象类型可以用typeof来判断.看下面的情况 <script> alert(typeof 1);//number alert(typeof "2" ...
- js中XMLHttpRequest对象实现GET、POST异步传输
js中XMLHttpRequest对象实现GET.POST异步传输 /* * 统一XHR接口 */ function createXHR() { // IE7+,Firefox, Opera, Chr ...
- JavaScript学习12 JS中定义对象的几种方式
JavaScript学习12 JS中定义对象的几种方式 JavaScript中没有类的概念,只有对象. 在JavaScript中定义对象可以采用以下几种方式: 1.基于已有对象扩充其属性和方法 2.工 ...
- js中推断对象详细类型
大家可能知道js中推断对象类型能够用typeof来推断. 看以下的情况 <script> alert(typeof 1);//number alert(typeof "2&quo ...
随机推荐
- GaussDB(DWS)集群通信:详解pooler连接池
本文分享自华为云社区<GaussDB(DWS) 集群通信系列一:pooler连接池>,作者:半岛里有个小铁盒. 1.前言 适用版本:[8.1.0(及以上)] GaussDB(DWS) 为M ...
- 开源:基于mybatis和jpa的数据库安全加密脱敏插件,围观交流
开源:基于mybatis和jpa的数据库安全加密脱敏插件,围观交流
- 协议 UARST & 数据发送与接收
STM32具有的协议 UASRT是通用异步/同步收发器,UART是通用异步收发器 串口空闲状态时高电平,开始传输数据时,第一个数据为固定的低电平: 数据:最后为高电平的停止位 奇偶校验:通过+1或者不 ...
- 基于C语言的串口AT指令发送实例解析
一 知识点 1 AI指令后面一定要加 \n\r 2 注意AT指令里面待双引号的这种,要使用斜杠隔开. 二 源码: void Set_Pdu_Mode(void) { u8 a = 1; if(atKe ...
- Postman全网最详细使用教程
Postman全网最详细使用教程 欢迎关注博主公众号「Java大师」, 专注于分享Java领域干货文章, 关注回复「postman」, 获取postman插件和安装程序: http://www.jav ...
- 踩坑经历-jenkins安装使用
最近在整理之前临时记的笔记,好久之前了,大概记录下. 按照教程安装jenkins,随机选了个不是最新版的docker版本,然后一路下一步,但是到安装推荐插件就没有全部安装成功,我接着走下去想进到&qu ...
- 译:使用 Bun 执行 Shell 脚本
原文地址(Bun Blog): https://bun.sh/blog/the-bun-shell 作者: jarredsumner 发布时间:2024-01-20 前言 JavaScript 是世界 ...
- 开发必会系列:《深入理解JVM(第二版)》读书笔记
一 开始前 HotSpot:http://xiaomogui.iteye.com/blog/857821 http://blog.csdn.net/u011521890/article/detail ...
- 分享一个项目:go `file_line`,在编译器得到源码行号,减少运行期runtime消耗
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 file_line https://github.com/ ...
- MySQL连接数超出最大值报错及修改
报错: create connection SQLException, url: jdbc:mysql://xx.xxx.x.xx:6306/hksk-cloud-mes?characterEncod ...