this 指向详细解析(箭头函数)

时间:2022-09-20 21:11:50

前言

this 指向问题是入坑前端必须了解知识点,现在迎来了ES6时代,因为箭头函数的出现,所以感觉有必要对 this 问题梳理一下,遂有此文

在非箭头函数下, this 指向调用其所在函数的对象,而且是离谁近就是指向谁(此对于常规对象,原型链, getter & setter等都适用);构造函数下,this与被创建的新对象绑定;DOM事件,this指向触发事件的元素;内联事件分两种情况,bind绑定, call & apply 方法等, 容以下一步一步讨论。箭头函数也会穿插其中进行讨论。

全局环境下

在全局环境下,this 始终指向全局对象(window), 无论是否严格模式;

console.log(this.document === document); // true

// 在浏览器中,全局对象为 window 对象:
console.log(this === window); // true this.a = 37;
console.log(window.a); //

函数上下文调用

函数直接调用

普通函数内部的this分两种情况,严格模式和非严格模式。

非严格模式下,this 默认指向全局对象window

function f1(){
return this;
} f1() === window; // true

而严格模式下, this为undefined

function f2(){
"use strict"; // 这里是严格模式
return this;
} f2() === undefined; // true

对象中的this

对象内部方法的this指向调用这些方法的对象,

  1. 函数的定义位置不影响其this指向,this指向只和调用函数的对象有关。
  2. 多层嵌套的对象,内部方法的this指向离被调用函数最近的对象(window也是对象,其内部对象调用方法的this指向内部对象, 而非window)。
//
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); //
var a = o.f;
console.log(a()): //undefined var o = {prop: 37}; function independent() {
return this.prop;
} o.f = independent; console.log(o.f()); // logs 37 //
o.b = {
g: independent,
prop: 42
};
console.log(o.b.g()); // logs 42

原型链中this

原型链中的方法的this仍然指向调用它的对象,与以上讨论一致;看个例子,

var o = {
f : function(){
return this.a + this.b;
}
};
var p = Object.create(o);
p.a = 1;
p.b = 4; console.log(p.f()); //

可以看出, 在p中没有属性f,当执行p.f()时,会查找p的原型链,找到 f 函数并执行,但这与函数内部this指向对象 p 没有任何关系,只需记住谁调用指向谁。

以上对于函数作为getter & setter 调用时同样适用。

构造函数中this

构造函数中的this与被创建的新对象绑定。

注意:当构造器返回的默认值是一个this引用的对象时,可以手动设置返回其他的对象,如果返回值不是一个对象,返回this。

function C(){
this.a = 37;
} var o = new C();
console.log(o.a); // logs 37 function C2(){
this.a = 37;
return {a:38};
} var b = new C2();
console.log(b.a); // logs 38

以上两个例子内部的this都指向对象o, 看到这里的你不妨在控制台执行下以上代码,看看对象 o 和 b ,这些是属于构造函数的内容了,此处不多做介绍。(C2函数中的this.a = 37 对整个过程完全没有影响的, 可以被忽略的)。

call & apply

当函数通过Function对象的原型中继承的方法 call() 和 apply() 方法调用时, 其函数内部的this值可绑定到 call() & apply() 方法指定的第一个对象上, 如果第一个参数不是对象,JavaScript内部会尝试将其转换成对象然后指向它。

例子:

function add(c, d){
return this.a + this.b + c + d;
} var o = {a:1, b:3}; add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16 add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34 function tt() {
console.log(this);
}
// 返回对象见下图(图1)
tt.call(5); // Number {[[PrimitiveValue]]: 5}
tt.call('asd'); // String {0: "a", 1: "s", 2: "d", length: 3, [[PrimitiveValue]]: "asd"}

this 指向详细解析(箭头函数)

bind 方法

bind方法在ES5引入, 在Function的原型链上, Function.prototype.bind。通过bind方法绑定后, 函数将被永远绑定在其第一个参数对象上, 而无论其在什么情况下被调用。

function f(){
return this.a;
} var g = f.bind({a:"azerty"});
console.log(g()); // azerty var o = {a:37, f:f, g:g};
console.log(o.f(), o.g()); // 37, azerty

DOM 事件处理函数中的 this & 内联事件中的 this

DOM事件处理函数

  1. 当函数被当做监听事件处理函数时, 其 this 指向触发该事件的元素 (针对于addEventListener事件)
  // 被调用时,将关联的元素变成蓝色
function bluify(e){
//在控制台打印出所点击元素
console.log(this);
//阻止时间冒泡
e.stopPropagation();
//阻止元素的默认事件
e.preventDefault();
this.style.backgroundColor = '#A5D9F3';
} // 获取文档中的所有元素的列表
var elements = document.getElementsByTagName('*'); // 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色
for(var i=0 ; i<elements.length ; i++){
elements[i].addEventListener('click', bluify, false);
}

以上代码建议在网页中执行以下,看下效果。

内联事件
内联事件中的this指向分两种情况:

  1. 当代码被内联处理函数调用时,它的this指向监听器所在的DOM元素
  2. 当代码被包括在函数内部执行时,其this指向等同于 ****函数直接调用****的情况,即在非严格模式指向全局对象window, 在严格模式指向undefined

this 指向详细解析(箭头函数)

页面的代码块

this 指向详细解析(箭头函数)

在浏览器内显示三个按钮

this 指向详细解析(箭头函数)

依次点击上边的三个按钮后在控制台的输出结果,

建议自己操作一遍以便于更好的理解。

setTimeout & setInterval

对于延时函数内部的回调函数的this指向全局对象window(当然我们可以通过bind方法改变其内部函数的this指向)
看下边代码及截图

//默认情况下代码
function Person() {
this.age = 0;
setTimeout(function() {
console.log(this);
}, 3000);
} var p = new Person();//3秒后返回 window 对象
==============================================
//通过bind绑定
function Person() {
this.age = 0;
setTimeout((function() {
console.log(this);
}).bind(this), 3000);
} var p = new Person();//3秒后返回构造函数新生成的对象 Person{...}

this 指向详细解析(箭头函数)

this 指向详细解析(箭头函数)

箭头函数中的 this

由于箭头函数不绑定this, 它会捕获其所在(即定义的位置)上下文的this值, 作为自己的this值,

  1. 所以 call() / apply() / bind() 方法对于箭头函数来说只是传入参数,对它的 this 毫无影响。
  2. 考虑到 this 是词法层面上的,严格模式中与 this 相关的规则都将被忽略。(可以忽略是否在严格模式下的影响)

因为箭头函数可以捕获其所在上下文的this值 所以

function Person() {
this.age = 0;
setInterval(() => {
// 回调里面的 `this` 变量就指向了期望的那个对象了
this.age++;
}, 3000);
} var p = new Person();

以上代码可以得到我们所以希望的值,下图可以看到,在setTimeout中的this指向了构造函数新生成的对象,而普通函数指向了全局window对象

this 指向详细解析(箭头函数)

var adder = {
base : 1, add : function(a) {
var f = v => v + this.base;
return f(a);
}, addThruCall: function inFun(a) {
var f = v => v + this.base;
var b = {
base : 2
}; return f.call(b, a);
}
}; console.log(adder.add(1)); // 输出 2
console.log(adder.addThruCall(1)); // 仍然输出 2(而不是3,其内部的this并没有因为call() 而改变,其this值仍然为函数inFun的this值,指向对象adder

bind() & apply() 读者可以自行测试

对于是否严格模式示例代码(可以复制进控制台进行验证)

var f = () => {'use strict'; return this};
var p = () => { return this};
console.log(1,f() === window);
console.log(2,f() === p());
//1 true
//2 true

this 指向详细解析(箭头函数)

以上的箭头函数都是在方法内部,总之都是以非方法的方式使用,如果将箭头函数当做一个方法使用会怎样呢?
上例子


this 指向详细解析(箭头函数)

可以看到,作为方法的箭头函数this指向全局window对象,而普通函数则指向调用它的对象

以上为个人学习整理内容, 文中例子参考MDN, 欢迎交流学习

参考文献

this - JavaScript | MDN
箭头函数 - JavaScript | MDN

本文地址:http://www.cnblogs.com/dongcanliang/p/7054176.html

this 指向详细解析(箭头函数)的更多相关文章

  1. &lbrack;转载&rsqb;this 指向详细解析(箭头函数&rpar;

    本文转自:http://www.cnblogs.com/dongcanliang/p/7054176.html 为了以后更方便的查看,便做了转载 前言 this 指向问题是入坑前端必须了解知识点,现在 ...

  2. ES5与ES6 this 指向详细解析(箭头函数)

    首先要明白箭头函数的作用: 箭头函数除了让函数的书写变得很简洁,可读性很好外:最大的优点是解决了this执行环境所造成的一些问题.比如:解决了匿名函数this指向的问题(匿名函数的执行环境具有全局性) ...

  3. this指向问题(箭头函数没有this)

    全局环境下,指向windows console.log(this.document === document); // true 函数上下文调用 function f1(){ return this; ...

  4. 普通函数跟箭头函数中this的指向问题

    箭头函数和普通函数的区别如下. 普通函数:根据调用我的人(谁调用我,我的this就指向谁) 箭头函数:根据所在的环境(我再哪个环境中,this就指向谁) 一针见血式总结: 普通函数中的this: 1. ...

  5. 箭头函数与定时器的this指向问题

    函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象. 箭头函数本身没有this,this继承上级的this. 定时器中箭头函数的this指向包含定时器的函数,所以定时器中的箭头函数要 ...

  6. ES6中的箭头函数的语法、指向、不定参数

    箭头函数的语法 function fn1() { console.log(1); } let fn2 = () => { console.log(2); } fn1()//1 fn2()//2 ...

  7. js 五种绑定彻底弄懂this,默认绑定、隐式绑定、显式绑定、new绑定、箭头函数绑定详解

     壹 ❀ 引 可以说this与闭包.原型链一样,属于JavaScript开发中老生常谈的问题了,百度一搜,this相关的文章铺天盖地.可开发好几年,被几道this题安排明明白白的人应该不在少数(我就是 ...

  8. JS五种绑定彻底弄懂this,默认绑定、隐式绑定、显式绑定、new绑定、箭头函数绑定详解&lpar;转载&rpar;

    目录 壹 ❀ 引 贰 ❀ this默认绑定 叁 ❀ this隐式绑定 1.隐式绑定 2.隐式丢失 肆 ❀ this显式绑定 伍 ❀ new绑定 陆 ❀ this绑定优先级 柒 ❀ 箭头函数的this ...

  9. ES6新特新之箭头函数使用细节

    <=这个大家都知道是小于等于,那么=>是什么呢?今天我们就来探究一下ES6的新特新-----胖箭头函数. 其他语言的函数定义都是很简洁的,但是为什么javaScript的就那么复杂呢?还必 ...

随机推荐

  1. 开发基于C&num;&period;NET的mongodb桌面版的应用程序&lpar;1&rpar;

    1.之前没有使用过C#开发过相应的桌面应用程序,现在既然要从零到有进行开发,自然要掌握好C#桌面开发相关的原理与技术,以及站在多类型用户的角度开发具有实际生产意义的mongodb数据库管理软件. 2. ...

  2. c语言调试接口

    http://blog.chinaunix.net/uid-10106787-id-2985587.html 在C语言程序设计中,常会出现各种各样的bug:段错误.参数异常等等.我们需要尽快定位错误, ...

  3. Mac下安装cocos2d-x环境

    安装后xcode之后,下载cocos2dx压缩包,解压 通过中断cd到cocos2dx文件夹内 输入下行命令 sudo ./install-templates-xcode.sh 执行成功后打开xcod ...

  4. 进程池爬取并存入mongodb

    设置进程池爬取拉钩网: # coding = utf- import json import pymongo import pandas as pd import requests from lxml ...

  5. 比特币源码分析--C&plus;&plus;11和boost库的应用

    比特币源码分析--C++11和boost库的应用     我们先停下探索比特币源码的步伐,来分析一下C++11和boost库在比特币源码中的应用.比特币是一个纯C++编写的项目,用到了C++11和bo ...

  6. day37-多进程多线程二-锁

    Lock组件 当我们用多进程来读写文件的时候,如果一个进程是写文件,一个进程是读文件,如果两个文件同时进行,肯定是不行的,必须是文件写结束以后,才可以进行读操作.或者是多个进程在共享一些资源的时候,同 ...

  7. &lt&semi;转&gt&semi;lua解析脚本过程中的关键数据结构介绍

    在这一篇文章中我先来介绍一下lua解析一个脚本文件时要用到的一些关键的数据结构,为将来的一系列代码分析打下一个良好的基础.在整个过程中,比较重要的几个源码文件分别是:llex.h,lparse.h.l ...

  8. CST&comma;CET&comma;UTC&comma;GMT&comma;DST&comma;Unix时间戳几种常见时间概述与关系(转)

    转自:http://www.cnblogs.com/frontendBY/p/5215785.html 1.UTC: Universal Time Coordinated 协调世界时,又称世界标准时间 ...

  9. 网页加速之Chromium 预载入 Prerendering

    前一篇博文已经介绍通过prefetch预先载入网页的资源来提升网页载入速度,以下我们一起来看一下网页加速之chromium prerendering.在介绍prerendering之前,先介绍两个概念 ...

  10. Ubuntu中的解压缩文件的方式

    记录Ubuntu下各种压缩和解压方式: .tar 解包:tar xvf FileName.tar 打包:tar cvf FileName.tar DirName (注:tar是打包,不是压缩!) -- ...