各位小伙伴在面试中被面试官问道this指向问题一定不少吧,同时还被问道apply,call和bind的用法区别,现在,就来简单的聊一聊this到底指向何方。

1.基本概念

MDN的官方解释:与其他语言相比,函数的 this 关键字在 JavaScript 中的表现略有不同,此外,在严格模式和非严格模式之间也会有一些差别。在绝大多数情况下,函数的调用方式决定了this的值。this不能在执行期间被赋值,并且在每次函数被调用时this的值也可能会不同。

简而言之:

  1.this指向的对象称为函数的上下文对象context;  

  2.this的指向取决于函数被调用方式

不管函数怎么调用的天花乱坠,我们只要记住这几点即可清晰的找出this的指向。

2.小试牛刀

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

面试官问你this指向哪里,当然大声回答不知道,原因:谁调用指向谁,函数都没被调用,确实不知道指向。

小结:直接通过函数名来调用函数,this指向全局变量window;通过对象.函数名调用函数,this指向该对象。

3.DOM对象调用函数时this的指向问题

1.通过选择器选择元素加事件属性来绑定事件,this指向该DOM对象,例子如下:

document.getElementById('btn').onclick=function(){
console.log('click'); //click
console.log(this); //<button id="btn">button</button>
}

2.直接在DOM标签中写事件,this指向window,我们可以通过吧this作为参数传入方法中再使用,例子如下

html:
<button onclick="modify()">add</button>
<span id="count">0</span>
<button onclick="modify()">reduce</button> script:
// 操作方法
function modify(){
console.log(this); //window
}

因为这个时候是直接调用方法的,所以this指向全局window对象,那么问题来了,我们想判断我们点击的是哪一个按钮,应该怎么做呢,我们可以把this的值作为参数传入方法中再使用,例子如下。

html:
<button onclick="modify(this)">add</button>
<span id="count">0</span>
<button onclick="modify(this)">reduce</button> script:
// 操作方法
function modify(_this){
console.log(_this);
// <button onclick="modify(this)">add</button>
// <button onclick="modify(this)">reduce</button>
}

4.对象中this的指向问题

先看一个简单的例子:

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

我们定义了一个全局变量a和一个打印a的全局变量方法,之后又定义了一个obj对象,其中包含a属性和foo,bar两个方法。当我们调用obj.foo()打印了2,调用obj.bar()打印了1.

分析:

不管printA在哪里定义的,我们this的指向只取决于被谁调用的。在obj.foo(),foo的属性值为printA,被obj直接调用,所以this指向obj,this.a就是obj.a=2了;

当我们调用obj.bar()时,bar的属性值为function(){printA()},没有明确哪个对象来调用printA方法,this默认指向全局对象window,所以this.a=window.a=1;

第三种情况我们把obj.foo值赋予了foo变量,在调用的时候就相当于是window.foo()了,打印1。

小结:this的指向不是函数声明是绑定的,而是在函数运行过程中动态绑定的。

5.改变this的指向方法:applay call bind

话不多话:写了一个例子,大家先看,万一比喻不恰当,大家能理解其中意思即可

var liLei={
name:'liLei',
money:10,
buyPen:function(){
this.money=this.money-1;
console.log(this.name+" have money:"+this.money)
}
} var hanMeiMei={
name:'hanMeiMei',
money:20,
buyPan:function(){
this.money=this.money-2;
console.log(this.name+" have money:"+this.money)
}
} liLei.buyPen(); // liLei have money:9
hanMeiMei.buyPan(); //hanMeiMei have money:18 

例子很好理解,输出的结果相信大家也能看得明白,哪天,韩梅梅想买一个盆,她买不了,因为她还没有这个方法,她一想:我没有这个方法,但是李雷有啊,我打电话给李雷把钱他让他帮我买啊;后来李雷想买一个盘,实现方法也是如此。那么,在代码中如何实现呢?

JavaScript有好几个方法可以实现:call,apply,bind。

call方法:
语法:call(thisObj,Object)
定义:调用一个对象的一个方法,以另一个对象替换当前对象。
说明:
call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。

liLei.buyPen.call(hanMeiMei); //hanMeiMei have money:19
hanMeiMei.buyPan.call(liLei); //liLei have money:8

apply方法:
语法:apply(thisObj,[argArray])
定义:应用某一对象的一个方法,用另一个对象替换当前对象。
说明:
如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。

liLei.buyPen.apply(hanMeiMei); //hanMeiMei have money:19
hanMeiMei.buyPan.apply(liLei); //liLei have money:8

bind方法:

liLei.buyPen.bind(hanMeiMei)(); //hanMeiMei have money:19
hanMeiMei.buyPan.apply(liLei)(); //liLei have money:8

小结:三种方法的相同指出是:可以改变this的指向,不同之处是:apply接受的参数为一个数组,call接收的参数为一个个独立的值;apply,call会直接调用方法,bind改变this的指向返回一个方法不调用。

注:有些低版本的浏览器不支持函数使用bind方法,我们在做浏览器兼容时可以加以判断,具体实现方法暂不赘述。

  以上就是个人对于this的指向问题的理解,我们只需记住一点:this指向-谁调用,指向谁。不得不说JavaScript真是个奇妙的世界,文中有纰漏不足的地方,欢迎指正。


参考资料:

MDN-this

杰瑞教育

外婆的彭湖湾

转载请注明出处,谢谢!

面试题-浅谈JavaScript中的This指向问题的更多相关文章

  1. 通过一道笔试题浅谈javascript中的promise对象

    因为前几天做了一个promise对象捕获错误的面试题目,所以这几天又重温了一下promise对象.现在借这道题来分享下一些很基础的知识点. 下面是一个面试题目,三个promise对象捕获错误的例子,返 ...

  2. 浅谈JavaScript中的闭包

    浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...

  3. 浅谈JavaScript中的null和undefined

    浅谈JavaScript中的null和undefined null null是JavaScript中的关键字,表示一个特殊值,常用来描述"空值". 对null进行typeof类型运 ...

  4. 浅谈JavaScript中的正则表达式(适用初学者观看)

    浅谈JavaScript中的正则表达式 1.什么是正则表达式(RegExp)? 官方定义: 正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去 ...

  5. 浅谈JavaScript中的内存管理

    一门语言的内存存储方式是我们学习他必须要了解的,接下来让我浅谈一下自己对他的认识. 首先说,JavaScript中的变量包含两种两种类型: 1)值类型或基本类型:undefined.null.numb ...

  6. 浅谈JavaScript中闭包

    引言 闭包可以说是JavaScript中最有特色的一个地方,很好的理解闭包是更深层次的学习JavaScript的基础.这篇文章我们就来简单的谈下JavaScript下的闭包. 闭包是什么? 闭包是什么 ...

  7. 浅谈JavaScript中的继承

    引言 在JavaScript中,实现继承的主要方式是通过原型链技术.这一篇文章我们就通过介绍JavaScript中实现继承的几种方式来慢慢领会JavaScript中继承实现的点点滴滴. 原型链介绍 原 ...

  8. 浅谈JavaScript中继承的实现

    谈到js中的面向对象编程,都有一个共同点,选择原型属性还是构造函数,两者各有利弊,而就片面的从js的对象创建以及继承的实现两个方面来说,官方所推荐的是两个相结合,各尽其责,各取其长,在前面的例子中,我 ...

  9. 【总结】浅谈JavaScript中的接口

    一.什么是接口 接口是面向对象JavaScript程序员的工具箱中最有用的工具之一.在设计模式中提出的可重用的面向对象设计的原则之一就是“针对接口编程而不是实现编程”,即我们所说的面向接口编程,这个概 ...

随机推荐

  1. python数据存储技巧

    1.文本存储 比如我们现在有10篇文章,每篇文章由三部分组成,题目,作者,内容(title,author,content),然后要求这三个部分明确展示出来,并且每篇文章之间用=====分割. 大致思路 ...

  2. 微信小程序入门一

    基本的准备工作 -知识储备 --基础:HTML+JS+CSS --进阶:React.Vue -工具安装 --工具由微信官方提供 ---下载地址:https://github.com/zce/weapp ...

  3. 让 Homebrew 走代理更新 + brew 管理 node 版本

    0.前言 环境:MacOS 背景:整理下今天所做的配置. 1. 让 Homebrew 走代理更新 brew update 就卡住了,即使开了 shadowsocks 也不行.因为 shadowsock ...

  4. javascript中的"x != x"

    在javascript的运用中,经常遇到判断两个 对象/值 是否相等的情况.有些表明上看着一样,其实他们不一样.有些特殊情况,需要我们辨别. 引用类型 他们都是引用类型,存储的空间将从堆中分配.变量处 ...

  5. BlackArch安装(译文)

    翻译:荒原之梦 原文地址:BlackArch Install 以下是译文: 该教程将会向你展示如何使用ISO和blackarch-installer安装BlackArch Linux. 这个教程中使用 ...

  6. Fedora Linux中解决“xxx不在sudoers文件中”

    问题描述: 在Fedora中执行一些操作时需要使用root权限,当我使用命令: sudo 想在普通用户中临时获得root权限时,却被提示: "xxx 不在 sudoers 文件中.此事将被报 ...

  7. springboot集成schedule(深度理解)

    背景 在项目开发过程中,我们经常需要执行具有周期性的任务.通过定时任务可以很好的帮助我们实现. 我们拿常用的几种定时任务框架做一个比较: 从以上表格可以看出,Spring Schedule框架功能完善 ...

  8. TestNG 自动化测试入门教程--典型示例

    TestNG介绍 TestNG是Java中的一个测试框架, 类似于JUnit 和NUnit,   功能都差不多, 只是功能更加强大,使用也更方便 Java中已经有一个JUnit的测试框架了.  Tes ...

  9. 安装python软件找不到setuptools的解决方案

    在新装的centos系统中,用源码安装supervisor提示如下: [root@1e supervisor-3.0]# python setup.py install Traceback (most ...

  10. 高性能Server---Reactor模型【转载】

    原文链接:http://www.ivaneye.com/2016/07/23/iomodel.html 无处不在的C/S架构 在这个充斥着云的时代,我们使用的软件可以说99%都是C/S架构的! 你发邮 ...