先来看这样几段代码
function func() {
function f() {
return this
}
console.log(f())
return f
}
func()()
let obj = {
func() {
function f() {
return this
}
console.log(f())
return f
}
}
obj.func()()
function T() {
this.func = function() {
function f() {
return this
}
console.log(f())
return f
}
}
let obj = new T()
obj.func()()
function T() {}
T.prototype.func = function() {
function f() {
return this
}
console.log(f())
return f
}
let obj = new T()
obj.func()()
class T {
func() {
function f() {
return this
}
console.log(f())
return f
}
}
let obj = new T()
obj.func()()
class T {
static func() {
function f() {
return this
}
console.log(f())
return f
}
}
T.func()()
如果你将他们一一粘贴到控制台运行后会发现:除了ES6的class的两个例子外,其余的例子,嵌套函数内部函数的this
都是指向全局对象window
,而ES6的class的两个例子中this
是undefined
。
实际上上述的几个例子基本展示了大部分函数调用的方法,我们想探究的是嵌套函数内部函数的this
指向什么。
在探究之前我们已知如下知识点
- 函数内部的
this
总是在运行时决定指向 - 直接调用的函数或自执行函数的内部
this
指向全局对象
那么ES6的class例子的行为理应和其他例子保持一致,为什么会出现指向undefined
的情况?那么一定是class内部有什么不同。
我在搜索ES6 class的源码时发现这么一个仓库:里面有一个es6 class转换成普通函数书写的转码器。
我们看到实际上class可以这样转义:
// Classes
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
get name() {
// Template strings
return `${this.firstName} ${this.lastName}`;
}
toString() {
return this.name;
}
}
// Normal Function
var $__Object$defineProperties = Object.defineProperties;
var Person = function() {
"use strict";
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
$__Object$defineProperties(Person.prototype, {
name: {
get: function() {
// Template strings
return "" + this.firstName + " " + this.lastName + "";
},
enumerable: true,
configurable: true
},
toString: {
value: function() {
return this.name;
},
enumerable: false,
writable: true
}
});
return Person;
}();
那么我们的例子转义后的结果将是:
var $__Object$defineProperties = Object.defineProperties;
// instance method
var T = function() {
"use strict";
function T() {}
$__Object$defineProperties(T.prototype, {
func: {
value: function() {
function f() {
return this
}
console.log(f())
return f
},
enumerable: false,
writable: true
}
});
return T;
}();
let obj = new T()
obj.func()()
// static method
var T = function() {
"use strict";
function T() {}
$__Object$defineProperties(T, {
func: {
value: function() {
function f() {
return this
}
console.log(f())
return f
},
enumerable: false,
writable: true
}
});
return T;
}();
T.func()()
实际上和我们上面普通function写法别无二致,唯一不同的就是这个"use strict"
。首先正常在控制台执行两个转义后代码的例子,结果仍然是this
指向undefined
;而后我们尝试删掉"use strict"
,this
确实又指向了window
。
原来一切都是因为严格模式啊。
关于严格模式的说明,大家可以参照阮老师Javascript 严格模式详解这篇文章,文章中提到的一点正解释了我们今天问题的现象。
最后我们顺便简单总结一下使用严格模式后产生的影响:
- 全局变量必须显式声明
- 禁止使用with语句
- 创设eval作用域
- 禁止this关键字指向全局对象
- 禁止在函数内部遍历调用栈,限制
arguments
的使用 - 禁止删除变量
- 对象属性、函数参数重名报错
- function函数必须声明在顶层
- 新增保留字
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!