首先,要明白this 既不指向函数自身,也不指函数的词法作用域。this一般存在于函数中,表示当前函数的执行上下文,如果函数没有执行,那么this没有内容,只有函数在执行后this才有绑定。

然后,我们来看看this四种绑定规则,也可以说在四种不同函数执行方式时this的指向。

1.默认绑定(执行)

默认执行:即没有其他绑定规则存在时的默认规则。这也是函数调用中最常用的规则。this指向window,严格模式下指向undefined

function fn(){
console.log(this)
}
fn()

fn()打印到控制台结果为window

开启严格模式后

 function fn(){
"use strict"
console.log(this)
}
fn()

fn()打印到控制台结果为undefined

2.隐式绑定(执行)

通过对象执行(通过上下文对象执行) obj.fn():当前的执行对象

function fn(){
console.log(this.a)
}
var a = 10;
var obj = {
a:20,
b:fn
}
var obj2 = {
a:30,
b:obj.b
}
obj2.b(); //??

obj2.b(); 打印到控制台结果为30

因为obj2.b();在上述代码中等价于obj2.fn(),所以此时this指向obj2,所以打印结果为30;

多层调用

  function fn(){
console.log(this.a)
}
var a = 10;
var obj = {
a:20,
b:fn
}
var obj2 = {
a:30,
b:obj.b
}
var obj3 = {
a:40,
b:obj2
}
obj3.b.b() //?

obj3.b.b() 打印结果为30

上述代码调用结果为obj3.b->obj2,obj2.b->obj.b->fn,因为this只获取最近一层调用的上下文对象,即obj2

所以结果为30

隐式丢失(函数别名)

注意:这里存在一个陷阱,大家在分析调用过程时,要特别小心

function fn() {
console.log( this.a );
} var a = 2; var obj = {
a: 3,
b: fn
}; var bar = obj.b;
bar(); //?

bar() 打印结果为2

为什么会这样,obj.b 赋值给bar,那调用bar()为什么没有触发隐式绑定,使用的是默认绑定呢。

这里有个概念要理解清楚,obj.b 是引用属性,赋值给bar的实际上就是fn函数(即:bar指向fn本身)。

那么,实际的调用关系是:通过bar找到fn函数,进行调用。整个调用过程并没有obj的参数,所以是默认绑定,全局属性a。

隐士丢失(回调函数)

function fn(){
console.log(this.a)
}
var a=20;
var obj = {
a:20,
b:fn
}
setTimeout(obj.b, 2000);
function setTimeout(cb,t){
// t
cb() //?
}

cb()打印结果为20

同样的道理,虽然参传是obj.fn,因为是引用关系,所以传参实际上传的就是fn对象本身的引用。对于setTimeout的调用,还是 setTimeout -> 获取参数中fn的引用参数 -> 执行 fn 函数,中间没有obj的参与。这里依旧进行的是默认绑定。

3.显示绑定(执行)

 function fn(){
console.log(this.a)
} var obj1= {
a:10
}
var obj2 ={
a:20
}
var obj3 ={
a:30
}
fn.bind(obj1)();
fn.call(obj2);
fn.apply(obj3);

fn.bind(obj1)();打印结果为10

fn.call(obj2); 打印结果为20

fn.apply(obj3); 打印结果为30

这里要注意fn.bind(obj1)后面还要加一个括号才执行!

4.new 绑定(构造函数执行(通过new执行))

js中的new操作符,和其他语言中(如JAVA)的new机制是不一样的。js中,它就是一个普通函数调用,只是被new修饰了而已。

使用new来调用函数,会自动执行如下操作:

如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。

从这点可以看出,this指向的就是对象本身。

function foo(a) {
this.a = a;
} var a = 2; var bar1 = new foo(3);
console.log(bar1.a); // ? var bar2 = new foo(4);
console.log(bar2.a); // ?

因为每次调用生成的是全新的对象,该对象又会自动绑定到this上,所以打印结果分别为3,4

绑定规则优先级

优先级是这样的,以按照下面的顺序来进行判断:

数是否在new中调用(new绑定)?如果是的话this绑定的是新创建的对象。

数是否通过call、apply(显式绑定)或者硬绑定调用?如果是的话,this绑定的是 指定的对象。

数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上下文对象。

果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到 全局对象。

详解javascript中的this的指向问题的更多相关文章

  1. 【转】详解JavaScript中的this

    ref:http://blog.jobbole.com/39305/ 来源:foocoder 详解JavaScript中的this JavaScript中的this总是让人迷惑,应该是js众所周知的坑 ...

  2. 详解javascript中的this对象

    详解javascript中的this对象 前言 Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象.Javascript可以通过一定的 ...

  3. (转载)详解Javascript中prototype属性(推荐)

    在典型的面向对象的语言中,如java,都存在类(class)的概念,类就是对象的模板,对象就是类的实例.但是在Javascript语言体系中,是不存在类(Class)的概念的,javascript中不 ...

  4. 详解 javascript中offsetleft属性的用法(转)

    详解 javascript中offsetleft属性的用法 转载  2015-11-11   投稿:mrr    我要评论 本章节通过代码实例介绍一下offsetleft属性的用法,需要的朋友可以做一 ...

  5. 详解JavaScript中的原型

    前言 原型.原型链应该是被大多数前端er说烂的词,但是应该还有很多人不能完整的解释这两个内容,当然也包括我自己. 最早一篇原型链文章写于2019年07月,那个时候也是费了老大劲才理解到了七八成,到现在 ...

  6. 详解JavaScript中的Event Loop(事件循环)机制

    前言 我们都知道,javascript从诞生之日起就是一门单线程的非阻塞的脚本语言.这是由其最初的用途来决定的:与浏览器交互. 单线程意味着,javascript代码在执行的任何时候,都只有一个主线程 ...

  7. 【转】详解JavaScript中的异常处理方法

    有三种类型的编程错误:(1)语法错误和(2)运行时错误(3)逻辑错误:语法错误: 语法错误,也被称为解析错误,在编译时进行传统的编程语言,并出现在JavaScript解释时. 例如,下面一行将导致一个 ...

  8. 详解JavaScript中的arc的方法

    今天说说JavaScript在网页中画圆的函数arc! 一.arc所需要的参数设置 1 arc(x, y, radius, startAngle, endAngle, counterclockwise ...

  9. 详解JavaScript中的this

    JavaScript中的this总是让人迷惑,应该是js众所周知的坑之一. 个人也觉得js中的this不是一个好的设计,由于this晚绑定的特性,它可以是全局对象,当前对象,或者…有人甚至因为坑大而不 ...

随机推荐

  1. NetCore跨平台桌面框架Avalonia的OSX程序打包

    虽然工作开发语言已经转到了java,但平时仍会用netcore做一些小工具,提升工作效率,但是笔记本换成了Mac,小工具只能做成命令行形式,很是痛苦,迫切需要一个.net跨平台的桌面程序解决方案. 为 ...

  2. linux初学者-常用基本命令篇

    linux系统中有着许许多多的命令,并且软件也有可能自带命令,要想全部了解这些命令是很困难的,但是有一些基本命令是在平时的学习工作中应用的很广泛的.以下简要介绍几种linux系统中的常用命令. 1.m ...

  3. java读写文件小心缓存数组

    一般我们读写文件的时候都是这么写的,看着没问题哈.   public static void main(String[] args) throws Exception {   FileInputStr ...

  4. python查漏补缺 --- 基础概念及控制结构

    python  是一种面向对象的解释型计算机程序设计语言,在运行时由解释器处理,在执行程序之前不需要编译程序.Python就是一句话,写得快,跑得慢. 下面的内容是平时工作中容易忽略掉的小细节,希望借 ...

  5. BFS vs DFS

    1 Clone Graph   1  copy ervery nodes by bfs  2  add neighbors public UndirectedGraphNode cloneGraph( ...

  6. 使用RedisMQ 做一次分布式改造

    引言 熟悉TPL Dataflow博文的朋友可能记得这是个单体程序,使用TPL Dataflow 处理工作流任务, 在使用Docker部署的过程中, 有一个问题一直无法回避: 在单体程序部署的瞬间会有 ...

  7. 对比度拉伸(一些基本的灰度变换函数)基本原理及Python实现

    1. 基本原理 对比度拉伸是扩展图像灰度级动态范围的处理.通过在灰度级中确定两个点来控制变换函数的形状.下面是对比度拉伸函数中阈值处理的代码示例,阈值为平均值. 2. 测试结果 图源自skimage ...

  8. Danjgo学习笔记(一)

    ## 创建项目: 1. 通过命令行的方式:首先要进入到安装了django的虚拟环境中.然后执行命令: ``` django-admin startproject [项目的名称] ``` 这样就可以在当 ...

  9. React Native-安卓环境的搭建

    最近公司做一个项目,项目中使用React Native(简称RN)来写安卓APP,现在我分享下安卓环境搭建的过程. 我参照https://reactnative.cn/docs/getting-sta ...

  10. Opengl_入门学习分享和记录_00

    2019.7.4 本着对游戏创作的热情,本人初步了解了一部分的unity引擎的使用,也学习了一点C#可是越学习unity我就反而对引擎内部感兴趣(不知道有没有一样的朋友=,=). 接着了解到了open ...