JavaScript中this的全面解析及常见实例


Posted in Javascript onMay 14, 2019

前言

this 关键字在 Javascript 中非常常见,但是很多开发者很难说清它到底指向什么。大部分人会从字面意思上去理解 this,认为 this 指向函数自身,实际上this 是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调
用时的各种条件。this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。

总结: 函数被调用时发生 this 绑定,this 指向什么完全取决于函数在哪里被调用。

一、this 的绑定规则

this 一共有 4 中绑定规则,接下来一一介绍每种规则的解释和规则直接的优先级

  • 默认绑定(严格/非严格模式)
  • 隐式绑定
  • 显式绑定
  • new 绑定

1.1 默认绑定(严格/非严格模式)

  • 独立函数调用: 独立函数调用时 this 使用默认绑定规则,默认绑定规则下 this 指向 window(全局对象)。
  • 严格模式下: this 无法使用默认绑定,this 会绑定到 undefined。

独立函数调用

function foo() {
 console.log(this.a);
}
var a = 2;
foo(); // 2

严格模式下:

function foo() {
 "use strict";
 console.log(this); //undefined
 console.log(this.a); //Uncaught TypeError: Cannot read property 'a' of undefined
}
var a = 2;
foo();

注意下边两种情况

var age = "18";
var obj = {
 name: "heyushuo",
 age: 25,
 fn: function() {
 function sayName() {
  console.log(this); //window
  console.log(this.age); //undefined
 }
 sayName();
 }
};
obj.fn();

函数 sayName 虽然是在 obj.fn 内部定义的,但是它仍然是一个独立函数调用,this 仍然指向 window。

var a = "global";
var obj = {
 a: 2,
 foo: function() {
 console.log(this.a); //global
 }
};
var bar = obj.foo; // 函数别名!
bar();

虽然 bar 是 obj.foo 的一个引用,但是实际上,它引用的是函数本身,因此此时的
bar() 其实是一个不带任何修饰的独立函数调用,因此应用了默认绑定。

1.2 隐式绑定

当函数引用有上下文对象时(例如:obj.foo 这个时候使用 obj 上下文来引用函数 foo),隐式绑定规则会把函数中的 this 绑定到这个上下文对象。

var obj = {
 name: "heyushuo,
 foo: function() {
 console.log(this.name); //heyushuo
 }
};

obj.foo();

对象属性引用链中只有上一层或者说最后一层在调用中起作用。

var obj = {
 name: "heyushuo",
 obj1: {
 name: "kebi",
 foo: function() {
  console.log(this.name); // kebi
 }
 }
};

obj.obj1.foo();

隐式丢失

被隐式绑定的函数会丢失绑定对象,而应用默认绑定,把 this 绑定到全局对象或者 undefined(严格模式) 上。

第一种

var a = "global";
var obj = {
 a: 2,
 foo: function() {
 console.log(this.a); //global
 }
};
var bar = obj.foo; // 函数别名!
bar();

虽然 bar 是 obj.foo 的一个引用,但是实际上,它引用的是函数本身,因此此时的bar() 其实是一个不带任何修饰的独立函数调用,因此应用了默认绑定。

第二种传入回调函数时:

var a = "global";
var obj = {
 a: 2,
 foo: function() {
 console.log(this.a); //global
 }
};
var bar = obj.foo; // 函数别名!
function doFoo(fn) {
 fn(); // <-- 调用位置!
}
doFoo(bar); //global

//和下边这种一样
setTimeout(obj.foo, 300);

1.3 显示绑定

通过 call() 或者 apply()方法。第一个参数是一个对象,在调用函数时将这个对象绑定到 this 上,称之为显示绑定。

function foo() {
 console.log(this.a);
}
var obj = {
 a: 2
};
foo.call(obj); // 2

显示绑定引申出来一个硬绑定,代码如下

function foo(something) { 
 console.log( this.a, something ); 
 return this.a + something;
}
// 简单的辅助绑定函数
function bind(fn, obj) { 
 return function() {
 return fn.apply( obj, arguments ); //内部已经强制绑定了传入函数this的指向
 };
}
var obj = { 
 a:2
};
var bar = bind( foo, obj ); 
var b = bar( 3 ); // 2 3
console.log( b ); // 5

bar函数无论如何调用,它总会手动在 obj 上调用 fn,强制把 fn 的 this 绑定到了 obj。这样也解决前面提到的丢失绑定问题
由于硬绑定是一种非常常用的模式,所以在 ES5 中提供了内置的方法 Function.prototype.bind

function foo(something) { 
 console.log( this.a, something ); 
 return this.a + something;
}
var obj = { 
 a:2
};
var bar = foo.bind( obj );
var b = bar( 3 ); // 2 3 
console.log( b ); // 5

1.4 new绑定

使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。

  • 创建(或者说构造)一个全新的对象。
  • 这个新对象会被执行 [[ 原型 ]] 连接。
  • 这个新对象会绑定到函数调用的 this。
  • 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。

例如:

function foo() { 
 this.name = "heyushuo";
 this.age = 25
} 
foo.prototype.sayName = function(){
 console.log(this.name+this.age);
}
var bar = new foo();

console.log(bar); //{name: "heyushuo", age: 25}
//这个新对象会绑定到函数调用的 this。所以此时的this就是bar对象
console.log( bar.age ); // 25

如下图是 new foo() 这个对象

JavaScript中this的全面解析及常见实例

二、四种绑定关系的优先级

判断this,可以按照下面的顺序来进行判断:

1、函数是否在 new 中调用(new 绑定)?如果是的话 this 绑定的是新创建的对象。

var bar = new foo()

2、函数是否通过 call、apply(显式绑定)或者硬绑定调用?如果是的话,this 绑定的是指定的对象。

var bar = foo.call(obj2)

3、函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this 绑定的是那个上下文对象。

var bar = obj1.foo()

4、如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到 undefined,否则绑定到全局对象。

var bar = foo()

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
IE中createElement需要注意的一个问题
Jul 13 Javascript
JS获取计算机mac地址以及IP的实现方法
Jan 08 Javascript
javascript实现获取浏览器版本、操作系统类型
Jan 29 Javascript
jQuery实现hover合成事件的方法
Aug 06 Javascript
jQuery实现链接的title快速出现的方法
Feb 20 Javascript
Angular 4.x 动态创建表单实例
Apr 25 Javascript
JQuery和html+css实现带小圆点和左右按钮的轮播图实例
Jul 22 jQuery
浅谈react 同构之样式直出
Nov 07 Javascript
Vue2.0设置全局样式(less/sass和css)
Nov 18 Javascript
Vue 与 Vuex 的第一次接触遇到的坑
Aug 16 Javascript
JQuery绑定事件四种实现方法解析
Dec 02 jQuery
Nest.js散列与加密实例详解
Feb 24 Javascript
jquery 验证用户名是否重复代码实例
May 14 #jQuery
记录vue项目中遇到的一点小问题
May 14 #Javascript
javascript中如何判断类型汇总
May 14 #Javascript
详解如何探测小程序返回到webview页面
May 14 #Javascript
JQuery获取元素尺寸、位置及页面滚动事件应用示例
May 14 #jQuery
javascript实现遮罩层动态效果实例
May 14 #Javascript
JQuery animate动画应用示例
May 14 #jQuery
You might like
php基础知识:类与对象(5) static
2006/12/13 PHP
作为PHP程序员应该了解MongoDB的五件事
2013/06/03 PHP
thinkphp备份数据库的方法分享
2015/01/04 PHP
PHP使用JSON和将json还原成数组
2015/02/12 PHP
Javascript实例教程(19) 使用HoTMetal(2)
2006/12/23 Javascript
JavaScript中的isXX系列是否继续使用的分析
2011/04/16 Javascript
如何使用jQUery获取选中radio对应的值(一句代码)
2013/06/03 Javascript
JavaScript实现下拉列表框数据增加、删除、上下排序的方法
2015/08/11 Javascript
jQuery布局组件EasyUI Layout使用方法详解
2017/02/28 Javascript
基于cropper.js封装vue实现在线图片裁剪组件功能
2018/03/01 Javascript
详解koa2学习中使用 async 、await、promise解决异步的问题
2018/11/13 Javascript
Three.js实现简单3D房间布局
2018/12/30 Javascript
js实现京东秒杀倒计时功能
2019/01/21 Javascript
微信小程序模板消息推送的两种实现方式
2019/08/27 Javascript
vue 使用v-for进行循环的实例代码详解
2020/02/19 Javascript
vue中解决chrome浏览器自动播放音频和MP3语音打包到线上的实现方法
2020/10/09 Javascript
[02:42]2014DOTA2国际邀请赛 三冰专访:我会打到Ti20
2014/07/13 DOTA
[40:05]DOTA2上海特级锦标赛A组小组赛#1 EHOME VS MVP.Phx第一局
2016/02/25 DOTA
Python编程把二叉树打印成多行代码
2018/01/04 Python
详解python使用递归、尾递归、循环三种方式实现斐波那契数列
2018/01/16 Python
python3中zip()函数使用详解
2018/06/29 Python
python ftp 按目录结构上传下载的实现代码
2018/09/12 Python
python实现将汉字保存成文本的方法
2018/11/16 Python
python实现复制文件到指定目录
2019/10/16 Python
如何基于python对接钉钉并获取access_token
2020/04/21 Python
Python实现进度条和时间预估的示例代码
2020/06/02 Python
Python 实现简单的客户端认证
2020/07/29 Python
Python Opencv图像处理基本操作代码详解
2020/08/31 Python
css3圆角样式分享自定义按钮样式
2013/12/27 HTML / CSS
使用HTML5拍照示例代码
2013/08/06 HTML / CSS
L’AGENCE官网:加州女装品牌
2018/06/03 全球购物
ANINE BING官方网站:奢华的衣橱基本款和时尚永恒的单品
2019/11/26 全球购物
工程师岗位职责
2013/11/08 职场文书
《他得的红圈圈最多》教学反思
2014/04/24 职场文书
淘宝客服工作职责
2014/07/11 职场文书
大学毕业谢师宴致辞
2015/07/27 职场文书