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 ...
随机推荐
- poj 3436 ACM Computer Factory 最大流+记录路径
题目 题意: 每一个机器有一个物品最大工作数量,还有一个对什么物品进行加工,加工后的物品是什么样.给你无限多个初始都是000....的机器,你需要找出来经过这些机器操作后最多有多少成功的机器(111. ...
- Ubuntu中Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend)问题的解决
参考博客:https://blog.csdn.net/shimadear/article/details/90598646 问题描述: 解决方法: 第一种情况: 进程中存在与apt相关的正在运行的进程 ...
- Linux-平均负载指数
目录 系统平均负载 什么是平均负载 平均负载多少合理 如何观察平均负载 平均负载和CPU的使用率的区别 平均负载分析 执行CPU密集型任务 执行I/O密集型任务 大量进程调度 关于平均负载的总结 系统 ...
- 考研最路径dijkstra和floyd
先来讲个段子:为什么 Dijkstra 不能提出 floyd 算法?因为他的名字是 ijk 而不是 kij. get不到点没有关系.我们今天的任务是看懂这个笑话. dijkstra 的效率是n^2.处 ...
- python阿里云api查询域名是否可以注册(CheckDomain)
import requests from fun import * from urllib import parse url ='http://domain.aliyuncs.com/?' acces ...
- 设计模式六大原则 All In one
设计模式六大原则 All In one 开闭原则: 对扩展开放,对修改关闭; 设计模式的六大原则: 0.总原则-开闭原则 对扩展开放, 对修改封闭; 在程序需要进行拓展的时候, 不能去修改原有的代码, ...
- Vue 3.x & v-model
Vue 3.x & v-model https://v3.vuejs.org/guide/migration/v-model.html#overview BREAKING: When used ...
- set CSS style in js solutions All In One
set CSS style in js solutions All In One css in js set each style property separately See the Pen se ...
- OpenCV & Web Assembly & Web Worker
OpenCV & Web Assembly & Web Worker opencv-in-the-web https://aralroca.com/blog/opencv-in-the ...
- Flutter 区分开发环境和生产环境
Uri _baseUrl; final isProd = const bool.fromEnvironment('dart.vm.product'); if (isProd) { _baseUrl = ...