js--this指向的相关问题
前言
关于this的指向问题是前端面试中常考的知识点,也是我们开发学习中较难理解的问题。作为JavaScript的基础,需要我们彻底理解这一关键词。this作为JavaScript中非常复复杂的机制,值得我们付出更大的代价来学习理解。这里分享一下我的学习笔记。
正文
1.this是什么?this指向什么?
学习this之前首先要知道this永远指向一个对象,this就是函数运行时候所在的环境,我们在学习执行上下文的时候提到,每一个执行上下文都包含三个重要对象,分别是变量对象、作用域链和 this,JavaScript支持运行环境动态切换,也就是说,this的指向是动态的,并不是固定的指向一个对象,this的指向完全取绝于函数调用的位置。接下来我们看下下面的代码:
var a=1
function foo(){
var a=3
console.log(a)
}
foo()//3
上面的代码执行用到函数的作用域问题,foo()函数执行的时候,函数内部定义一个变量a等于3,然后输出打印a,此时foo上下文中存在a变量,因此输出3,若函数foo()内部没有定义a这个变量,在执行打印这句代码的时候,函数内部找不到该变量,此时会沿着作用域链向上次查找,即全局作用域,此时打印结果便为1。
var a=1
function foo(){
var a=3
console.log(this.a)
}
foo()//1
上面的代码执行结果会打印出1,对比第一段代码你会发现就这里多了this这一个关键词,为什么加了this之后输出结果会发生改变呢?莫非此时this指向window全局对象?
var a=1
function foo(){
var a=3
console.log(this.a)
}
var obj={a:100,foo:foo}
obj.foo()//100
再来看下上面的代码,打印结果变为100,对比前面两段代码,foo函数增加了obj对象的一层引用,输出的this.a结果再次发生改变?难道此时this指向obj对象?
this的指向为什么会发生改变,this的指向到底什么时候发生的?是因为函数在JavaScript中既可以当作值传递和返回,也可以当作对象和构造函数。所有函数在运行的时候才能确定其当前的运行环境,所以this就产生了,this会根据函数的运行环境的改变而改变,同时,函数中的this也只能在函数运行时最终确定其运行环境。
2.this不指向它自身。
function foo(num) {
console.log( "foo: " + num ); // 记录 foo 被调用的次数
this.count++;
}
foo.count = 0;
for (var i=0; i<5; i++) {
foo( i );
}
console.log("foo.count:"+foo.count)
//foo: 0
//foo: 1
//foo: 2
//foo: 3
//foo: 4
//foo.count:0
上面的代码打印输出foo:01234,说明foo函数被调用了五次,然后打印foo.count输出还是0,说明this.count中的this并不是指向的函数foo本身,foo.count只是函数foo的一个属性,this无法指向他本身。我们可以通过arguments.callee来引用当前正在执行的函数对象,即对象本身。
3.this不指向它的作用域。
另一种常见的误解就是this指向函数的作用域。我们需要牢记,this在任何情况下都不指向函数的词法作用域,this的指向完全取决于函数调用的位置。因此不能使用this来引用一个函数词法作用域内部的东西。
4.this的绑定规则。
通过函数调用的位置来确定函数绑定的this对象,需要遵守以下四条规则:
(1)默认绑定
function foo() {
console.log( this.a );
}
var a = 2;
foo(); // 2
上面的代码中,foo()函数直接调用,不带任何修饰的函数引用进行调用,因此采用默认绑定,此时this指向window对象,无法应用其他规则。在非 strict mode 下时,默认绑定才能绑定到全局对象,严格模式下 this 绑定在undefined。
(2)隐式绑定--需要考虑的规则是调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含。
function foo() {
console.log( this.a );
}
var obj = { a: 2, foo: foo };
obj.foo(); // 2
上面的代码中,foo函数被调用时 obj 对象 “ 拥有 ” 或者 “ 包含 ” 它。当函数引 用有上下文对象时,隐式绑定规则会把函数调用中的 this绑定到这个上下文对象,因为调 用 foo() 时 this 被绑定到 obj,因此 this.a 和 obj.a 是一样的。
function foo() {
console.log(this.a);
}
var obj2 = {
a: 2,
fn: foo
};
var obj1 = {
a: 1,
o1: obj2
};
obj1.o1.fn();//2
上面的代码需要值得注意的是:对象属性引用链中只有最顶层或者说最后一层会影响调用位置。
function foo() {
console.log( this.a );
}
var obj = { a: "local", foo: foo };
var bar = obj.foo; // 函数别名!
var a = " global"; // a 是全局对象的属性
bar(); // "global"
上面的代码,虽然 bar 是 obj.foo 的一个引用,但是实际上,它引用的是 foo 函数本身,因此此时的 bar() 其实是一个不带任何修饰的函数调用,因此应用了默认绑定。
function foo(){
console.log(this.a)
}
var a="global"
var obj={a:"local",foo:foo}
var bar=obj.foo
function doFnc(fn){
fn()
}
doFnc(bar)//global
上面的代码需要注意的是:被隐式绑定的函数会丢失绑定对象。
(3)显示绑定或者硬绑定--call,apply,bind直接指定this的绑定对象
call() apply() bind()直接指定 this 的绑定对象,返回一个硬编码的新函数,它会把参数设置为 this 的上下文并调用原始函数。但是如果你把 null 或者 undefined 作为 this 的绑定对象传入 call、apply 或者 bind,这些值 在调用时会被忽略,实际应用的是默认绑定规则。foo.call( obj );以在调用 foo 时强制把它的 this 绑定到 obj 上。
(4)new绑定
JavaScript 中 new 的机制实 际上和面向类的语言完全不同。
在 JavaScript 中,构造函数只是一些 使用 new 操作符时被调用的函数。它们并不会属于某个类,也不会实例化一个类。实际上, 它们甚至都不能说是一种特殊的函数类型,它们只是被 new 操作符调用的普通函数而已。包括内置对象函数(比如 Number(..))在内的所有函数都可 以用 new 来调用,这种函数调用被称为构造函数调用。
使用 new 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
1. 创建(或者说构造)一个全新的对象。
2. 这个新对象会被执行 [[ 原型 ]] 连接。
3. 这个新对象会绑定到函数调用的 this。
4. 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象
new 来调用 foo(..) 时,我们会构造一个新对象并把它绑定到 foo(..) 调用中的 this 上。
5.绑定的优先和一些特殊情况。
(1)间接绑定
function foo() { console.log( this.a ); }
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // 2
赋值表达式 p.foo = o.foo 的返回值是目标函数的引用
对比隐式绑定
function foo() { console.log( this.a ); }
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 ,fo:o.foo};
p.fo() //4 对比间接引用
(2)事件绑定中的this
1.行内绑定 <input type='button' onclick="this">
<input onclick="clickFuc"> function(){ this ...}
//this指向window对象
2.事件监听与动态绑定
<input type="button" value="按钮" id="btn">
<script> var btn = document.getElementById('btn');
btn.onclick = function(){
this ; // this指向本节点对象
}</script>
//动态绑定的事件本身就是对应节点的一个属性,重新赋值为一个匿名函数,this自然就指向了本节点对象
(3)箭头函数
ES6 中的箭头函数并不会使用四条标准的绑定规则,而是根据当前的词法作用域来决定this,具体来说,箭头函数会继承外层函数调用的 this 绑定(无论 this 绑定到什么)。这其实和 ES6 之前代码中的 self = this 机制一样。
总结
js--this指向的相关问题的更多相关文章
- js 时间函数 及相关运算大全
js 时间函数 及相关运算大全 var myDate = new Date(); myDate.getYear(); //获取当前年份(2位) myDate.getFullYear(); ...
- js中scroll滚动相关
js中scroll滚动相关 scroll,滚动,一般讨论的是网页整体与浏览器之间的关系. 一.元素相关 属性/方法 解释 element.scrollHeight 返回元素的整体高度. element ...
- JS中this指向问题相关知识点及解析
概括:this指向在函数定义的时候是无法确定的,只有在函数调用执行的时候才能确定this最终指向了谁,this最终指向的是调用它的对象(常见的说法,后面有小小的纠正): 例1: 图中的函数fn1其实是 ...
- [学习笔记]JS 数组Array push相关问题
前言: 今天用写了一个二维数组,都赋值为零,然后更新其中一个值,结果和预期是不一样,会整列的相同位置都是同一个值. 1.用Chrome的控制台样例如下: arrs[2][2] =1的赋值,竟然是三个数 ...
- 【本周面试题】第2周 - js单线程和异步相关问题
硬性知识点考察: 为什么js是单线程的? 因为js设计最初是为了操作dom而生,如果是多线程的,当多个线程同时修改一个dom时就会产生冲突,所以设计成单线程,一次只能做一件事. 既然是单线程为什么要有 ...
- 白话js this指向问题
前言 通过本文,你大概能了解this基础指向的问题,抛开例子去说this太虚幻,这里还是结合几篇博文做个整理,算是个人的记录了. 先说概念,this指向与申明无关,永远指向距离自己最近的最终调用者 ...
- vue.js的package.json相关问题解惑
使用vue-cli创建vue.webpack项目,在项目中用到了iSlider移动端滑动插件,只在本地命令工具中npm install islider.js:提交之后,partner下载代码后一直运行 ...
- 面试题-JS中的作用域相关问题
对象类型: 原始数据类型存储的是值,而对象类型存储的是地址(指针).下面的这个例子就比较有意思了. 先看题: function test(person) { person.age = 26 perso ...
- 彻底搞懂js this指向问题
在这里必须要提一句的是,this指向是学习js必须要掌握的(必须),再开始之前先看底部的总结,然后回上面看例子便一目了然. 例子1: function a(){ var user = "Ta ...
- JS this指向
正常模式 在正常模式下独立函数的的 this 指向 undefined 或 window. <script type="text/javascript"> functi ...
随机推荐
- Long Long Message POJ - 2774 后缀数组
The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to him ...
- c#记两个变量进行值交换
今天腊月二十九啦,无心上班,专注划水.然后就在那里翻帖子消磨时光. 看到了这样一个问题,有人提问为什么 a=b+(b=a)*0 ??? 第一眼看上去,我也有点蒙,仔细推敲了一下,嗯~的确是交换了 ...
- k8s-3-容器云监控系统
apollo小结 课程目录 一.容器云监控prometheus概述 https://prometheus.io/docs/introduction/overview/ #官方文档 https://gi ...
- docker理论题-02
1.什么是namespace? 答:名称空间,作用隔离容器 2.namespace隔离有那些? 答:ipc:共享内存.消息队列 mnt:挂载点 net:网络栈 uts:域,主机名 user:用户,组 ...
- element ui 渲染超过上百条数据时页面卡顿,更流畅的加载大量数据
问题:element ui table渲染上百条数据,页面渲染开始出现延时 解决方案:使用pl-table 注意:设置use-virtual并给定table高度
- json-server All In One
json-server All In One https://github.com/typicode/json-server#getting-started $ npm i -g json-serve ...
- console.log & front-end jobs
console.log & front-end jobs bind & function let log = console.log; let obj = {}; log(obj); ...
- google advanced search operators
google advanced search operators https://www.google.com/advanced_search js es6 site:xgqfrms.xyz http ...
- svg 矩阵转换
svg 矩阵转换 https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/matrix https://develope ...
- apollo-server 返回模拟数据
模式模拟GraphQL数据 const { ApolloServer, gql } = require('apollo-server'); const typeDefs = gql` type Que ...