前端里的this指向问题

news2025/3/12 19:15:08

目录

1.代码输出结果

2.代码输出结果

3.代码输出结果

4.代码输出结果

5.代码输出结果

6.代码输出结果

7.代码输出结果

8.代码输出结果

9.代码输出结果

10.代码输出结果

11.代码输出结果

12.代码输出结果

13.代码输出结果

14.代码输出结果

总结


1.代码输出结果

function foo() {
  console.log( this.a );
}

function doFoo() {
  foo();
}

var obj = {
  a: 1,
  doFoo: doFoo
};

var a = 2; 
obj.doFoo()

输出结果为2,因为执行foo的是doFoo函数,函数默认执行window

但是如果doFoo函数里:

function doFoo() {
        // foo();
        console.log(this.a);//1
      }

输出的就是1,因为执行它的是obj对象,会隐式的把this指向obj对象

2.代码输出结果

var a = 10
var obj = {
  a: 20,
  say: () => {
    console.log(this.a)
  }
}
obj.say() //10  


var anotherObj = { a: 30 } 
obj.say.apply(anotherObj) //10

输出结果为10;10

apply或者bind通过绑定会指向里面的参数

但是这个是往外翻两层到window这层,所以都是最外层的a=10

如果换成普通函数的话就是20;30

3.代码输出结果

function a() {
  console.log(this);
}
a.call(null);

输出结果为window

call里面的参数如果是null或者undefined的话,this就会指向全局对象(浏览器里是window)

但是在严格模式情况下,参数是null输出的就是null;参数是undefined输出的是undefined

4.代码输出结果

var obj = { 
  name: 'cuggz', 
  fun: function(){ 
     console.log(this.name); 
  } 
} 
obj.fun()     // cuggz
new obj.fun() // undefined

第二个new是取出了obj里的fun作为新的构造函数,所以里面没有name参数,结果为undefined

5.代码输出结果

var obj = {
   say: function() {
     var f1 = () =>  {
       console.log("1111", this);
     }
     f1();
   },
   pro: {
     getPro:() =>  {
        console.log(this);
     }
   }
}
var o = obj.say;
o();
obj.say();
obj.pro.getPro();

第一个:o=obj.say然后再调用o(),其实相当于是:

o=function() {
     var f1 = () =>  {
       console.log("1111", this);
     }
     f1();
   },

而且里面是箭头函数,翻第一层到f1,第二层到o,o是一个函数,它拥有this,与o平级的this就是window

第二个:obj.say() 翻第一层到f1,第二层到say,say平级的this就是obj

第三个:obj.pro.getPro()第一层翻到getPro,翻第二层到pro(注意对象是没有this 的!!只有函数有!),所以第二层直接翻到最外层,this就是window

对象不构成单独的作用域=>没有this

6.代码输出结果

var myObject = {
    foo: "bar",
    func: function() {
        var self = this;
        console.log(this.foo);  
        console.log(self.foo);  
        (function() {
            console.log(this.foo);  
            console.log(self.foo);  
        }());
    }
};
myObject.func();

func是myObject调用的,所以func里面的this是myObject,那么self也是

this.foo就是bar

self.foo也是bar

下面的函数被调用,里面作用域的this是func,所以它里面没有foo属性,输出undefined

然后最后一个self.foo,这块是一个闭包,里面函数可以调用外层函数的属性self.foo===bar

7.代码输出结果

window.number = 2;
var obj = {
 number: 3,
 db1: (function(){
   console.log(this);
   this.number *= 4;
   return function(){
     console.log(this);
     this.number *= 5;
   }
 })()
}
var db1 = obj.db1;
db1();
obj.db1();
console.log(obj.number);     // 15
console.log(window.number);  // 40

⚠️注意:obj.db1是个立即执行函数,它在obj对象定义完之后就会执行,然后返回后面的函数

所以在下面一系列调用函数之前就会有一次输出window,而且此时window上的number=8,在非严格模式下,自执行函数IIFE输出的this就是window

所以第一次先会输出一个window,此时这个函数变成了这样:

window.number = 2;
var obj = {
 number: 3,
 db1: function(){
     console.log(this);
     this.number *= 5;
  }
}
var db1 = obj.db1;
db1();
obj.db1();
console.log(obj.number);     // 15
console.log(window.number);  // 40

db1=obj.db1之后,db1如下:

db1=function(){
     console.log(this);
     this.number *= 5;
  }

打印这个this就是window(db1时函数不是对象),此时window . number=5*8=40

然后调用obj.db1(),this打印obj对象,obj.number=3*5=15

8.代码输出结果

var length = 10;
function fn() {
    console.log(this.length);
}
 
var obj = {
  length: 5,
  method: function(fn) {
    fn();
    arguments[0]();
  }
};
 
obj.method(fn, 1);

fn()这样调用只是一个普通函数,而不是作为对象的方法去调用,所以this是window,输出10

而arguments承接参数fn和1,但是这次相当于arguments(因为它是个类数组对象!)去调用方法,所以this指向arguments,而且它是伪数组有length,输出2

9.代码输出结果

var a = 1;
function printA(){
  console.log(this.a);
}
var obj={
  a:2,
  foo:printA,
  bar:function(){
    printA();
  }
}

obj.foo(); // 2
obj.bar(); // 1
var foo = obj.foo;
foo(); // 1

obj.foo(),foo里的this指向obj;它跟上面的区别是:上面那个只是由obj穿参的,但是不是obj去调用的,只是函数进行到那里去调用了,不是对象调用的,而这个就是obj调用的,所以this是obj;

obj.bar(),现在printA函数就不是由obj对象调用而进行的了,所以printA函数里的this是全局对象,输出1;

var foo=obj.foo,那么foo相当于(foo是函数):

全局上的foo:printA,this是window,输出1

10.代码输出结果

var x = 3;
var y = 4;
var obj = {
    x: 1,
    y: 6,
    getX: function() {
        var x = 5;
        return function() {
            return this.x;
        }();
    },
    getY: function() {
        var y = 7;
        return this.y;
    }
}
console.log(obj.getX()) // 3
console.log(obj.getY()) // 6

第一个:又是一个立即执行函数,IIFE里面的this指向全局对象,所以x=3

第二个:调用对象是obj,this是obj的this,输出6

11.代码输出结果

 var a = 10; 
 var obt = { 
   a: 20, 
   fn: function(){ 
     var a = 30; 
     console.log(this.a)
   } 
 }
 obt.fn();  // 20
 obt.fn.call(); // 10
 (obt.fn)(); // 20

obt.fn()调用者是obj,所以函数里的this是obj,输出obj的a,20

obt.fn.call(),call用来改变this,但是里面的参数为空(null),call里的参数为undefined或者null,this就是全局对象window,所以输出a为10

()的作用是改变运算顺序,所以这个跟第一个没什么区别,输出20

12.代码输出结果

function a(xx){
  this.x = xx;
  return this
};
var x = a(5);
var y = a(6);

console.log(x.x)  // undefined
console.log(y.x)  // 6

x一开始相当于:

var x=function a(5){

this.x=5;

return this

}

没有对象调用这个函数,所以this.x说的是window.x=5,最后return this => window,返回的window又赋值回给var x了,所以最外层的window.x=window,x.x=undefined

顺序:

window.x=5

var x=window=>window.x=window

y一开始相当于:

var y=function a(6){

this.x=6;

return this

}

window上的x=6,返回window赋值给y

顺序:

window.x=6

window=y

输出y.x=6

13.代码输出结果

function foo(something){
    this.a = something
}

var obj1 = {
    foo: foo
}

var obj2 = {}

obj1.foo(2); 
console.log(obj1.a); // 2

obj1.foo.call(obj2, 3);
console.log(obj2.a); // 3

var bar = new obj1.foo(4)
console.log(obj1.a); // 2
console.log(bar.a); // 4

先是调用obj1.foo(2),obj1去调用的函数,所以obj1里的a是2,下面输出为2

然后obj1.foo.call(obj2,3),obj2上的a赋值为3

var bar=new obj1.foo(4)这是又new了一个,所以不会赋值之前的2,obj1上的a输出还是2

bar相当于:

var bar=function foo(){},注意new出来的比隐式绑定优先级高,所以里面的this是bar,bar的a就是4

14.代码输出结果

function foo(something){
    this.a = something
}

var obj1 = {}

var bar = foo.bind(obj1);
bar(2);
console.log(obj1.a); // 2

var baz = new bar(3);
console.log(obj1.a); // 2
console.log(baz.a); // 3

这一步相当于:

var bar=function foo(sm){

this.a=sm;(this是obj1)

},obj1上

bar(2)=> obj1.a=2

var baz= new bar(3),new出来的比bind绑定的优先级高,所以this是baz,baz上的a为3

总结

改变this指向的四种方式:

函数默认指向,this是window

对象调用函数,函数里的this指向对象

显示绑定:call、apply、bind绑定,有参数绑定参数,null或者undefined就是window

通过new绑定this

其中new>显示>对象调用>默认指向

箭头函数里的this是一开始就定义好的,与后来谁去调用没有关系,this会继承自定义时的外层作用域,而且对象不会创建作用域,所以往外翻的时候只能翻到函数上

就比如这张图,obj.say()第一层到f1函数,第二层到say函数,然后找与say函数平级的this

obj.pro.getPro()第一层到getPro函数,第二层到最外层window

还有一些特殊情况比如立即执行匿名函数IIFE,在非严格模式下this就是window

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2299722.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

黑马Redis详细笔记(实战篇---短信登录)

目录 一.短信登录 1.1 导入项目 1.2 Session 实现短信登录 1.3 集群的 Session 共享问题 1.4 基于 Redis 实现共享 Session 登录 一.短信登录 1.1 导入项目 数据库准备 -- 创建用户表 CREATE TABLE user (id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 用户ID,phone …

基于N-gram模型的中文文本分析系统设计与实现

前言 在数字化人文研究快速发展的背景下,中文古典文本的量化分析面临着独特的挑战。古典文献中繁简异体字共存、语义单元边界模糊、意象隐喻密集等特征,使得传统的词频统计方法难以准确捕捉其深层语言规律。现有文本分析工具多面向现代汉语设计&#xff…

零基础购买阿里云服务器,XShell连接云服务器

目录 1.环境搭建方式 2. 使用云服务器 3.使用终端软件登录到Linux 4.使用XShell登录主机 5.连接失败的原因: 下一篇更新:Linux的基础指令以及如何Linux的环境搭建 1.环境搭建方式 主要有四种: 1.直接安装在物理机上,虽然Linux有图形化…

CNN手写数字识别1——模型搭建与数据准备

模型搭建 我们这次使用LeNet模型,LeNet是一个经典的卷积神经网络(Convolutional Neural Network, CNN)架构,最初由Yann LeCun等人在1998年提出,用于手写数字识别任务 创建一个文件model.py。实现以下代码。 源码 #…

深度学习04 数据增强、调整学习率

目录 数据增强 常用的数据增强方法 调整学习率 学习率 调整学习率 ​调整学习率的方法 有序调整 等间隔调整 多间隔调整 指数衰减 余弦退火 ​自适应调整 自定义调整 数据增强 数据增强是通过对训练数据进行各种变换(如旋转、翻转、裁剪等)&am…

PH热榜 | 2025-02-16

1. Cal.com Routing 标语:根据客户线索,系统会智能地自动安排约会。 介绍:告别繁琐的排期!Cal.com 推出了新的路由功能,能更智能地分配预约,让你的日程安排更顺畅。这项功能运用智能逻辑和深入的数据分析…

数据库基本概念及基本使用

数据库基本概念 什么是数据库: 数据库特点: 常见的数据库软件: 不同的公司进行不同的实践,生成了不同的产品。 比如买汽车,汽车只是一个概念,你要买哪个牌子哪个型号的汽车,才是真正的汽车的一…

gozero实现数据库MySQL单例模式连接

在 GoZero 框架中实现数据库的单例连接可以通过以下步骤来完成。GoZero 使用 gorm 作为默认的数据库操作框架,接下来我会展示一个简单的单例模式实现。 ### 1. 定义数据库连接的单例结构 首先,你需要定义一个数据库连接的结构体,并在初始化…

CSS flex布局 列表单个元素点击 本行下插入详情独占一行

技术栈:Vue2 javaScript 简介 在实际开发过程中有遇到一个场景:一个list,每行个数固定,点击单个元素后,在当前行与下一行之间插入一行元素详情,便于更直观的查看到对应的数据详情。 这种情形&#xff0c…

无人机航迹规划: 梦境优化算法(Dream Optimization Algorithm,DOA)求解无人机路径规划MATLAB

一、梦境优化算法 梦境优化算法(Dream Optimization Algorithm,DOA)是一种新型的元启发式算法,其灵感来源于人类的梦境行为。该算法结合了基础记忆策略、遗忘和补充策略以及梦境共享策略,通过模拟人类梦境中的部分记忆…

权限五张表

重点:权限五张表的设计 核心概念: 在权限管理系统中,经典的设计通常涉及五张表,分别是用户表、角色表、权限表、用户角色表和角色权限表。这五张表的设计可以有效地管理用户的权限,确保系统的安全性和灵活性。 用户&…

Docker-数据卷

1.数据卷 容器是隔离环境,容器内程序的文件、配置、运行时产生的容器都在容器内部,我们要读写容器内的文件非常不方便。大家思考几个问题: 如果要升级MySQL版本,需要销毁旧容器,那么数据岂不是跟着被销毁了&#xff1…

IT : 是工作還是嗜好? Delphi 30周年快乐!

又到2月14日了, 自从30多年前收到台湾宝蓝(Borland)公司一大包的3.5 磁盘片, 上面用黑色油性笔写着Delphi Beta开始, Delphi便和我的工作生涯有了密不可分的关系. 一年后Delphi大获成功, 自此对于使用Delphi的使用者来说2月14日也成了一个特殊的日子! 我清楚记得Delphi Beta使用…

DeepPose

目录 摘要 Abstract DeepPose 算法框架 损失函数 创新点 局限性 训练过程 代码 总结 摘要 DeepPose是首个将CNN应用于姿态估计任务的模型。该模型在传统姿态估计方法的基础上,通过端到端的方式直接从图像中回归出人体关键点的二维坐标,避免了…

[HarmonyOS]鸿蒙(添加服务卡片)推荐商品 修改卡片UI(内容)

什么是服务卡片 ? 鸿蒙系统中的服务卡片(Service Card)就是一种轻量级的应用展示形式,它可以让用户在不打开完整应用的情况下,快速访问应用内的特定功能或信息。以下是服务卡片的几个关键点: 轻量级&#…

DeepSeek R1 本地部署和知识库搭建

一、本地部署 DeepSeek-R1,是幻方量化旗下AI公司深度求索(DeepSeek)研发的推理模型 。DeepSeek-R1采用强化学习进行后训练,旨在提升推理能力,尤其擅长数学、代码和自然语言推理等复杂任务 。 使用DeepSeek R1, 可以大大…

领域驱动设计叕创新,平安保险申请DDD专利

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 见下图: 这个名字拼得妙:领域驱动设计模式。 是领域驱动设计?还是设计模式?还是领域驱动设计设计模式?和下面这个知乎文章的…

团体程序设计天梯赛-练习集——L1-041 寻找250

前言 10分的题,主要的想法就一个,按这个想法可以出几个写法 L1-041 寻找250 对方不想和你说话,并向你扔了一串数…… 而你必须从这一串数字中找到“250”这个高大上的感人数字。 输入格式: 输入在一行中给出不知道多少个绝对值…

C#控制台大小Console.SetWindowSize函数失效解决

在使用C#修改控制台大小相关API会失效. 由于VS将控制台由命令提示符变成了终端,因此在设置大小时会出现问题 测试代码: Console.SetWindowSize(100, 50);

spring boot 对接aws 的S3 服务,实现上传和查询

1.aws S3介绍 AWS S3(Amazon Simple Storage Service)是亚马逊提供的一种对象存储服务,旨在提供可扩展、高可用性和安全的数据存储解决方案。以下是AWS S3的一些主要特点和功能: 1.1. 对象存储 对象存储模型:S3使用…