当前位置: 首页 > news >正文

【JS】this关键字的相关问题

我是目录

  • 引言
  • this
    • 为什么要用this
    • 对this的误解
      • this并不指向自身
      • this 并不指向普通函数的作用域
    • this的绑定方式
      • 默认绑定(Default Binding)
      • 隐式绑定(Implicit Binding)
        • 隐式绑定丢失
        • 面试实战
      • 显式绑定(Explicit Binding)
        • 硬绑定
          • 软绑定
        • call apply bind的区别
        • call函数实现
        • apply函数实现
      • new绑定原理
        • 实现new关键字的方法
      • 四种绑定方式的优先级
        • 显式绑定的优先级高于隐式绑定。
        • new绑定的优先级高于隐式绑定。
    • 箭头函数中的this
      • 箭头函数的绑定无法被修改
      • 不适合箭头函数的场景

引言

JS中this关键字,面试时候一般不太会直接提问,一般会问:new的实现;call/apply的区别等等这种比较初级的知识。这篇主要总结一下this的相关知识,主要包括this的指向、绑定方式、call/apply、new的实现等等。

this

this提供了一种优雅的方式来隐式传递一个对象引用,API可以设计的更加简洁且易于复用。如果不用this的话,就必须给一些函数显式传入上下文对象。this使得函数可以自动引用合适的上下文对象。
this 的指向,是在调用函数时根据执行上下文所动态确定的,它指向调用它的对象。
this 是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。
在之前的【JS】作用域、执行上下文与闭包中提到,当一个函数被调用时, 会创建一个执行上下文。这个执行上下文中会包含函数传入的参数、变量对象、作用域链等信息。this 的指向就是在执行上文中被确定的。

为什么要用this

this可以隐式传递一个对象引用,使代码更加简洁。

function identify(context) {return context.name.toUpperCase();
}
function speak(context) {var greeting = "Hello, I'm " + identify( context );console.log( greeting );
} 
identify( you ); // READER
speak( me ); //hello, 我是 KYLE

上面的一段函数就是显式传入了上下文对象,可以用this进行改写:

function identify() {return this.name.toUpperCase();
}
function speak() {var greeting = "Hello, I'm " + identify.call( this );console.log( greeting );
}
var me = {name: "Kyle"
};
var you = {name: "Reader"
};
identify.call( me ); // KYLE
identify.call( you ); // READER
speak.call( me ); // Hello, 我是 KYLE
speak.call( you ); // Hello, 我是 READER

为什么需要从函数内部引用函数自身?
常见的原因是递归( 从函数内部调用这个函数) 或者可以写一个在第一次被调用后自己解除绑定的事件处理器。

function foo() {foo.count = 4; // foo 指向它自身
} 
setTimeout(function() {// 匿名( 没有名字的) 函数无法指向自身
}, 10);

对this的误解

  1. this并不指向自身
  2. this 并不指向普通函数的作用域

this并不指向自身

在函数内部的this,很容易让人误认为它指向函数自身。

function foo(num) {console.log( "foo: " + num );// 记录 foo 被调用的次数this.count++;
} 
foo.count = 0;
var i;
for (i = 0; i < 10; i++) {if (i > 5) {foo( i );}
} 
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo 被调用了多少次?
console.log( foo.count ); // 0

foo函数确实被调用了4次,但是foo.count其实还是0。在foo函数中看似累加的count其实每次都是创建了一个全局变量,它的值是NaN。
想解决的话只要强制改变this指向就可以

function foo(num) {console.log( "foo: " + num );// 记录 foo 被调用的次数// 注意, 在当前的调用方式下, this 确实指向foothis.count++;
} 
foo.count = 0;
var i;
for (i=0; i < 10; i++) {if (i > 5) {// 使用 call(..) 可以确保 this 指向函数对象 foo 本身foo.call( foo, i );}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo 被调用了多少次?
console.log( foo.count ); // 4

this 并不指向普通函数的作用域

this 在任何情况下都不指向函数的词法作用域。 在 JavaScript 内部, 作用域确实和对象类似,可见的标识符都是它的属性。但是作用域“ 对象” 无法通过 JavaScript代码访问, 它存在于 JavaScript 引擎内部。

function foo() {var a = 2;this.bar();
}
function bar() {console.log( this.a );
} 
foo(); // ReferenceError: a is not defined

这段代码试图通过 this.bar() 来引用 bar() 函数。这是绝对不可能成功的。调用 bar() 最自然的方法是省略前面的 this,直接使用词法引用标识符。
此外,编写这段代码的开发者还试图使用 this 联通 foo()bar() 的词法作用域,从而让bar() 可以访问 foo() 作用域里的变量 a。这是不可能实现的,不能使用 this 来引用一个词法作用域内部的东西。
每当想要把 this 和词法作用域的查找混合使用时,一定要提醒自己,这是无法实现的。

this的绑定方式

在了解this的绑定方式之前,需要知道什么是调用位置(call site)。

调用位置是指函数在代码中被调用的位置( 而不是声明的位置),需要分析调用栈。我们关心的调用位置就在当前正在执行的函数的前一个调用中。

function baz() {// 当前调用栈是: baz// 因此, 当前调用位置是全局作用域console.log( "baz" );bar(); // <-- bar 的调用位置
}

http://www.mrgr.cn/news/68560.html

相关文章:

  • 【深圳大学/大学物理实验2】霍尔效应及其应用实验预习参考
  • 【LeetCode】【算法】300. 最长递增子序列
  • SQL server增删改查语句和实例
  • VisionPro —— CogIPOneImgeTool工具详解
  • qt QFile详解
  • 每日OJ题_牛客_DP59数位染色_01背包_C++_Java
  • C语言实验 循环结构
  • YOLOv7-0.1部分代码阅读笔记-experimental.py
  • 使用STM32F407xx的GPIO引脚实现跑马灯效果的详细步骤
  • Linux进程通信之管道
  • oracle数据坏块处理(三)-数据抽取插入到新表中
  • RHCE—web服务器
  • VR的左右眼渲染方法
  • 08 反射与注解
  • 【Linux】解锁操作系统潜能,高效线程管理的实战技巧
  • vue3使用easy-player播放hls监控流
  • AIGC--如何在内容创作中合理使用AI生成工具?
  • 1 天通关 AWS AI 认证,AWS AI 从业者证书最强考试指南
  • LangChain 快速入门
  • 信息安全工程师(83)Windows操作系统安全分析与防护
  • 淘宝商品详情API大揭秘:用Python开启探险之旅
  • 自动驾驶中,2d图像目标检测(分割),融合激光雷达点云信息
  • ChatGLM2-6B微调记录【1】
  • 【计网不挂科】计算机网络期末考试——【选择题&填空题&判断题&简述题】题库(2)
  • ​解决‌win11无法打开msi安装程序包的方法‌
  • AI预测体彩排3采取888=3策略+和值012路+胆码+通杀1码测试11月8日升级新模型预测第128弹