转载自:http://www.cnblogs.com/dongcanliang/p/7054176.html

前言

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)。
    //1
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); //37
var a = o.f;
console.log(a()); //undefined/*这里undefine的原因是这是对象的函数,*/
/* a不能打印出来有功能的对象的函数*/
console.log(typeof(o.f));/*function*/
console.log(typeof(a));/*function*/ var o = {prop: 37}; function independent() {
return this.prop;
} o.f = independent; console.log(o.f()); // logs 37 //2
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"}

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

页面的代码块

在浏览器内显示三个按钮

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

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

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值,

  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对象

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

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

var obj = {
i: 10,
b: () => console.log(this.i, this),
c: function() {
console.log( this.i, this)
}
}
obj.b(); // undefined window{...}
obj.c(); // 10 Object {...}

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

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

参考文献

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

JavaScript中this的指向(转载)的更多相关文章

  1. javascript中this的指向

    作为一个前端小白在开发中对于this的指向问题有时候总是会模糊,于是花时间研究了一番. 首先this是JS的关键字,this是js函数在运行是生成的一个内部对象,生成的这个this只能在函数内部使用. ...

  2. Javascript中的this指向。

    一.JavaScript中的函数 在了解this指向之前,要先弄明白函数执行时它的执行环境是如何创建的,这样可以更清楚的去理解JavaScript中的this指向. function fn(x,y,n ...

  3. JavaScript中 this 的指向

    很多人都会被JavaScript中this的指向(也就是函数在调用时的调用上下文)弄晕,这里做一下总结: 首先,顶层的this指向全局对象. 函数中的this按照调用方法的不同,其指向也不同: 1.函 ...

  4. 前端面试之JavaScript中this的指向【待完善!】

    JavaScript中this的指向问题! 另一个特殊的对象是 this,它在标准函数和箭头函数中有不同的行为. 在标准函数中, this 引用的是把函数当成方法调用的上下文对象,这时候通常称其为 t ...

  5. 面试题-浅谈JavaScript中的This指向问题

    各位小伙伴在面试中被面试官问道this指向问题一定不少吧,同时还被问道apply,call和bind的用法区别,现在,就来简单的聊一聊this到底指向何方. 1.基本概念 MDN的官方解释:与其他语言 ...

  6. JavaScript中this究竟指向什么?

    摘要: 神奇的this! 原文:JS 中 this 在各个场景下的指向 译者:前端小智 Fundebug经授权转载,版权归原作者所有. 1. this 的奥秘 很多时候, JS 中的 this 对于咱 ...

  7. JavaScript中的this指向

    this是谁 技术一般水平有限,有什么错的地方,望大家指正. this代指当前对象super调用父类的构造函数,应表会运网数物,加载驱动建立链接执行SQL处理结果,直到现在每想起这三点就能想起我上大学 ...

  8. Javascript 中的this 指向的对象,你搞清楚了吗?

    Javascript 中的this 总让人感到困惑,你能分清以下三种test1(),test2(),test3() 情况下的输出吗? 注:以下Javascript运行环境中为浏览器 //1 this在 ...

  9. javascript中的this指向问题

    在深入学习JavaScript之后,我们越来越多的会遇到函数或者在对象内部中,对于this的指向问题的疑惑,其实基本上每一个编程语言中都有一个this,这个this的指向都是大同小异,你也可以汉化它的 ...

随机推荐

  1. No converter found for return value of type: class com.alibaba.fastjson.JSON解决办法

    默认情况下,springMVC的@ResponseBody返回的是String类型,如果返回其他类型则会报错.使用fastjson的情况下,在springmvc.xml配置里加入: <mvc:a ...

  2. web.xml中多个Servlet执行顺序的问题!

    1.两个servlet或者两个servlet-mapping,其中的servlet-name名称不能存在相同. 2.所有的servlet-mapping标签下,url-pattern中包含的文本不能相 ...

  3. token方法可用于临时关闭令牌验证,

    token方法可用于临时关闭令牌验证,例如: $model->token(false)->create(); 即可在提交表单的时候临时关闭令牌验证(即使开启了TOKEN_ON参数). 大理 ...

  4. 洛谷P3376【模板】网络最大流  Dinic模板

    之前的Dinic模板照着刘汝佳写的vector然后十分鬼畜跑得奇慢无比,虽然别人这样写也没慢多少但是自己的就是令人捉急. 改成邻接表之后快了三倍,虽然还是比较慢但是自己比较满意了.虽然一开始ecnt从 ...

  5. Mac系统下安装Vue-cli详细步骤

    Vue-cli安装 因为是mac系统,所以和视频里老师讲的有些许不同. 1.首先打开终端 按照老师的操作,首先检查node版本 下面是我的操作 打开终端,输入命令 node -v 我去,找不到node ...

  6. 自建免费的代理ip池

    00x01--- 前言 因为爬虫被禁ip这样的反扒真的很凶,但自从建了一个代理ip池以后,反反扒就可以跟的上节奏.当然你也可以上网上各种代理平台自己付费.这些平台当然很方便提供api调用,还不用自己验 ...

  7. nosql BASE

  8. vue:解决使用param传参后,再次刷新页面会新增一个原有的tab

    问题:在最近的项目中,我通过传递不同的参数,复用同一组件进行渲染,然而意外出现一个bug,就是当我重新刷新该页面时,会新增一个tab 原来的: 刷新页面后: 查阅资料后,发现该现象是由于通过param ...

  9. Django项目:CRM(客户关系管理系统)--82--72PerfectCRM实现CRM动态菜单和角色

    #models.py # ————————01PerfectCRM基本配置ADMIN———————— from django.db import models # Create your models ...

  10. vbox虚拟机复制&&虚拟机指定静态IP

    一.复制镜像(假设源镜像已经用桥接方式,可以访问互联网). 注意需要重新生成mac地址 二.复制完成,启动复制好的镜像(注意,此时的镜像无法联网) vi /etc/udev/rules.d/70-pe ...