Comments (336)
@littleluckly this 确实是指向 window ,但是这道题的陷阱在于 Foo 函数执行的时候,里面的 getName 函数覆盖了外层的 getName 函数
from blog.
太官方了,没看懂。
我知道的是:this一般有几种调用场景
var obj = {a: 1, b: function(){console.log(this);}}
1、作为对象调用时,指向该对象 obj.b(); // 指向obj
2、作为函数调用, var b = obj.b; b(); // 指向全局window
3、作为构造函数调用 var b = new Fun(); // this指向当前实例对象
4、作为call与apply调用 obj.b.apply(object, []); // this指向当前的object
from blog.
@littleluckly 刚才去吃饭了,这道题考察的是运算符优先级问题,各运算符优先级可以查看这里。
你会发现 成员访问 和 new (带参数列表)的优先级都为 19,相同等级下,遇到谁先执行谁,所以 new Foo().getName()相当于 (new Foo()).getName()
接下来的就比较简单了, new 返回一个对象,这个对象的原型指向 Foo.prototype,然后访问这个对象上的getName方法,自然是调用写在原型上的这个方法啦,结果也就是 3。
from blog.
@lynn1824 感谢补充,我觉得从调用场景去讲 this 的指向是一个非常重要的总结,这在我们日常的使用中非常重要。然而我该如何解释 (obj.b)()
(false || obj.b)()
(foo.bar, foo.bar)()
下 this 的指向呢?为什么 (obj.b)() 是作为对象调用, (false || obj.b)() 就是作为函数调用呢?不知道该如何很好的解释这些,才让我最终决定从规范的角度去讲一讲
from blog.
感觉看了三遍也没懂!!!
from blog.
@Nikaple 感谢回答,确实是这样的~
@MissCuriosity 回答的晚了,很抱歉,不知道你读规范受到了怎样的煎熬,实际上,我在学习 this 的时候,也深感艰难,要理解这篇文章的话,是要边跟着文章的思路边看规范的,而理解 this 的关键点在于通过查阅规范,判断表达式的结果是不是一个 Reference 类型。规范确实难懂,但若能克服对规范的恐惧,也是一个巨大的成长!与你相互勉励~
from blog.
@littleluckly 哈哈,感觉这是一个有味道的感谢,(~ ̄▽ ̄)~
from blog.
好了。博主。你成功把我讲懵逼了。
from blog.
下面一段代码的执行结果为1,why???,Foo()函数返回的this指window对吧,然后Foo().getName(),不就是指window.getName()吗,所以执行结果应该是5呀?求解答
function Foo(){
getName = function(){
console.log(1);
};
return this
}
function getName(){
console.log(5);
}
Foo().getName();
from blog.
@yangzhongxun 非严格模式下, this 的值如果为 undefined,默认指向全局对象
from blog.
@MrGoodBye 哈哈,(obj.b)()
也有两个括号呐……看规范的意思,(obj.b)()
和 (false || obj.b)()
的区别在于 ||
运算符对值进行了计算,可是为什么进行了计算,this 的指向就发生了变化呢?哎呀,我们还是来看规范吧……😂
from blog.
@mqyqingfeng 博主请务必一定接受一个抠脚大汉对你表示的感谢~~~么么哒
from blog.
= =没看懂,谢特,我再来看一遍。
from blog.
@MissCuriosity GetValue, GetBase以及Reference类型等这篇文章提到的概念都属于浏览器底层的实现,只是为了从原理上来解读this指向问题的,自然在console里是无法使用的~
from blog.
非常感谢博主,能看到这篇文章绝对是我的幸运。事实上我之前看到过一篇类似的文章http://dmitrysoshnikov.com/ecmascript/chapter-3-this/
虽然能理解大部分,但是文中介绍 Reference 类型不够清晰(或者说我看不懂),然后我也有跟博主一样的疑惑,最后还是博主这篇文章让我彻底明白了,再次感谢。我看了博主的几篇文章,感觉捡到宝了(兴奋)。希望博主能写更多好文章让我这种小白能更深入的理解JS,感激不尽!
from blog.
@sunsl516 哈哈,这一篇不影响以后文章的阅读,你可以安心读接下来的文章,这篇文章是为了告诉大家还有一种讲解 this 的角度是从规范切入,如果有一天,你想知道从规范怎么解读 this,那再回来看这一篇文章哈~
from blog.
@pxz199381 因为构造函数里没有把方法绑定到实例上,如果Foo
里是this.getName = ...
就会输出1了。
from blog.
我自己打印了一下,在foo.proto,foo.bar.__proto__中都没有GetValue,在全局直接使用GetValue也是报错得啊(GetValue is not defined),这一章真的是看得万脸懵逼啊!!
from blog.
看的我是万脸蒙逼啊
from blog.
from blog.
即渊博又谦逊的博主!!!感谢博主的分享!感谢我看到了这么棒的文章!!!
from blog.
这是我学JS这一个月看过最最最最难懂的文章,也是我遇到剖析的最深的文章,感谢博主的无私分享!!!
from blog.
感谢博主的分析,化繁为简,读完确实感觉判断this的思路清晰很多,只是要记住底层的方法还是要一些时间,一遍看下来还是要回头看很多次😂😂😂
另外关于示例4(false || foo.bar)()
中的解释:
2.Let lval be GetValue(lref).
刚看的时候觉得“不对吖,这个逻辑运算符的计算结果不应该是右边的foo.bar
么,跟lref应该没关系吧”,遂查看中文文档:
1. 令 lref 为解释执行 LogicalORExpression 的结果 .
2. 令 lval 为 GetValue(lref).
3. 如果 ToBoolean(lval) 为 true ,返回 lval.
4. 令 rref 为解释执行 LogicalANDExpression 的结果 .
5. 返回 GetValue(rref).
发现其实rref也做了一次GetValue()
操作,这样的话就能解释为什么是输出undefined
了,像示例4这种情况,博主只解释说lref的情况,理解容易出现偏差。
这里提个小小的建议,希望博主在解释的时候能尽量完整的说明产生这种结果的原因是什么。
再次感谢博主帮助分析底层逻辑结构,实在是获益良多。
from blog.
var value = 1;
var foo = {
value: 2,
bar: function () {
return this.value;
}
}
foo.bar() //2
var temp = foo.bar;
temp()//1
这种情况,感觉是=赋值引起的,就像上面说的(foo.bar = foo.bar)(),不知道这样理解对不对
from blog.
@mqyqingfeng 对哦,Foo()函数里面也是个一个函数表达式,getName也是指向的全局。谢谢博主
from blog.
@mqyqingfeng 感觉(false || obj.b)()
像是一个自调用立执行函数
,所以是函数调用模式
.
from blog.
@wy1009 o(////▽////)q
from blog.
请问楼主,这里好像只是单纯从ECMAScript的角度去诠释this,那在event事件以及setTimeout之类的计时器中this是如何去定义的
from blog.
@Ghohankawk foo.bar = foo.bar
就是取出 foo.bar 的值然后再赋值给 foo.bar,只是将自己的值再赋值给自己而已,返回的还是这个赋的值,也就是 foo.bar。
这些运算为什么会导致丢失呢?我也不知道,因为按照规范中的这些运算符的运算过程进行推导,最终得出的值并不是一个 Reference 类型,而它们不是 Reference 类型,判断 this 时就是会返回 undefined,可是为什么它们不返回一个 Reference 类型呢?是出于什么考虑的呢?我也不知道呀。
这篇文章算是给大家提供一个思路去判断 this 的值,不同于传统的根据场景和经验来判断,而是根据规范,切实可查的判断每个运算符的最终结果,根据是不是 Reference ,如果是 Reference 类型又怎样怎样,最终得出 this 值。
不得不说,真的很麻烦,哈哈~
from blog.
@Heroor 没有呀,执行上下文包含了 this,你说改变了执行上下文也是可以的呀~
from blog.
@ps520 如果 console.log(name),name 的值跟声明的位置有关系,现在是 console.log(this.name),就相当于打印某个对象的属性一样,这时候就要看 this 是指向哪个对象了~
from blog.
@mqyqingfeng 追问一下博主,如果代码改成如下这样,结果为3,请指教
function Foo(){
getName = function(){
console.log(1);
};
return this;
}
Foo.prototype.getName = function(){
console.log(3);
};
function getName(){
console.log(5);
};
new Foo().getName()//3
from blog.
嗯。 这个角度倒是很新颖。 这篇文章得反复琢磨才能搞懂。反正已经收藏了。后面再多看几遍。谢博主无私分享。@mqyqingfeng
from blog.
看了两遍,有一点不太明白,具体分析的例子里面的后三问的 this 为什么不是 window,而是 undefined,如果是 undefined,那么 undefined.value 的值为什么是 2 呢?博主有时间了还请帮忙解释下,多谢!
from blog.
@mqyqingfeng 多谢博主!规范的确更加难懂,不过也是语言的根本,向博主学习!
from blog.
@webLion200 哈哈,不影响以后文章的阅读,请安心的接着看~
from blog.
所以,上面的demo,你只需要把:
getName = function(){
console.log(1);
};
改成:
var getName = function(){
console.log(1);
};
输出结果就也是5
了。
from blog.
@chenxiaochun 哈哈,确实是这样的,不过@littleluckly 那道题其实是一道面试题,就是专门挖了这个陷阱~
from blog.
博主.前面都能看懂,就这一篇好多看不懂啊,我能怎么办我也很绝望啊
from blog.
@Flying-Eagle2 所以我特地讲了 即便不是很理解此篇的内容,依然不影响大家了解执行上下文这个主题下其他的内容。所以,依然可以安心的看下一篇文章
,我希望这篇文章能给大家带来一个新角度去看待 this ,暂时没有看懂,没有关系,以后突然想看了,那就再来啃一啃规范,那个时候也许就会看懂很多了~
from blog.
@mqyqingfeng 恩恩,感谢博主哈
from blog.
好文,从浏览器底层解读this指向,感谢博主~~~
from blog.
请问博主能不能讲一下浏览器的事件循环,task queue?job queue?以及渲染之类的?
from blog.
@sterproton 谢谢夸奖哈,浏览器方面的内容现在还没有研究过,不过已经加入了待研究课题中,未来一定会写这些内容的~
from blog.
这绝绝对对是我看到所有讲解this指向中最新颖的方式啦虽然大神的东东没看懂不过打算多看几遍
from blog.
大大呐 我也成功懵逼了 Mark着以后哪天脑子开窍了慢慢啃
from blog.
看的我整个人都**了
from blog.
又看了一遍,懂一点点了,爽
from blog.
道行太浅,以后再来读一遍
from blog.
@ershing 没有什么问题哈~ 我就是想知道规范到底是怎么确定 this 的~
from blog.
(foo.bar)()
foo.bar返回的是
function () {
return this.value;
}
感觉这应该是属于立即执行函数的范畴。
这样看运行的时候this不应该指向全局吗
from blog.
博主人好温柔呀……
from blog.
能不能做一下伸手党,请问一下,如果是箭头函数的this指向,在规范中是如何规定的呢?><感激不尽!
from blog.
from blog.
from blog.
@lynn1824 感谢回答哈~ @wy1009 我能说关于箭头函数的 this 在规范中是如何规定的,我还没有研究过吗……未来写到 ES6 系列的 arrow function,一定给你回复哈~
from blog.
楼主标准看了多少?之前问了一些人,都说看标准浪费时间,然后就没有看啦
from blog.
@YanLIU0822 标准我也并没有看过多少,我认为倒不需要专门去看规范,毕竟很多地方都很枯燥,有需要的时候,比如研究隐式类型转换的规则,就可以查看规范是如何定义的
from blog.
此文让我就明白一个道理,就是还是要去看规范
from blog.
到是博主另一片文章作用域链和上下文让我理解this了,其实说白了,this就是指向当前作用域上的[[scope]]
from blog.
value = 1;
function foo() {
var value = 2;
function dd() {
return this.value;
}
return dd;
}
console.log(foo()()) // 1
请问下楼主,里的结果分析应该用词法作用域还是用本章讲的this呢,有点混乱
from blog.
涉及到了 this,就是用本章的 this,如果没有,比如
value = 1;
function foo() {
var value = 2;
function dd() {
return value;
}
return dd;
}
console.log(foo()()) // 2
就根据词法作用域进行解释,此时的结果就变成了 2
from blog.
@mqyqingfeng 那么this.value是在调用foo()时,就已经确定了吗,还是最后foo()()时确定的。不好意思,这个是我疑惑的地方,刚才表述不太清楚。
from blog.
@fallenleaves409 this.value 是最后 foo()() 确定的,而 value 是函数创建的时候确定的~
from blog.
@mqyqingfeng 十分感谢 = =
from blog.
果然看不懂啊,果然道行不够
from blog.
function Foo(){
getName = function(){
console.log(1);
};
return this;
}
Foo.prototype.getName = function(){
console.log(3);
};
function getName(){
console.log(5);
};
new Foo().getName()//3
博主,为什么最后new的实例不先去找构造函数里的固有方法,而是直接从原型上找
from blog.
@Nikaple OK,多谢了
from blog.
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()());
这里object.getNameFunc()()的MemberExpression是object.getNameFunc(),那它是引用类型吗,如果是它的值是什么呀?@mqyqingfeng
from blog.
是否考虑完结的弄成PDF?
from blog.
受益匪浅
from blog.
@DarkYeahs 这个方面我还没有研究过,算是留个待补充的内容吧~
from blog.
楼主,表示一脸懵逼,完全看不明白,深受打击啊
from blog.
@jingaier 跳过这一篇哈~
from blog.
厉害厉害,准备全部看一遍搞个总结什么的出来
from blog.
@zanqianqvxifu 好呀,欢迎分享~
from blog.
首先说,第一个点是,第一次见这种直到this本质的规范文章,从来不知道,原来this是这样算出来的,第二点,前面有个说场景的那个同学,我也是基本是这么个认识,感觉足够了,可是看这篇文章
我有点不明白,比如,
console.log((foo.bar = foo.bar)());
console.log((false || foo.bar)());
console.log((foo.bar, foo.bar)());
像这种写法,(foo.bar = foo.bar)(),到底是啥意思?或者说,foo.bar=foo.bar左边括号里面,返回了啥?这是啥写法?(求解惑)
//而后面的,false || foo.bar,和false ,foo.bar,这2个地方,是一个表达式,分别是或表达,以及,逗号表达式,返回的内容,我知道,
//以前了解的this,也就是,所有这三种形式,都丢失了,this当前的上下文,变成了全局的this,也就是文章说的,undefined,或者说是,window对象
//但是为啥会丢失,看了这篇文章没找到答案,我的意思是说,能再大白话一点不,解释这里
后面三行,忽视掉,因为想起了,就是前面有个同学说的,其实就是,因为最终在全局环境中执行,
function () {
return this.value;
}
这里的this当然是window
from blog.
再看个例子
var value = 1;
var foo = {
value: 2,
bar: function () {
return this.value;
}
}
console.log((false || foo).bar()); // 2
你可以尝试所有函数调用.形式是
(any expression return a funcion)();
/*
如果不绑定,调用结果的this一定是window 或者 global
因为在规范中定义的函数调用符号()前面的是memberexpression,
你用括号括起来,没有访问符,那这不就是一个全局成员?
*/
from blog.
是不是可以这么说,用到了 || && , = ... 这些运算符,都会调用这个内置的getvalue。会导致它的this指向变化了。
from blog.
@jxZhangLi 是的~ 不过为什么会调用这个内置的 getValue 方法,我也没有想清楚😂
from blog.
看过的关于this的指向确定里面,唯一从规范角度来确定this指向的文章。即便是你不知道的JavaScript系列上中对于this的指向也是偏经验的角度,靠经验的话的确无法解释为何最后一个例子返回值是1。来来回回看了此文十遍左右,中间部分来回翻对着下面例子来解释,中午算是能理解了。也尝试用规范来解释最后一个经验解释不了的例子,的确this指向了全局,返回1。规范实在看不下去,幸好作者将关键的重点都拎出来,看起来省很多力气。感谢!
from blog.
看了这章感觉一脸懵逼~之前的this理解都是错误的么。。
from blog.
@c690554125 想说一句, 《你不知道的js》中的this的讲解根本没有任何偏经验的言论, 他是告诉了你规则(这也是根据规范得来的),而且在帮助你理解的时候,作者特意强调了函数就是函数本身,它从来不属于任何对象,this的指向取决于调用形式,函数是引用类型,我不觉得最后一个例子和 var f = foo.bar; f(); 有任何本质上的区别。
from blog.
@mqyqingfeng @Ghohankawk 这时因为foo.bar = foo.bar是个表达式呀, 而这个表达式返回的是右边那个foo.bar的值,也就是这个函数的引用(这是不加任何修饰的,你不知道的js中就是这样描述的,我也想不到更好的描述了...233),然后直接加()来调用,this自然就指向顶层对象了呀
from blog.
@MinhowS 不不,你之前理解的也没有错误……只是角度不同罢了,如果这篇看不懂,没有关系的,接着往下看,剩下的比起这篇都很简单哦~
from blog.
@c690554125 看这么多遍……真是辛苦了,棒棒哒~ o( ̄▽ ̄)d,希望带给你一个新的视角去理解 this ~
from blog.
@sinkinlife 之所以说最后一个例子和 var f = foo.bar; f() 本质是不同的,是因为从规范的角度去看的话,两者其实走了不同的 this 判断分支。返回函数引用的这种理解方式也是可以的啦,规范算是从更具体的角度去表示,相辅相成~
from blog.
@sinkinlife 哦,看懂你的意思了,明白你要说的内容了,对,这个地方,你这么一说,我也稍微明白啦,这种表达方式对于理解也是可以的,其实就是和类似,你主动调用了,如,function a(){alert("han")},这种函数一样,即使你没有返回任何东西,函数也是默认返回了,一个undefined的值,这里,就是你说的,foo.bar=foo.bar,这个东西虽然是赋值,但是是有返回值的,一个道理,谢谢了
from blog.
call方法改变的是函数执行上下文还是this呢?
from blog.
@yoky @jaweXU 这篇文章可能写的有些难懂,不要死磕,可以接着看下面的文章哈~
from blog.
@Heroor 应该改变的是 this,但是函数执行上下文也包含了 this 的概念~
from blog.
@mqyqingfeng 我在网上其他文章里看到说,call,apply改变的是执行上下文,然后执行上下文创建时会建立this,所以this就跟着变了,这么理解是不是不对啊
from blog.
@inventer13 这里被我写漏了,感谢指出哈~
from blog.
不明觉厉,看了博主其他文章,理清了很多困惑,感谢
from blog.
var name=456;
var p={
name:123,
say:{
name:789,
hello:function(){
console.log(this.name)
}
}
}
p.say.hello();//789
var b= p.say.hello;
b();//456
我看到过你说过 上下文关系和声明位置有关和执行位置无关,可是上面这段代码又怎么解释呢?
from blog.
@mqyqingfeng 大概明白了,谢谢回复。
from blog.
strict reference 没有解释
from blog.
from blog.
@HuangQiii 如果是
foo.bar = foo.bar;
foo.bar();// 2
还是有区别的。
from blog.
第一遍 ,一脸迷茫
from blog.
Related Issues (20)
- 冴羽答读者问:如何在工作中打造影响力,带动同事?
- 无
- 冴羽答读者问:如何学习更有计划性、提升更稳更快? HOT 4
- 冴羽答读者问:过程比结果重要吗? HOT 1
- 冴羽答读者问:冴羽,你为什么写起了鸡汤? HOT 3
- 聊聊 npm 的语义化版本(Semver) HOT 4
- How to create Backlinks 😤
- 思考题第2题
- 可以理解为原型是prototype,原型链是通过__proto__ 链接起来的吗
- React 之 createElement 源码解读 HOT 8
- React 之元素与组件的区别 HOT 1
- React 之 Refs 的使用和 forwardRef 的源码解读
- React 之 Context 的变迁与背后实现 HOT 1
- 第一段不报错啊,刚试过了,会打印1
- how can i HOT 1
- Hosting of Blog Issue
- 全局对象
- 为啥每次都要创建一个 Child函数来new 子类?现在不都是 const p1 = new Person(); const p2 = new Person()吗
- 文档内容中文件结构的错位 HOT 1
- 原型链继承
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from blog.