以下js比较示例,引用“小小小小小亮”同学
点击我,跳转至他的分析结果
var a=11
function test1(){
this.a=22;
let b=function(){
console.log(this.a);
};
b();
}
var x=new test1();
输出11
var a=11;
function test2(){
this.a=22;
let b=()=>{console.log(this.a)}
b();
}
var x=new test2();
//输出22
这里往往有三种反应
1与3的反应一般都是this指向的不熟悉以及相关业务的实践量缺少
2的反应,应该是大多数人的反应,前者是解释的通的,单纯定义一个方法,并未被父级对象所引用(姑且这么说吧),则this指向的是全局,否,则指向父级对象
var a = function () {
console.log(this.test)
}
var b = {
test: 666,
a: a // a挂在了对象上(被引用)
// 等价于 a: function () {...}
}
b.a()
// 输出666
var a = function () {
console.log(this.test)
}
var b = function () {
this.test = 666
}
b.prototype.a = a // 挂在了原型链上(被引用)
var k = new b()
k.a()
// 输出666
var a = {
test: 666,
b: function () {
var c = function () { // 未被引用
console.log(this.test)
}
c()
}
}
a.b()
// 输出undefined
但第二种是百思不得理解的,因缺少混合模式或构造函数模式的开发经验,又是封装方法依赖注入,所以大部分的避免了作用域中去定义函数调用。
随着该问题的暴露,趁着这次,来个实践出真理
var test = 777
var a = function () {
// 不实例化的话,这里定义this是没有意义的
}
a.prototype.b = function () {
this.test = 666
let k = () => {
console.log(this.test)
}
k()
}
a.prototype.b()
// 输出666
很神奇是不是,这可能关系到=>函数的解析机制,暂且分析为:
如果=>函数定义在prototype下的作用域中时,this会指向prototype上所引用的父级对象
实践下
var test = 777
var a = function () {}
a.prototype.b = function () {
this.test = 666
let k = () => {
console.log(this.test)
}
k()
}
a.prototype.b.prototype.c = function () {
this.test = 555
let k = () => {
console.log(this.test)
}
k()
}
a.prototype.b() // 输出666
a.prototype.b.prototype.c() // 输出555
这里如果执行a.prototype
会发现除了b定义的方法外,还有一个constructor(构造器)函数的生成,但事实上是没用到这个的(只有实例化的时候),而且delete a.prototype.constructor
删除该函数后,调用的=>对象也依然没影响到this的指向或抛错,所以
有没constructor并不能成为判断=>指向的依据(个人观点)
经检验确实无误,那实例化试试
var test = 777
var a = function () {
// 实例化一定会经过构造器,则this可定义该处了
this.test = 666
}
a.prototype.b = function () {
let k = () => {
console.log(this.test)
}
k()
}
var b = new a()
b.b()
// 输出666
那回过头来看看,为什么没有prototype,直接实例化也能达到this指向局部呢?
var a=11;
function test2(){
this.a=22;
let b=()=>{console.log(this.a)}
b();
}
var x=new test2(); // 关键在此,new里实现了什么
//输出22
那关于new里实现了啥,百度上一搜一大把,这里简单来说,就是内部创建了个new Object()
并且将定义的”test2“这个函数用call或apply将this指向了object并return达到了this 的更变
来简单试试
var a = () => {
console.log(this.b)
}
var k = {
b: 666
}
a.call(k)
// 输出 undefined
按道理来说,应该是变的,因为ES5的函数定义更变this指向是成功了,那为啥ES6的=>函数指向没变?
要知道为啥,又得来看看=>函数里发生了什么……(无语)
这里就不提及更深层次的了,大致只要知道,=>函数因为是es6语法,已经被浏览器所解析,所以一用=>函数,就已经被预解析了(你还想在浏览器执行之前搞定?)因此,call或apply与=>有一定耦合性,没准在内部的执行过程中被if过滤掉了。
我们再来试试new Object()的创建方式
var a= {
test: 666,
b: function () {
var k= () => {
var kk = () => {
console.log(this.test)
}
kk()
}
k()
}
}
a.b()
// 输出666
=>函数在含有父级对象的作用域中定义,this即指向父级对象
好,实践到此为止,结果已经显而易见了。
function定义的子级函数对象必须被父级所引用,是父级对象的一部分,例如:
var a = {
b: function () { // 一部分
console.log(this)
}
}
/* or */
var a = function () {}
a.prototype.b = function () { // 一部分
console.log(this)
}
this则指向上一级对象,否则this永远指向全局。
=> 函数,如果定义在含有父级对象的作用域下或被实例化了,则this指向上一级对象,否则永远指向全局,例如:
var a = {
b: function () { // 父级
return (() => { // 父级对象下的作用域
console.log(this)
})()
}
}
/* or */
var a = function () {}
a.prototype.b = function () { // 父级
return (() => { // 父级对象下的作用域
console.log(this)
})()
}
还有二种说法:
1、有constructor则=>指向上一级,无则指向全局(不是很赞同)
2、有prototype则=>指向上一级,无则指向全局(有缺陷)
make:o︻そ╆OVE▅▅▅▆▇◤(清一色天空)
blog:http://blog.csdn.net/mcky_love
掘金:https://juejin.im/user/59fbe6c66fb9a045186a159a/posts
找一个问题时,又会发现另外的问题,查找另外的问题时,往往又有无穷无尽的问题滚来,前端,广,还TM深 例如上面的问题,再找下去,估计就跑到浏览器的框架源码去了,所以量力而行,适可而止……