JS中this的指向

news2024/11/27 8:08:24

JS中this的指向

本文目录

  • JS中this的指向
      • 全局上下文(Global Context)
      • 函数上下文(Function Context)
        • 普通函数调用
        • 作为对象的方法调用
        • 构造函数调用
        • 箭头函数
        • 回调函数
      • 事件处理器上下文(Event Handler Context)
      • 通过 call,apply,bind 改变this指向

  1. this永远指向一个对象

  2. this的指向完全取决于函数调用的位置

  3. JavaScript支持运行环境动态切换,this的指向是动态的

全局上下文(Global Context)

在全局执行环境中(在任何函数体外部),this都是指向全局对象,在浏览器中,window对象即是全局对象。

// 在浏览器中,window 对象同时也是全局对象:
console.log(this === window); // true

a = 37;
console.log(window.a); // 37

this.b = "MDN";
console.log(window.b)  // "MDN"
console.log(b)         // "MDN"
console.log(this.b)    // "MDN"

函数上下文(Function Context)

在函数内部,this的值取决于函数的调用方式。这包括普通函数调用、作为对象的方法调用、构造函数调用、以及通过call、apply或bind方法调用。

普通函数调用

如果一个函数不是作为对象的方法被调用,而是作为普通函数被调用,那么 this 通常指向全局对象(在严格模式下,this 是 undefined)

var name = 'window';
var doSth = function(){
  console.log(this.name);
}
doSth();  // 'window'

let 不给顶层对象添加属性(浏览器为Window)

let name2 = 'window2';
let doSth2 = function(){
  console.log(this === window);
  console.log(this.name2);
}
doSth2() // true, undefined

严格模式下,正常函数中的 this 行为不同,如未定义输出undefined

'use strict'
var name3 = 'window3';
var doSth3 = function(){
    console.log(typeof this === 'undefined');
    console.log(this.name3);
}
doSth3();

window.doSth3();

作为对象的方法调用

如果一个函数作为对象的方法被调用,this 就指向这个对象

var name = 'window';
var doSth = function(){
    console.log(this.name);
}
var student = {
    name: 'dog',
    doSth: doSth,
    other: {
        name: 'other',
        doSth: doSth,
    }
}

student.doSth(); // 'dog'
// call like this
student.doSth.call(student);

student.other.doSth(); // 'other'
// call like this
student.other.doSth.call(student.other);

将对象中的函数分配给变量,实际上又是一个普通函数,所以使用普通函数的规则(默认绑定)。

var studentDoSth = student.doSth;
studentDoSth(); // 'window'
// call like this :
studentDoSth.call(undefined);

o.f() 被调用时,函数内的 this 将绑定到 o 对象

var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};

console.log(o.f()); // 37

也可以先定义函数,然后再将其附属到o.f,这样做的结果是一样的

var o = {prop: 37};

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // 37

原型链中的 this
对于在对象原型链上某处定义的方法,同样的概念也适用。如果该方法存在于一个对象的原型链上,那么 this 指向的是调用这个方法的对象

var o = {
  f: function() {
    return this.a + this.b;
  }
};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5

构造函数调用

当一个函数用作构造函数时(使用new关键字),this 指向新创建的对象。

function Foo() {
  this.name = 'Test';
  console.log(this);
}

// 使用new关键字调用
var obj = new Foo();  // this指向新创建的obj对象
console.log(obj.name); // 输出 'Test'

// 不使用new关键字调用
Foo();  // this指向全局对象(非严格模式)或undefined(严格模式)
console.log(window.name); // 在非严格模式下,输出 'Test'
  1. 如果构造函数没有返回对象(也就是没有返回值或者返回非对象),那么new表达式的结果就是新创建并且被this关键字指向的对象。
  2. 如果构造函数返回一个对象,那么new表达式的结果就是这个返回的对象。
function C(){
  this.a = 37;
}

var o = new C();
console.log(o.a); // logs 37


function C2(){
  this.a = 37;
  return {a:38};
}

o = new C2();
console.log(o.a); // logs 38

箭头函数

箭头函数上下文(Arrow Function Context)
箭头函数不绑定this,它会捕获其所在(即定义的位置)的上下文的this值作为自己的this值。

this 被设置为它被创建时的环境

var name = 'window';
var student = {
    name: 'dog',
    doSth: function(){
        // var self = this;
        var arrowDoSth = () => {
            // console.log(self.name);
            console.log(this.name);
        }
        arrowDoSth();
    },
    arrowDoSth2: () => {
        console.log(this.name);
    }
}
student.doSth(); // 'dog'
student.arrowDoSth2(); // 'window'

不能通过call、apply、bind来绑定箭头函数的this(它本身没有this

var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true

// 作为对象的一个方法调用
var obj = {foo: foo};
console.log(obj.foo() === globalObject); // true

// 尝试使用 call 来设定 this
console.log(foo.call(obj) === globalObject); // true

// 尝试使用 bind 来设定 this
foo = foo.bind(obj);
console.log(foo() === globalObject); // true

call、apply、bind可以绑定缓存箭头函数上面的普通函数的this

var student = {
    name: 'dog',
    doSth: function(){
        console.log(this.name);
        return () => {
            console.log('arrowFn:', this.name);
        }
    }
}
var person = {
    name: 'person',
}
student.doSth().call(person); // 'dog'  'arrowFn:' 'dog'
student.doSth.call(person)(); // 'person' 'arrowFn:' 'person'

回调函数

回调函数中 this 的指向,决定于执行回调函数 时的执行上下文环境

(function(){
  console.log(this); // window
})();

setTimeout(() => {
  console.log(this); // window
}, 0);

setTimeout(function(){
  console.log(this); // window
}, 0);

组合使用

第一个setTimeout,执行obj.getage 之后,相当于setTimeout的回调是一个匿名函数,执行的时候,函数内部未设置this的指向。相当于是普通函数调用。所以this默认指向window,所以结果是undefined。

第二个setTimeout,传给setTimeout的也是一个匿名回调函数,执行匿名函数,执行到 obj.getage() 的时候,getage函数里的this,指向的就是obj了,所以能打印出10。遵循 谁调用产生 this指针的函数,this就指向谁的规则

var obj = {
    age:10,
    getage:function(){
        console.log(this.age)
    }
}

setTimeout(obj.getage,1000)   // undefined

setTimeout(function(){
    obj.getage()  // 10
},1000)
let obj={
  a:222,
  fn:function(){    
    setTimeout(()=>{console.log(this.a)});
  }
};
obj.fn(); // 222
var name = 'window'; 
var A = {
  name: 'A',
  sayHello: () => {
    console.log(this.name)
  }
}

A.sayHello(); // 输出的是window,根据刚才讲的规则就可以判断

// 那如何改造成永远绑定A呢:

var name = 'window'; 
var A = {
  name: 'A',
  sayHello: function(){
    var s = () => console.log(this.name)
    return s//返回箭头函数s
  }
}

var sayHello = A.sayHello();
sayHello();// 输出A 
let obj = {
  value: 'Hello, World',
  print: function() {
    setTimeout(function() {
      console.log(this.value);
    }, 1000);
  }
};

obj.print();  // 输出:undefined(严格模式)或者一个全局value(非严格模式)


let obj = {
  value: 'Hello, World',
  print: function() {
    setTimeout(() => {
      console.log(this.value);  // 输出:Hello, World
    }, 1000);
  }
};

// 或者

let obj = {
  value: 'Hello, World',
  print: function() {
    setTimeout(function() {
      console.log(this.value);
    }.bind(this), 1000);
  }
};

事件处理器上下文(Event Handler Context)

在DOM事件处理器中,this通常指向触发事件的元素。

在事件处理函数(或者说事件监听器)中,this通常指向触发事件的 DOM 元素。第一个事件监听器中,this打印出来的是按钮元素本身。

bluify函数作为事件处理函数使用,因此在这个函数中,this指向触发点击事件的按钮元素。

let btn = document.getElementById('btn');

btn.addEventListener('click', function () {
  console.log(this);  // button
});

btn.addEventListener('click', bluify, false);

function bluify(e) {
  console.log(this === e.currentTarget); // 总是 true

  // 当 currentTarget 和 target 是同一个对象时为 true
  console.log(this === e.target);
  this.style.backgroundColor = '#A5D9F3';
}

通过 call,apply,bind 改变this指向

  • call(a, b, c方法接收三个参数,第一个是this指向,第二个,三个是传递给函数的实参,可以是数字,字符串,数组等类型的数据类型都可以

  • apply(a, [b])和call基本上一致,唯一区别在于传参方式,apply把需要传递给fn()的参数放到一个数组(或者类数组)中传递进去,虽然写的是一个数组,但是也相当于给fn()一个个的传递

  • bind(a, b, c:语法和call一模一样,区别在于立即执行还是等待执行

fn.bind(第一个参数是this的指向)
fn.call(第一个参数是this的指向,parma2,param3...)
fn.apply(第一个参数是this的指向,[parma2,parma3..])
//call()方法:改变fn中的this,并且把fn立即执行
fn.call(obj, 1, 2); 
//bind()方法:改变fn中的this,fn并不执行
fn.bind(obj, 1, 2); 
var obj = {
  name:'111',
  getName:function(){
    console.log(this.name)
  }
};

var otherObj = {
  name:'222',
};

var name = '333';
        
obj.getName();               // 111
obj.getName.call();          // 333
obj.getName.call(otherObj);  // 222
obj.getName.apply();         // 333
obj.getName.apply(otherObj); // 222
obj.getName.bind(this)();    // 333
obj.getName.bind(otherObj)();// 222

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

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

相关文章

find_package深度解析及实例应用

1. 检索模式 1.1 module模式 在这个模式下会查找一个名为find.cmake的文件,首先去CMAKE_MODULE_PATH指定的路径下去查找,然后去cmake安装提供的查找模块中查找(安装cmake时生成的一些cmake文件)。找到之后会检查版本,…

大模型全情投入,低代码也越来越清晰

众所周知,不少互联网企业在大模型领域全情投入。那么在这阵阵浪潮中,我们可以观察到什么样的“众生相”? 今年3月以来,国内已有超过20家企业入局大模型赛道。从百度“文心一言”、阿里“通义千问”的发布,华为“盘古”…

解决Kali的Python版本切换问题以及pip2安装问题

问题背景 需要使用Python2版本运行脚本,但是Kali系统自从2021后Python2,3共存 解决方案 (1)打开终端输入以下命令,但是需要有root权限 update-alternatives --install /usr/bin/python python /usr/bin/python2 100…

k8s介绍

目录 1:k8s概念 2:为什么引入k8s和k8s特性 2.1 为什么要引入k8s: 2.2 k8s特性 3 K8S架构 1:k8s概念 k8s官方网站:Kubernetes Kubernetes 是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和…

数据库基础——5.运算符

这篇文章我们来讲一下SQL语句中的运算符操作。 说点题外话:SQL本质上也是一种计算机语言,和C,java一样的,只不过SQL是用来操作数据库的。在C,java中也有运算符,这两种语言中的运算符和数学中的运算符差距不…

【形形色色的卷积】差分卷积

文章目录 0. 前言1. 中心差分卷积2. 像素差分卷积3. 参考 0. 前言 普通卷积不能显式地提取图像的梯度信息,因此不能较好地描述细粒度的纹理信息,在人脸活体检测、边缘检测等对细粒度纹理信息敏感的任务中难以取得理想的结果。针对上述问题,O…

基于STM32的定时器--定时中断(HAL库)

基于STM32的定时器--定时中断(HAL库) 介绍引言定时器介绍 实例项目介绍准备设计流程 介绍 引言 本文旨在介绍如何使用STM32CubeMX配置KEIL 5开发一个每10us定时器中断触发一次的项目。帮助初学者入门STM32的定时器使用。 定时器介绍 定时器是STM32微…

2.信息安全之常用黑客攻击手段

1.自己也可以建CA系统 winserver2003 https 准备2台机器xpsp3(证书,Web),在同一网段,https通讯 –>网络内部网络(同一网段) (iso镜像才有网络和服务…这个镜像已 经安装好了(不能乱删)) sp1 2 3 的网络 改 tcp/ip 属性 ip地址112.26.0.1 和子网掩码255.0.0.0(与ip地址对应,…

opencv_c++学习(二十七)

一、单目相机模型 上图为针孔相机成像原理,蓝色坐标中的O即为镜头光心。成像原理与小孔成像相同。 单目相机映射关系如下: 将上式进行变换,就可以从三位空间映射到2维平面的公式。 相机的畸变公式如下: 二、模型投影函数 vo…

数据结构基础内容-----第五章 串

文章目录 串串的比较串的抽象数据类型串的顺序存储结构朴素的额模式匹配算法kmp模式匹配算法 串 在计算机编程中,串(String)是指由零个或多个字符组成的有限序列。它是一种基本的数据类型,在许多编程语言中都得到了支持和广泛应用…

STM32之SPI和W25Q128

目录 SPI 介绍 SPI 物理架构 SPI 工作原理 SPI 工作模式 W25Q128 介绍 W25Q128 存储架构 W25Q128 常用指令 W25Q128 状态寄存器 W25Q128 常见操作流程 实验:使用 SPI 通讯读写 W25Q128 模块 硬件接线 cubeMX配置 w25q128_write_nocheck流程图 代码&a…

如何在华为OD机试中获得满分?Java实现【最长回文子串】一文详解!

✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 🌟专栏地址: Java华为OD机试真题(2022&2023) 文章目录 1. 题目描述2. 输入描述3. 输出描述…

网络原理(八):HTTPS

目录 HTTP 基本工作流程 利用对称密钥进行加密 利用非对称密钥进行加密 引入了第三方权威机构加密 之前在http 协议中说到:我们现在很少有网站直接使用HTTP 协议的,而是使用HTTPS ,至于什么原因,本篇会介绍清楚。 HTTPS 其实…

C++11 -- lambda表达式

文章目录 lamaba表达式的引入lambda表达式语法lamabda达式各部分说明捕获列表说明 lamaba表达式底层原理探索 lamaba表达式的引入 在C11之前,如果我们想对自定义类型Goods排序,可以根据姓名,价格,学号按照从大到小或者从小到大的方式排序,可是,这样我们要写额外写6个相关的仿函…

以太坊学习三: Merkle树和验证

Merkle tree简介 Merkle树又称为哈希树,是一种二叉树,由一个根节点、若干中间节点和一组叶节点组成。最底层的叶节点存储数据,在它之上的一层节点为它们对应的Hash值,中间节点是它下面两个子节点的Hash值,根节点是最后…

DAY 66 数据库缓存服务——NoSQL之Redis配置与优化

缓存概念 缓存是为了调节速度不一致的两个或多个不同的物质的速度,在中间对速度较慢的一方起到加速作用,比如CPU的一级、二级缓存是保存了CPU最近经常访问的数据,内存是保存CPU经常访问硬盘的数据,而且硬盘也有大小不一的缓存&am…

爆肝整理,最全单元测试-测试用例总结(全覆盖)及拿即用...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 Python自动化测试&…

Maven私服仓库配置-Nexus详解

目录 一、什么是Maven私服?二、Maven 私服优势三、Maven 私服搭建四、Sonatype Nexus介绍五、Nexus仓库属性和分类六、Nexus仓库配置以及创建仓库七、Nexus配置用户角色八、Maven SNAPSHOT(快照)九、项目当中配置Nexus上传依赖十、项目当中配置Nexus下载依赖十一、测…

人工智能基础部分20-生成对抗网络(GAN)的实现应用

大家好,我是微学AI,今天给大家介绍一下人工智能基础部分20-生成对抗网络(GAN)的实现应用。生成对抗网络是一种由深度学习模型构成的神经网络系统,由一个生成器和一个判别器相互博弈来提升模型的能力。本文将从以下几个方面进行阐述&#xff1…

flutter_学习记录_03_通过事件打开侧边栏

实现类似这样的侧边栏的效果&#xff1a; 可以用Drawer来实现。 1. 在Scaffold组件下设置endDrawer属性 代码如下&#xff1a; import package:flutter/material.dart;class ProductListPage extends StatefulWidget {ProductListPage( {super.key}) ;overrideState<Pro…