浅谈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 相关文章推荐
Javascript学习笔记1 数据类型
Jan 11 Javascript
JavaScript回调(callback)函数概念自我理解及示例
Jul 04 Javascript
jquery模拟LCD 时钟的html文件源代码
Jun 16 Javascript
Jquery注册事件实现方法
May 18 Javascript
简介JavaScript中substring()方法的使用
Jun 06 Javascript
JavaScript String(字符串)对象的简单实例(推荐)
Aug 31 Javascript
node.js实现博客小爬虫的实例代码
Oct 08 Javascript
JavaScript实现的微信二维码图片生成器的示例
Oct 26 Javascript
js编写的treeview使用方法
Nov 11 Javascript
JS中常用的消息框总结
Feb 24 Javascript
序列化模块json代码实例详解
Mar 03 Javascript
Vue 解决通过this.$refs来获取DOM或者组件报错问题
Jul 28 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
常用星际术语索引(新手指南)
2020/03/04 星际争霸
音乐朗读剧《MARS RED》2021年TV动画化决定!
2020/03/06 日漫
discuz Passport 通行证 整合笔记
2008/06/30 PHP
php递归删除目录下的文件但保留的实例分享
2014/05/10 PHP
php单元测试phpunit入门实例教程
2017/11/17 PHP
常见的5个PHP编码小陋习以及优化实例讲解
2021/02/27 PHP
一个很简单的办法实现TD的加亮效果.
2006/06/29 Javascript
自适应图片大小的弹出窗口
2006/07/27 Javascript
javascript Array对象基础知识小结
2010/11/16 Javascript
如何使用jQuery来处理图片坏链具体实现步骤
2013/05/02 Javascript
js导航栏单击事件背景变换示例代码
2014/01/13 Javascript
javascript的事件触发器介绍的实现
2014/06/05 Javascript
简介JavaScript中用于处理正切的Math.tan()方法
2015/06/15 Javascript
jQuery实现可关闭固定于底(顶)部的工具条菜单效果
2015/11/06 Javascript
javascript帧动画(实例讲解)
2017/09/02 Javascript
vue实现仿淘宝结账页面实例代码
2017/11/08 Javascript
实现div滚动条默认最底部以及默认最右边的示例代码
2017/11/15 Javascript
微信小程序实现顶部下拉菜单栏
2018/11/04 Javascript
微信小程序textarea层级过高(盖住其他元素)问题的解决办法
2019/03/04 Javascript
浅谈Angular单元测试总结
2019/03/22 Javascript
vue微信分享的实现(在当前页面分享其他页面)
2019/04/16 Javascript
优雅的处理vue项目异常实战记录
2019/06/05 Javascript
[04:16]DOTA2全国高校联赛16强抽签
2018/05/02 DOTA
[07:01]DOTA2-DPC中国联赛正赛 Aster vs Magma 3月5日 赛后选手采访
2021/03/11 DOTA
Python中的命令行参数解析工具之docopt详解
2017/03/27 Python
如何使用scrapy中的ItemLoader提取数据
2020/09/30 Python
世界上最大的在线旅行社新加坡网站:Expedia新加坡
2016/08/25 全球购物
美国成衣女装品牌:CHICO’S
2016/09/19 全球购物
Lentiamo荷兰:在线订购隐形眼镜、隐形眼镜液和太阳镜
2019/10/25 全球购物
领导检查欢迎词
2014/01/14 职场文书
医院检讨书范文
2014/02/01 职场文书
项目经理任命书范本
2014/06/05 职场文书
夫妻双方自愿离婚协议书
2014/10/24 职场文书
政风行风评议个人心得体会
2014/10/29 职场文书
Python控制台输出俄罗斯方块的方法实例
2021/04/17 Python
React如何使用axios请求数据并把数据渲染到组件
2022/08/05 Javascript