前几天发布的Javavscript基础——原型和原型链 收藏转化率还挺高,看来你们对于JS基础知识仍是很看重的,因为JS语言设计的关系,不少语言特性不是那么清晰。好比经典的this在哪的问题。javascript
本文研究一下Javascript的this指向。相信学完以后应该没啥问题。java
Javascript的this指向问题,有些人可能以为很简单,有些人却以为扑朔迷离,看完本文以后相应会对this的掌握有一个直观的判断,而不是"开局全靠猜"。面试
调用方式
肯定,跟定义环境无关。定义环境
决定,与调用方式无关
,也不能够bind(this)
。window
undefined
如下讨论均为非严格模式
,这个不影响今天的讨论。segmentfault
说结论每每是让人难以理解的,下面经过不一样的调用场景对this作一个说明。app
function test() { console.log(this); } test(); // 输出undefined
直接调用是最简单的, 大部分人在这里都能回答的很好。函数
直接调用时this指向
全局做用域
。this
- 非严格模式this指向window
- 严格模式this指向undefined
'use strict' var n = 1; var a = { n: 2, b: function() { console.log(this.n); } }; a.b(); // 输出2 var b = a.b; b(); // 输出1
非严格模式下,输出2和1,严格模式下输出2和一个报错(this指向undefined,访问undefined的n属性确定报错)
那若是你这么回答,满分
!设计
知其然还要知其因此然,咱们分析一下:code
为何输出2?对象
由于
a.b()
是对象调用方式,因此b()中的this指向a
为何输出1?
这个很是有意思,并且也颇有迷惑性,面试的时候常常问到,也常常有人被问倒。
var b = a.b
把a.b
赋值给变量b
,b就是一个函数,请注意: 这里只是赋值,没有调用,因此b中的this指向还不肯定
。
b();
调用函数b
,这是什么调用方式? 普通调用
,因此this指向全局做用域。
对象调用方式下this指向调用对象。
是否GET? 若是没有GET,请关注公众号NodeJs之路
,我在线给你答疑。
开胃菜已经吃了,下面来点"有难度的(实际上也没啥难度)"。
var n = 1; var a = { n: 2, b: { n: 3, c: function() { console.log(this.n) } } };
正确答案:未肯定调用环境
的状况下,this的指向不肯定
。错误答案:指向a.b对象,Too young too simple!
var n = 1; var a = { n: 2, b: { n: 3, c: function() { console.log(this.n) } } }; a.b.c(); // 输出3 a.c = a.b.c; a.c(); // 输出2 var c = a.b.c; c(); // 输出1
这道题跟以前那道对象调用
很像。
为何输出3?
对象调用方式下指向调用对象,a.b.c()中c()是经过a.b
对象调用,指向对象a.b
为何输出?
a.c = a.b.c 给a对象定义一个函数c,注意,此时没有调用!this指向不肯定a.c() 经过a对象来调用c(),因此this指向对象
a
为何输出1?
var c = a.b.c 函数赋值给普通变量,注意,此时没有调用!c(); 普通方式调用,指向window
嵌套对象调用方式下,this指向最终调用
函数的对象。
a.b.c.d.e.f.g.h()
h函数中的this指向a.b.c.d.e.f.g
var name = 1; function Person() { this.name = 2; } var p1= Person(); // p1为undefined console.log(p1.name); // 报错 var p2 = new Person(); console.log(p2.name); // 输出2
p1为何是undefined?
这道题比较坑,跟调用方式和this指向无关,由于Person函数没有返回值,js中,默认会返回undefined.
p2.name为何是2?
使用new操做符时,构造函数的返回值
默认
指向对象实例,因此p2.name就是Person()中的this.name
若是在Person()
函数中加上return this
的话,Person()
返回值仍是this
,由于这是普通调用。
原则上构造函数不该该有返回值,可是若是真的写了会怎么样?咱们来探讨一下。
function Person() { this.name = 2; return {}; } var p1 = new Person(); console.log(p1.name)// 输出undefined
虽然Js只有对象,可是有一些如string,number这种通常叫作简单对象,date,regex,array,object等等叫复杂对象。
function Person() { this.name = 2; return 1; } var p1 = new Person(); console.log(p1.name)// 输出2
使用typeof null
返回的是[object]
,证实null是个对象,不过我们来看看构造函数返回null的表现。
function Person() { this.name = 2; return null; } var p1 = new Person(); console.log(p1.name)// 输出2
构造函数中this指向对象实例自己,若是构造函数指明了返回值,那么表现以下:
var a = { n: 1 }; var b = { n: 2 } function f() { console.log(this.n); } var fa = f.bind(a); var fb = fa.bind(b); fa(); // 输出1 fb(); // 输出1
第1个输出1应该不难理解,bind能够更改function内部的this指向。屡次bind已经bind过的函数,this指向不变。
bind的实现原理有点复杂,将在下一篇文章进行详细解读。
bind能够手动绑定function的this,this
指向第1次
bind时的this。
这两个函数在this指向上表现一致,放到一块儿讲
var a = { n: 1 }; var b = { n: 2 } function f() { console.log(this.n); } f.call(a); // 输出1 f.apply(b); // 输出2
call和apply的第1个参数为function执行时的this,这个this是肯定的,对未使用过bind的函数进行屡次apply/call,this指向都会改变。
var n = 1; var b = { n: 2, a: () => { console.log(this.n); } } b.a(); // 输出1 b.a.call({n:3}); // 输出1
b.a定义时的this和n
,b
所在的this一致
,默认状况下为全局做用域
箭头函数的this指向定义时所在的this,这个是明确的,可是若是定义时所在的是1个function,那么this指向同上面7点。
说下我以前学JS遇到过的问题: ES5下function才会有做用域隔离, {}这种玩意不会隔离做用域。
构造函数方式调用指向对象实例
可是并不执行函数
this
指向为定义
箭头函数的this