JS中this指向的更改
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, 所以也就不能用作构造函数使用了。
JS中this指向的更改的更多相关文章
- 前端js中this指向及改变this指向的方法
js中this指向是一个难点,花了很长时间来整理和学习相关的知识点. 一. this this是JS中的关键字, 它始终指向了一个对象, this是一个指针; 参考博文: JavaScript函数中的 ...
- JavaScript面向对象(一)——JS OOP基础与JS 中This指向详解
前 言 JRedu 学过程序语言的都知道,我们的程序语言进化是从"面向机器".到"面向过程".再到"面向对象"一步步的发展而来.类似于 ...
- 关于js中this指向的理解总结!
关于js中this指向的理解! this是什么?定义:this是包含它的函数作为方法被调用时所属的对象. 首先,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁 ...
- js中this指向的三种情况
js中this指向的几种情况一.全局作用域或者普通函数自执行中this指向全局对象window,普通函数的自执行会进行预编译,然后预编译this的指向是window //全局作用域 console.l ...
- 关于js中this指向的总结
js中this指向问题一直是个坑,之前一直是懵懵懂懂的,大概知道一点,但一直不知道各种情况下指向有什么区别,今天亲自动手测试了下this的指向. 1.在对象中的this对象中的this指向我们创建的对 ...
- JS中this指向问题和改变this指向
首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然 ...
- 如何理解JS中this指向的问题
首先,用一句话解释this,就是:指向执行当前函数的对象. 当前执行,理解一下,也就是说this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定.this到底指向谁?this的最终指向的 ...
- 关于js中this指向的问题
this的绑定规则有4种 默认绑定 隐性绑定 显性绑定 new绑定 this绑定优先级 new 绑定 > 显性绑定 > 隐性绑定 > 默认绑定 1.如果函数被new 修饰 this绑 ...
- js中this指向学习总结
在面向对象的语言中(例如Java,C#等),this 含义是明确且具体的,即指向当前对象.一般在编译期绑定. 然而js中this 是在运行期进行绑定的,这是js中this 关键字具备多重含义的本质 ...
随机推荐
- 关于JSON数据体积优化的一点小心得
最近在做的一个项目里传输的json数据比较大,造成了线程间的卡顿,于是想优化一下json数据的体积. 可以看到在json文件里有很多无用的字段,这些字段占据了大量的存储空间. 对数据的结构作一下优化, ...
- 安装Zabbix5.0
目录 概述 支持的平台 安全相关 支持TimescaleDB agent升级 垂直菜单 部署 安装要求 数据库要求 前端要求 服务端要求 Agent 2 Java gateway 安装 配置镜像源 安 ...
- Python:三元表达式、列表推导式和生成器表达式
三元表达式 语法格式 如下: 为真时的结果 if 判断条件 else 为假时的结果 例子 name = input('姓名>>: ') res = '请进' if name == '张三' ...
- HBase中加盐(Salting)之后的表如何读取:协处理器文章
我们介绍了避免数据斑点的三种比较常见方法: 加盐-盐腌 哈希-散列 反转-反转 其中在加盐(Salting)的方法里面是这么描述的:给Rowkey分配一个随机指针以使其和之前排序不同.但是在Rowke ...
- CentOS7.5搭建ES6.2.4集群与简单测试
一 简介 Elasticsearch是一个高度可扩展的开源全文搜索和分析引擎.它允许您快速,近实时地存储,搜索和分析大量数据.它通常用作支持具有复杂搜索功能和需求的应用程序的底层引擎/技术. 下载地址 ...
- 修改VirtualBox中mac的分辨率
转自 http://www.ztyhome.com/virtualbox-mac-fen-bian-lv/?replytocom=3162 最近在windows上用VirtualBox安装了MAC o ...
- .NETCore微服务探寻(三) - 分布式日志
前言 一直以来对于.NETCore微服务相关的技术栈都处于一个浅尝辄止的了解阶段,在现实工作中也对于微服务也一直没有使用的业务环境,所以一直也没有整合过一个完整的基于.NETCore技术栈的微服务项目 ...
- 手把手教你基于SqlSugar4编写一个可视化代码生成器(生成实体,以SqlServer为例,文末附源码)
在开发过程中免不了创建实体类,字段少的表可以手动编写,但是字段多还用手动创建的话不免有些浪费时间,假如一张表有100多个字段,手写有些不现实. 这时我们会借助一些工具,如:动软代码生成器.各种ORM框 ...
- CLR垃圾收集器
CLR GC是一种引用跟踪算法,大致步骤如下: 1.暂停进程中所有的线程: 2.标记阶段,遍历堆中的所有对象,标记为删除,然后检查所有活动根,如果有引用对象,就标记那个对象可达,否则不可达: 3.GC ...
- 入门大数据---Flume整合Kafka
一.背景 先说一下,为什么要使用 Flume + Kafka? 以实时流处理项目为例,由于采集的数据量可能存在峰值和峰谷,假设是一个电商项目,那么峰值通常出现在秒杀时,这时如果直接将 Flume 聚合 ...