可以看到它是第一种情况,this应该指向的是 GetBase(ref),也就是foo,答案为2对于示例2,加了括号并不会产生影响,所以结果不变至于示例3,4 , 5,他们都用了操作符 , 最后的结果是一个值 , 所以不是reference,this指向undefined
还有一种情况,就是第二种情况,这时返回的是ImplicitThisValue(ref),该函数总是返回undefined,所以最后this也是指向undefined的(当然个人认为这句话还是有点问题)例子
function foo() {console.log(this);}foo();
像上面这段代码在本机的输出结果其实是windows全局对象这是因为当前环境的JavaScript没有使用严格模式使用严格模式后,值为undefined
执行上下文那么在了解清楚前面几个东西之后,就可以来看看执行上下文了对执行上下文来说,有3个重要的属性:1.变量对象 2.作用域链 3.this依然给出这个例子
var scope = "global scope";function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f();}checkscope();
现在我们来通过上下文的角度重新分析一下这段代码
- 创建全局上下文,压入上下文栈:ECSstack = [globalContext]
- 全局上下文初始化globalContext = {VO: [global],Scope: [globalContext.VO],this: globalContext.VO}
- checkscope执行上下文入栈ECStack = [checkscopeContext,globalContext,];
checkscopeContext = {AO: {arguments: {length: 0},scope: undefined,f: reference to function f(){}},Scope: [AO, globalContext.VO],this: undefined}
在初始化的同时,保存作用域链到f的内部属性 [[ scope ]]- 创建f函数执行上下文,f函数被压入上下文栈ECStack = [fContext,checkscopeContext,globalContext];
- f函数上下文初始化,跟之前那一步一样
fContext = {AO: {arguments: {length: 0}},Scope: [AO, checkscopeContext.AO, globalContext.VO],this: undefined}
后面就是函数执行完赋值弹出出栈的过程闭包一般来说,闭包指的是函数+函数所能访问的自由变量自由变量是除了函数参数和函数中的局部变量,可以在函数中使用的变量在ECMAScript中,闭包指的是理论上:所有的函数 。因为在创建函数时 , 其上下文的数据就都被保存起来了,函数在访问全局变量时其实就是在访问自由变量实践上:即使创建它的上下文已经摧毁,它依然存在(比如内部函数从父函数返回)在代码中引用了自由变量引入之前的一个例子
var scope = "global scope";function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f;}var foo = checkscope();foo();
在这个例子中,我们可以复习一下之前学习的执行上下文? 进入全局代码,创建全局执行上下文,全局执行上下文压入执行上下文栈? 全局执行上下文初始化? 执行 checkscope 函数,创建 checkscope 函数执行上下文,checkscope 执行上下文被压入执行上下文栈? checkscope 执行上下文初始化 , 创建变量对象、作用域链、this等? checkscope 函数执行完毕,checkscope 执行上下文从执行上下文栈中弹出? 执行 f 函数,创建 f 函数执行上下文,f 执行上下文被压入执行上下文栈? f 执行上下文初始化 , 创建变量对象、作用域链、this等? f 函数执行完毕,f 函数上下文从执行上下文栈中弹出
可以发现执行f时,checkscope其实已经被销毁了(出栈了)但是f还是可以通过作用域链找到对应的AO , 所以即使checkscopeContext被销毁了,但是JavaScript却能让其AO一直在内存中,这就是实践中的闭包
两个例子:
var data = https://www.huyubaike.com/biancheng/[];for (var i = 0; i < 3; i++) { data[i] = function () { console.log(i); };}data[0]();data[1]();data[2]();var data = [];for (var i = 0; i < 3; i++) { data[i] = (function (i) { return function(){ console.log(i); } })(i);}data[0]();data[1]();data[2]();
第一段代码的输出都是3,而第二段代码输出分别为0 , 1,2主要的区别就是第二段代码中多了个匿名函数的作用域链,大家可以自行去解读call,bind浅析call
var foo = { value: 1};function bar() { console.log(this.value);}bar.call(foo); // 1
可以看出 , call函数改变了this的指向(指向了foo),并且bar函数也执行了当foo为null时,视为指向window
推荐阅读
- javascript编程单线程之异步模式Asynchronous
- javascript编程单线程之同步模式
- JavaScript函数式编程之函子
- 原生JavaScript
- Learning Records 计算机网络
- JavaScript之无题之让人烦躁的模块化
- GACL 谣言检测《Rumor Detection on Social Media with Graph Adversarial Contrastive Learning》
- Javascript 手写 LRU 算法
- javascript 中的 Microsoft.XMLHTTP 的相关问题!