浅谈JavaScript中this的指向更改


Posted in Javascript onJuly 28, 2020

JS中this指向的更改

JavaScript 中 this 的指向问题 前面已经总结过,但在实际开中, 很多场景都需要改变 this 的指向。 现在我们讨论更改 this 指向的问题。

call更改this指向

call 的使用语法:func.call(thisArg, arg1, arg2, ...)

call 方法需要一个指定的 this 值( this要指向的对象 )和一个或者多个参数。提供的 this 值会更改调用函数内部的 this 指向。

// 使用 call 方法改变调用函数执行上下文的 this 指向
var animal = '小猫';
var times = '15小时';
function greet() {
 let str = this.animal + '睡觉时间一般为:' + this.times;
 console.log(str);
}
var dogObj = {
 animal: '小狗',
 times: '8小时'
};
var pigObj = {
 animal: '小猪',
 times: '13小时'
}
greet(); // 小猫睡觉时间一般为:15小时
greet.call(dogObj); // 小狗睡觉时间一般为:8小时
greet.call(pigObj); // 小猪睡觉时间一般为:13小时
greet.call(); // 小猫睡觉时间一般为:15小时

当直接调用函数 greet 时,函数 greet 内部的 this 指向的是全局对象 Window。

函数 greet 调用 call() 方法并传递对象 dogObj 时,函数 greet 内部的 this 就指向了对象 dogObj 。

函数 greet 调用 call() 方法并传递对象 pigObj 时,函数 greet 内部的 this 就指向了对象 pigObj 。

call()不传参的话,在严格模式下,this 的值将会是 undefined;否则将会指向全局对象 Window。

匿名函数调用call方法:

var books = [{
 name: 'CSS选择器',
 price: 23
}, {
 name: 'CSS世界',
 price: 35
}, {
 name: 'JavaScript语言设计',
 price: 55
}];
for (var i = 0; i < books.length; i++) {
 (function (i) {
  // 这里this指向的是call绑定的数组的每一个元素对象
  this.printf = function () {
   console.log(`${i} ${this.name}: ¥${this.price}`);
  }
  this.printf();
 }).call(books[i], i);
}
// 打印结果如下:
// 0 CSS选择器: ¥23
// 1 CSS世界: ¥35
// 2 JavaScript语言设计: ¥55

call实现继承:

// 实现两个数相加的构造函数
function CalcA(){
 this.add = function(a, b){
  return a + b;
 }
}
// 实现两个数相减的构造函数
function CalcS(){
 this.sub = function(a, b){
  return a - b;
 }
}
// 计算构造函数
function Calc(){
 console.log(this); // Calc {}
 CalcA.call(this);
 CalcS.call(this);
 console.log(this); // Calc {add: ƒ, sub: ƒ}
}
var calc = new Calc();
console.log(calc.add(2, 3)); // 5
console.log(calc.sub(10, 1));// 9

构造函数 Calc 通过 call 方法使构造函数 CalcA、CalcS中的 this 指向了 Calc 自己,从而继承了它们的属性及方法。所以,构造函数 Calc 生成的实例对象也能够访问构造函数 CalcA、CalcS中的属性及方法。

apply方法更改this指向

apply 的使用语法:func.apply(thisArg, [argsArray])

apply 的用法与 call 方法类似,只不过 call 方法接受的是参数列表,而 apply 方法接受的是一个数组或者类数组对象。上面的例子完全可以将 call 更换为 apply,只不过 apply 方法只能接受两个参数,而且第二个参数是一个数组或者类数组对象。

bind方法更改this指向

bind 的使用语法:func.bind(thisArg, arg1, arg2, ...)

bind 的参数与 call 相同,但是 bind 返回的是一个改变this指向后的函数实例。

var petalNum = 100;
function Flower() {
 this.petalNum = Math.ceil(Math.random() * 10) + 1;
}
Flower.prototype.declare = function() {
 console.log(this);
 console.log('this is a beautiful flower with ' + this.petalNum + ' petals');
}
Flower.prototype.bloom = function() {
 console.log(this); // Flower {petalNum: 7}
 // 如果不绑定 this 就会指向 Window 全局对象
 window.setTimeout(this.declare, 1000);
 // bind 绑定 this,指向 Flower 的原型对象
 window.setTimeout(this.declare.bind(this), 2000);
}
var flower = new Flower();
flower.bloom();

实例对象 flower 调用 bloom 方法后,bloom 内的 this 指向构造函数的原型对象。

1 秒后延迟函数调用构造函数的 declare 方法, 此时执行函数 declare 中的 this 指向 Window 。打印的结果如下:

// Window {parent: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
// this is a beautiful flower with 100 petals

2 秒后延迟函数调用构造函数的 declare 方法,此时执行函数 declare 通过 bind 将 this(构造函数的原型对象)绑定。打印的结果如下:

// 注意,此时petalNum的值时随机取的。
// Flower {petalNum: 7}
// this is a beautiful flower with 7 petals

这里将 bind换 成 call,apply 会导致立即执行,延迟效果会失效。

ES6的箭头函数更改this指向

箭头函数中的 this 是在定义函数的时候绑定,而不是在执行函数的时候绑定。 所谓定义时候绑定,就是指 this 是继承自父执行上下文的 this。

var a = 1;
var obj = {
 a: 2,
 f1: function(){
  console.log(this.a)
 },
 f2: () => {
  console.log(this.a)
 }
}
obj.f1(); // 2
obj.f2(); // 1

obj.f1() 执行后打印的是 2,这里好理解,obj 调用 f1 函数,那么函数中的 this 就指向调用对象 obj。可以看出,这里 this 是在执行函数的时候绑定的。

obj.f2() 执行后打印的是 1。f2 是箭头函数,那么函数中的 this 是继承自父执行上下文的 this。这里箭头函数的父级是对象 obj,obj 的执行上下文就是全局对象 Window,那么箭头函数中的 this 就指向了全局对象了。

再看一个例子:

var a = 11;
function test() {
 this.a = 22;
 let b = () => { console.log(this.a) }
 b();
}
test(); // 22

按着定义的理解,应该打印出 11 才对呀,因为箭头函数父级的执行上下文就是 Window 全局对象,此时打印的是全局对象的 a。

先不要着急,先慢慢分析,上面的分析是对的,箭头函数的 this 就是指向 Window 对象。test 函数在全局环境下调用时其内部的 this 就指向了全局 Window 对象,代码中的 this.a = 22;就将全局中的 a 重新赋值了,所以箭头函数在全局对象中找到的 a 值就是 22。我们可以在控制台上输入 window.a 查看全局对象中的 a 值,结果打印 22,所以我们就不难理解箭头函数中打印的结果为什么是 22 了。如果将代码中的 this.a = 22; 修改为 var a = 22;,那么箭头函数中打印的结果就是 11 了。

箭头函数会继承外层函数调用的 this 绑定,这和 var self = this;的绑定机制一样。箭头函数中,this 指向固定化,箭头函数根本就没有自己的 this, 所以也就不能用作构造函数使用了。

到此这篇关于浅谈JavaScript中this的指向更改的文章就介绍到这了,更多相关JavaScript中this指向更改内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
通过js脚本复制网页上的一个表格的不错实现方法
Dec 29 Javascript
excel操作之Add Data to a Spreadsheet Cell
Jun 12 Javascript
JavaScript中的对象化编程
Jan 16 Javascript
JSONP 跨域共享信息
Aug 16 Javascript
ExtJs纵坐标值重复问题的解决方法
Feb 27 Javascript
jQuery Mobile中的button按钮组件基础使用教程
May 23 Javascript
Vuejs第十一篇组件之slot内容分发实例详解
Sep 09 Javascript
JS封装的选项卡TAB切换效果示例
Sep 20 Javascript
vue.js配合$.post从后台获取数据简单demo分享
Aug 11 Javascript
Vue结合后台导入导出Excel问题详解
Feb 19 Javascript
javascript的this关键字详解
May 20 Javascript
js实现简易ATM功能
Oct 27 Javascript
Postman内建变量常用方法实例解析
Jul 28 #Javascript
使用Webpack 搭建 Vue3 开发环境过程详解
Jul 28 #Javascript
解决Vue使用bus总线时,第一次路由跳转时数据没成功传递问题
Jul 28 #Javascript
解决vue bus.$emit触发第一次$on监听不到问题
Jul 28 #Javascript
vue+element-ui JYAdmin后台管理系统模板解析
Jul 28 #Javascript
vue实现虚拟列表功能的代码
Jul 28 #Javascript
vue.js 解决v-model让select默认选中不生效的问题
Jul 28 #Javascript
You might like
利用PHP生成静态HTML文档的原理
2012/10/29 PHP
解析用PHP实现var_export的详细介绍
2013/06/20 PHP
PHP文件去掉PHP注释空格的函数分析(PHP代码压缩)
2013/07/02 PHP
PHP IE中下载附件问题解决方法
2014/01/07 PHP
php中FTP函数ftp_connect、ftp_login与ftp_chmod用法
2014/11/18 PHP
PHP5.5迭代生成器用法实例详解
2016/03/16 PHP
浅谈mysql_query()函数的返回值问题
2016/09/05 PHP
PHP中cookie知识点学习
2018/05/06 PHP
JavaScript的Function详细
2006/11/14 Javascript
js下获取div中的数据的原理分析
2010/04/07 Javascript
Javascript 面向对象编程(一) 封装
2011/08/28 Javascript
js获取客户端外网ip的简单实例
2013/11/21 Javascript
微信小程序 购物车简单实例
2016/10/24 Javascript
Web前端框架Angular4.0.0 正式版发布
2017/03/28 Javascript
JS实现去除数组中重复json的方法示例
2017/12/21 Javascript
原生javascript AJAX 三级联动的实现代码
2018/05/04 Javascript
webpack4之SplitChunksPlugin使用指南
2018/06/12 Javascript
通过实例解析js可枚举属性与不可枚举属性
2020/12/02 Javascript
详谈python http长连接客户端
2017/06/12 Python
Python3 操作符重载方法示例
2017/11/23 Python
Python爬取十篇新闻统计TF-IDF
2018/01/03 Python
python实现简易版计算器
2020/06/22 Python
python实现定时提取实时日志程序
2018/06/22 Python
详解python while 函数及while和for的区别
2018/09/07 Python
使用APScheduler3.0.1 实现定时任务的方法
2019/07/22 Python
python3 批量获取对应端口服务的实例
2019/07/25 Python
Python实现验证码识别
2020/06/15 Python
美国著名的女性内衣零售商:Frederick’s of Hollywood
2018/02/24 全球购物
2013年军训通讯稿
2014/02/05 职场文书
中学生自我评价范文
2014/02/08 职场文书
运动会稿件100字
2014/02/21 职场文书
高中生学期学习自我评价
2014/02/24 职场文书
低碳生活倡议书
2014/04/14 职场文书
青春飞扬演讲稿
2014/09/11 职场文书
小学生毕业评语
2014/12/26 职场文书
成品仓管员岗位职责
2015/04/01 职场文书