JavaScript中this的理解
citgpt 2024-11-25 10:02 3 浏览 0 评论
在 JavaScript 编程中,this 关键字非常重要,也比较难理解,经常让初学者比较迷惑,所有今天我们一起来聊一下this关键字。
一.this的概述
this是Javascript语言的一个关键字,它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用,随着函数使用场合的不同,this的值会发生变化,但是有一个总的原则,那就是this指的是调用函数的那个对象。
总结:谁调用了这个函数,this指向谁(对象)
二.this的指向
因为this存在于函数内部,通过不同的函数来检测this基本指向。
1.如果函数前面没有对象去调用,那么指向window,但是ES5新增的严格模式除外,因为在严格模式下this指向undefined。
代码如下:
普通函数:
function fn() {
console.log(this);
}
fn();//window
window.fn();//window
解析:普通函数直接调用,默认里面的this都是指向window,同时我们说函数也是window下面的方法,所以也可以通过window来调用,但结果同样指向window.
"use strict";//添加严格模式
function fn() {
console.log(this); //window
}
fn();//undefined
window.fn();//window
解析:严格模式下面如果直接调用函数,根据严格模式的语法行为改变里面的this是指向undefined,但window去调用依然还是指向window
自执行函数:
!(function () {
console.log(this); //window
})();
解析:下面的情况和上面一致,因为是子调用,即前面没有对象调用都指向window,严格模式下面指向undefined
函数表达式:
var声明的函数表达式,同上面的情况一致。
var fn1 = function(){
console.log(this);
}
fn1();//window
window.fn1();//window
let声明的函数表达式
let fn1 = function(){
console.log(this);
}
fn1();//window
window.fn1();//这里会报错 window.fn1 is not a function,因为let声明的函数表达式不是window下面方法,(let具有块作用域和暂时性死区)
2.事件处理函数,自定义对象里面的方法的this指向,根据谁调用函数this指向谁的特性,这里的this都指向当前操作的对象。
document.onclick = function(){
console.log(this);//document
}
解析:因为是document通过事件类型click触发了此函数,所以函数内部的this指向document,事件绑定addEventListener也一样。
const obj = {
name:'zhangsan',
age:18,
showName:function(){
console.log(this);// obj
console.log(this.name);//zhangsan
}
}
obj.showName();
解析:原理同上谁调用了函数,函数内部的this指向谁,这里的showName是obj对象下面的方法,通过obj对象调用,所以指向obj对象。
3.构造函数里面的this指向
因为构造函数的外表跟普通函数差不多,主要区别在于被调用的方式。当用 new 运算符调用函数时,该函数总会返回一个对象,通常情况下,构造函数里的this就指向返回的这个对象。
let MyClass = function(){
this.name = 'zhangsan';
};
let obj = new MyClass();
console.log(obj.name); //zhangsan
解析:构造函数里的this就指向返回的这个对象
但用new调用构造函数时,还要注意一个问题,如果构造函数显式地返回了一个 object 类型的对象,那么此次运算结果最终会返回这个对象,而不是我们之前的this。
let MyClass = function(){
this.name = 'zhangsan';
return { //显式地返回一个对象
name: 'lisi'
}
};
let obj = new MyClass();
console.log (obj.name); //lisi
如果构造函数不显式地返回任何数据,或者是返回一个非对象类型的数据,就不会造成上述问题,主要是new关键字调用函数,函数内部隐式返回this造成的。
let MyClass = function(){
this.name = 'zhangsan'
return 'lisi';
};
let obj = new MyClass();
console.log(obj.name); // 输出:zhangsan
4.箭头函数的this指向。
ES6新增了箭头函数,对于普通函数来说,内部的this指向函数运行时所在的对象,但是这一点对箭头函数不成立。它没有自己的this对象,内部的this就是定义时上层作用域中(父级作用域)的this。也就是说,箭头函数内部的this指向是固定的,相比之下,普通函数的this指向是可变的。
const obj = {
a:1
};
const fn = function () {
alert(this.a);//输出1,因为调用时修改了this指向,所以this指向obj
};
fn.call(obj); //本来this指向window,通过call(下文有讲解)改变this指向obj,最终的this就变成obj
const fn = () => {
alert(this.a);//输出undefined,因为window下面没有a属性。
};
fn.call(obj);//代码里面使用了箭头函数,this就不会受到影响,依然指向window
document.onclick = () => {
alert(this); //window,this来自于父级,如果没有父级,指向window
};
document.onclick = function () {
alert(this); //document,因为document调用了此函数
window.setInterval(() =>{
alert(this); //document,因为使用了箭头函数,this指向外层的函数里面的this.
}, 1000);
};
三.修改this指向的方式。
1.利用call,apply,bind方法。
函数下面有三个方法,call,apply,bind都可以改变this的指向,下面我们来具体演示这三个方法的应用和区别。
call方法:
call方法的第一个参数就是新的this指向, 从第二个参数开始表示函数自身的参数。
const obj = {
a: 100,
};
function sum(x, y) {
console.log(this.a + x + y);
}
sum(3,7);//underfined + 3 + 7 = NaN
解析:直接调用,this指向window,window下面没有a属性,所以window.a是undefined
sum.call(obj, 3, 7); //100 + 3 + 7 = 110
解析:通过call改变this,让其指向obj,obj下面具有a属性,所以obj.a是100
apply方法:
apply方法的第一个参数就是新的this指向, 第二个参数是一个数组或者类数组,里面的值依然是函数自身的参数。
const obj = {
a: 100,
};
function sum(x, y) {
console.log(this.a + x + y);
}
sum(3,7);//underfined + 3 + 7 = NaN
解析:直接调用,this指向window,window下面没有a属性,所以window.a是undefined
sum.apply(obj, [3, 7]); //100 + 3 + 7 = 110 注意中括号是apply的第二个参数必须是数组或者类数组。
解析:通过apply改变this,让其指向obj,obj下面具有a属性,所以obj.a是100
call和apply的简单应用
var obj1 = {
name: 'zhangsan'
};
var obj2 = {
name: 'lisi'
};
window.name = 'window';
var getName = function(){
alert ( this.name );
};
getName(); // 输出: window
getName.call( obj1 ); // 输出: zhangsan
getName.call( obj2 ); // 输出: lisi
bind方法:
bind方法的第一个参数就是新的this指向, 从第二个参数开始表示函数自身的参数,但bind 是返回对应函数体,便于稍后调用,apply、call则是立即调用
const obj = {
a: 100,
};
function sum(x, y) {
console.log(this.a + x + y);
}
sum(3,7);//underfined + 3 + 7 = NaN
解析:直接调用,this指向window,window下面没有a属性,所以window.a是undefined
sum.bind(obj, 3, 7)(); //100 + 3 + 7 = 110 注意这里需要再次调用
解析:通过bind改变this,让其指向obj,obj下面具有a属性,所以obj.a是100
bind的使用场景
案例:将fn函数内部的this指向obj对象,2s后输出this.num的值。
window.num = 100; //window添加属性
const obj = {
num: 1000
}
function fn() {
console.log(this.num);
}
fn(); //100 这里的this指向window
window.setInterval(fn.call(obj), 2000); //此时的定时器无效,已经调用fn函数,
window.setInterval(fn.apply(obj), 2000); //此时的定时器无效,已经调用fn函数
window.setInterval(fn.bind(obj), 2000); //定时器的第一个参数是函数体或者函数名称,bind返回的就是函数体,所以吻合需求。
2.将正确的this存储。
通过变量将需要的this存储下来,然后在函数内部利用存储的this达到我们的目标。
window.num = 2;
function fn() {
console.log(this.num);
}
const obj = {
num: 1,
shownum: function() {
let _this = this;// 通过变量将需要的this存储下来
return function() {
console.log(_this.num); //调用存储的this
}
}
}
obj.shownum();
3.借用其他对象的方法
借用其他对象方法的第一种场景是借用构造函数,通过这种技术,可以实现一些类似继承的效果:
let A = function( name ){
this.name = name;
};
let B = function(){
A.apply( this, arguments );
};
B.prototype.getName = function(){
return this.name;
};
var b = new B( 'zhangsan' );
console.log( b.getName() ); // 输出: 'zhangsan'
借用其他对象方法的第二种场景是借用arguments
我们知道函数的参数列表arguments是一个类数组对象,虽然它也有“下标”,但它并非真正的数组,所以也不能像数组一样,进行排序操作或者往集合里添加一个新的元素。这种情况下,我们常常会借用Array.prototype对象上的方法。比如想往arguments中添加一个新的元素,通常会借用
Array.prototype.push:
(function(){
Array.prototype.push.call( arguments, 3 );
console.log ( arguments ); // 输出[1,2,3]
})( 1, 2 );
在操作 arguments 的时候,我们经常非常频繁地找 Array.prototype 对象借用方法。
四.和this相关的一些经典案例解读
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()());//"The Window"
解析:
var声明的变量是window下面的属性
object对象里面存在方法getNameFunc,而且这个方法的返回值也是一个函数,必须再次调用。
通过返回的函数里面存在this,但是这里的this不是通过object进行调用,因为object.getNameFunc()返回的是一个函数体(普通的函数表达式),需要对函数体进行再次调用,而再次调用就和object对象没有关系了,所以这里的this不会指向object,而是指向window,结果输出"The Window"
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var _this = this;
return function(){
return _this.name;
};
}
};
alert(object.getNameFunc()()); //"My Object"
解析:
这里大部分情况和上面的一致,区别是object.getNameFunc方法里面提前将指向object对象的this存储为变量,并且在返回函数体的时候使用了这个变量,所以返回的函数中的this就是object.getNameFunc方法里面的this,即指向了object对象,结果输出 "My Object"
相关推荐
- 外贸网站建设要多少钱?外贸网站建设周期要多久
-
大家好,我是【无锡柠萌网络lemon56.com】的小美,今天分享:外贸网站建设要多少钱?外贸网站建设周期要多久您关注的问题·FAQ外贸网站建设中遇到的常见问题,让您少走弯路,提高效率!...
- 500块搭建一个可以卖货的跨境电商独立站,包括服务器和域名吗?
-
用500元搭建一个可以卖货的跨境电商独立站,虽然有一定挑战性,但通过精打细算和选择合适的工具和服务,仍然是有可能的。以下是一些建议,帮助你在预算范围内实现这个目标,包括服务器和域名的选择。...
- 无锡网络公司设计搭建阀门网站一般要多少钱?
-
无锡网络公司设计搭建阀门网站一般要多少钱?这是一个涉及多方面因素的复杂问题,其费用因网站规模、功能需求、设计复杂度及后续维护等因素而异。首先,从基础成本出发,域名注册是搭建网站的第一步,费用通常在几十...
- 定制化网站开发大概多少钱
-
定制化网站开发的价格因项目的复杂性、功能需求、设计要求和开发时间等因素而异。以下是一些常见的定制化网站开发价格范围,供参考:1.简单的定制化网站开发:一般来说,一个简单的定制化网站开发项目可能需要花...
- 9月安卓手机性能排行榜出炉:前十名差距仅为7%
-
时间已经进入9月,按照安兔兔目前的安卓手机性能榜单显示,红魔9SPro+依旧力压其他热销手机成为榜首,可见游戏定位的这款手机,在性能上确实非常的出色。不过,笔者也发现了一个问题,其中前十名中得分最高...
- 装修公司怎么在网络平台接单?实现高效获客
-
装修行业正经历着深刻的变革,随着消费者需求的日益多样化与个性化,传统的线下获客方式已难以满足装修公司的业务需求。因此,装修公司必须紧跟时代步伐,充分利用网络平台实现高效获客。1、入驻装修接单平台:壹品...
- 企业如何利用二维码进行线上营销?
-
#企业如何利用二维码进行线上营销?#企业利用二维码进行线上营销,可以从以下几个方面入手:?1.设计创意二维码?:...
- 家电销售该怎么线上拓客
-
社交媒体平台:利用微信、微博、抖音等平台,定期发布家电产品的信息、使用心得、促销活动等内容。引流靠手动一定是不行的,所以一般使用点软件肯定没错,最近用了款比较冷门的APP,"里德助手Plus...
- pop社交软件,脱单软件排行榜
-
在交友软件里面脱单是非常明确的一件事,各年龄各社交平台上的女人都是有所不同的,具体问题具体分析一下。接下来就说说又哪些比较优质的恋爱脱单软件。...
- 手机处理器最新跑分排行榜,你的手机什么水平?
-
手机处理器最新跑分排行榜,你的手机什么水平?第1名:天玑9300第2名:骁龙8Gen3第3名:A17Pro第4名:天玑9200第5名:骁龙8Gen2第6名:骁龙8Gen1...
- 继番茄小说后,字节再推免费网文 App“蛋花小说”和“常读小说”
-
据Tech星球报道,字节跳动公司近期推出了两款全新的免费网文App,分别是“蛋花小说”和“常读小说”。这两款产品的开发公司分别为湖北福瑞兴网络科技有限公司和湖北聚合润网络科技有限公司,均为字节跳动的1...
- 全世界最好用的AI软件排名是?
-
Hey小伙伴们,今天咱们来聊聊那些让人爱不释手的AI神器!在这个智能化时代,谁还没几个拿得出手的AI软件呢?别急,我这就给你盘点一波全球超火的AI软件,保证让你大开眼界!...
- 手机root软件哪个成功率高?手机root软件排行榜2025
-
作为游戏玩家,欲在手游中畅玩无阻,root权限不可或缺,可优化画质、启用辅助。2025年已至,究竟哪些手机root软件能脱颖而出?哪款软件的root成功率会独占鳌头?一、手机root软...
- 独立站新手教程引流篇:如何优化谷歌广告投放效果?
-
随着谷歌广告单价的持续上涨,如何在提升投放效果的同时,降低推广费用成为每一个独立站卖家的必修课。因此新手卖家在完成初步的广告投放流程后,最重要的就是了解一下谷歌广告优化的基础策略。设置转化跟踪即利用G...
- 云媒易:干货知识分享!海外推广的渠道有哪些,如何正确的选择?
-
越来越多的海外企业或国内的跨境商家认识到海外的网络营销的作用,开展线上外贸营销,渠道是非常的重要,那么海外的推广渠道有哪些?企业应该如何选择呢?1、社交媒体推广社交媒体推广是现在海外推广方式中最热门的...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracleclient (56)
- springbatch (59)
- oracle恢复数据 (56)
- 简单工厂模式 (68)
- 函数指针 (72)
- fill_parent (135)
- java配置环境变量 (140)
- linux文件系统 (56)
- 计算机操作系统教程 (60)
- 静态ip (63)
- notifyicon (55)
- 线程同步 (58)
- xcode 4 5 (60)
- 调试器 (60)
- c0000005 (63)
- html代码大全 (61)
- header utf 8 (61)
- 多线程多进程 (65)
- require_once (60)
- 百度网盘下载速度慢破解方法 (72)
- 谷歌浏览器免费入口 (72)
- npm list (64)
- 网站打开速度检测 (59)
- 网站建设流程图 (58)
- this关键字 (67)