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 相关文章推荐
将函数的实际参数转换成数组的方法
Jan 25 Javascript
将HTML的左右尖括号等转义成实体形式的两种实现方式
May 04 Javascript
jQuery实现的仿百度分页足迹效果代码
Oct 30 Javascript
javaScript嗅探执行神器-sniffer.js
Feb 14 Javascript
基于node.js的fs核心模块读写文件操作(实例讲解)
Sep 10 Javascript
Vue2.0用户权限控制解决方案
Nov 29 Javascript
vue+vuex+axios+echarts画一个动态更新的中国地图的方法
Dec 19 Javascript
Vue异步组件处理路由组件加载状态的解决方案
Sep 07 Javascript
详解Node.js 中使用 ECDSA 签名遇到的坑
Nov 26 Javascript
ES6入门教程之Array.from()方法
Mar 23 Javascript
详解Vue之事件处理
Jul 10 Javascript
解决vue项目打包上服务器显示404错误,本地没出错的问题
Nov 03 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中常见的缓存技术实例分析
2015/09/23 PHP
php实现和c#一致的DES加密解密实例
2017/07/24 PHP
PHP十六进制颜色随机生成器功能示例
2017/07/24 PHP
PHP7移除的扩展和SAPI
2021/03/09 PHP
jquery中的事件处理详细介绍
2013/06/24 Javascript
JS JSON对象转为字符串的简单实现方法
2013/11/18 Javascript
js和jquery使按钮失效为不可用状态的方法
2014/01/26 Javascript
javascript操作符&quot;!~&quot;详解
2015/02/10 Javascript
JS+CSS实现实用的单击输入框弹出选择框的方法
2015/02/28 Javascript
JS实现弹性漂浮效果的广告代码
2015/09/02 Javascript
Jquery+ajax+JAVA(servlet)实现下拉菜单异步取值
2016/03/23 Javascript
el表达式 写入bootstrap表格数据页面的实例代码
2017/01/11 Javascript
bootstrap table表格使用方法详解
2017/04/26 Javascript
vue实现点击当前标签高亮效果【推荐】
2018/06/22 Javascript
JavaScript日期工具类DateUtils定义与用法示例
2018/09/03 Javascript
JS中使用react-tooltip插件实现鼠标悬浮显示框
2019/05/15 Javascript
Jquery动态列功能完整实例
2019/08/30 jQuery
微信小程序授权登陆及每次检查是否授权实例代码
2019/09/18 Javascript
Vue常用API、高级API的相关总结
2021/02/02 Vue.js
[01:11:15]VGJ.S vs Secret 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
PHP网页抓取之抓取百度贴吧邮箱数据代码分享
2016/04/13 Python
详解Python3.6的py文件打包生成exe
2018/07/13 Python
在python Numpy中求向量和矩阵的范数实例
2019/08/26 Python
Python大数据之使用lxml库解析html网页文件示例
2019/11/16 Python
Python3操作读写CSV文件使用包过程解析
2020/04/10 Python
Python unittest discover批量执行代码实例
2020/09/08 Python
Windows环境下Python3.6.8 importError: DLLload failed:找不到指定的模块
2020/11/01 Python
PurCotton全棉时代官网:100%天然棉花生产的生活护理用品
2016/11/18 全球购物
北美三大旅游网站之一:Travelocity
2017/08/12 全球购物
Superdry极度干燥美国官网:英国制造的服装品牌
2018/11/13 全球购物
医院总经理职责
2013/12/26 职场文书
教学实习自我评价
2014/01/28 职场文书
圣诞节开幕词
2015/01/29 职场文书
暗恋桃花源观后感
2015/06/12 职场文书
z-index不起作用
2021/03/31 HTML / CSS
Go 语言中 20 个占位符的整理
2021/10/16 Golang