/*js运行机制题目*/
/*知识点:
1.所有的等号赋值,第一步是先创建值
函数创建的时候就声明了她的作用域
*/
/*
全局代码执行作用域EC(G)
*/
var i =0;
function A(){
var i =10;
function x(){
console.log(i)
}
// console.log(x)
return x //此时返回的是函数x的函数体
}
// console.log(A()+'111')
var y=A()
console.log(y)
// y()
// var y =A();
y();
function B(){
var i =20;
y()
}
B()
/*一般函数执行完毕之后就出栈释放了 函数堆释放
闭包:函数执行时产生一个不被释放的私有上下文(也就是被占用的时候 ),保护里面私有变量不受污染而且还可以把这些信息保存下来,
供她的下级上下文使用
* heap 堆函数释放:空指针 比如:
let obj ={a:'111'}
obj=null 空指针,此时obj之前指向的堆被释放
* stack 栈内存释放:
1. 全局上下文中,页面关闭即释放
2. 私有上下文中:
(1)函数执行完,私有上下文都会出栈释放
(2)当前上下文中的某些内容(比如一个堆),被除了当前上下文之外的内容占用了,就不能出栈.
GC浏览器垃圾回收机制:
(1)引用标记法_谷歌浏览器:当堆内存被占用时做标记(这个要自己查 TODO:)
(2)引用计数_IE低版本浏览器 容易内存泄漏 TODO: 查一下内存泄漏的原因以及情况
总结:当前内存如果被占用就不能被释放,没被占用的时候,浏览器会在空闲时间将他们释放出去
*/
/* let const var 的区别
* let: 创建一个变量,这个变量可以在下面被修改 比如:
let a =10;
a =12
console.log(a)-->12
* const: 创建一个变量,关联一个值,这个值不可被修改(不能需修改此变量的关联指向) 比如:
const b =10;
b=12 --> 报错
但是,如果 const 是一个对象,可以通过成员访问的方式进行修改
比如:
const b ={
name:'qqq'
}
b.name='aaa'
console.log(b)--> {name:'aaa'}
* 再相同的上下文中
(1) var 允许重复声明,但只识别一次
(2) let 不允许重复声明
*/
// console.log不会被执行,而是直接报错,是因为在词法解析阶段,如果有报错,所有代码都不会执行
//code.html:103 Uncaught SyntaxError: Identifier 'b' has already been declared
// console.log('ok')
// const b =10;
// const b =30;
/*
var 和function 中声明的变量,除了在全局变量对象VO(G)中储存,也会在GO(window)中设置相应的属性.(新版处理机制:在全局上下文中
基于bar 和function声明的变量,会直接存储到GO也就是window中,不会在 VO(G)中存储了)
let 和const 中声明的变量,只会在全局上下文VO(G)中存储,不会在GO(window )中存储
*/
/* js 中的暂时性死区:用typeof检测一个未声明的变量,不会报错,会显示 'undefined'
例如: console.log(typeof n ) -->此时n未被声明,typeof n 形成暂时性死区 但是
如果 let n =10 上面输出结果就会报错:不得在未声明之前使用n 所以
可以用 在下面let创建变量抵消上面的暂时性死区 即 let的机制可以抵消暂时性死区
*/
console.log(typeof n)
// var n =10 -->不会抵消暂时性死区
//let n=10
//-->Uncaught ReferenceError: Cannot access 'n' before initialization 抵消暂时性死区
{
var k=20
let m=90;// -->此时的m只是块级私有的 在下面无法被调用
console.log(m)
}
console.log(m)
/*
匿名函数:把函数作为值赋给xxx
例如: xxx.onclick=function(){....}
*/
/*
this 的指向
1-全局上下文中的this指向的是window
2-块级作用域指向的是他所继承的this,箭头函数也是
函数执行
* 正常的普通函数执行:看函数执行前是否有“点”,有,“点”前面是谁this就是谁,没有“点”,this是window「严格模式下是undefined」,
跟他在哪里调用 哪里执行的都没关系
* 匿名函数:
* + 函数表达式:等同于普通函数或者事件绑定等机制
* + 自执行函数:this一般都是window/undefined
* + 回调函数:一般都是window/undefined,但是如果另外函数执行中,对回调函数的执行做了特殊处理,以自己处理的为主
* 括号表达式:小括号中包含“多项”,这样也只取最后一项,但是this受到影响(一般是window/undefined),比如:(10,obj.fn)(),
* 指向的是window,如果开启严格模式,会显示undefind
* function fn() {
// console.log(this);
// }
// let obj = {
// name: 'zhufeng',
// fn
// // fn: fn
// };
// fn(); //this->window/undefined
// obj.fn(); //this->obj
自执行函数的this是window 或者undefeated(在严格模式下
自执行函数举例:
(function(){
console.log(this)==>输出window
})(10)
回调函数:把一个函数A作为实参,传递给另外一个执行的函数B「在B函数执行中,可以把A执行」
/* function fn(callback) {
// callback -> 匿名函数
callback();
}
fn(function () {
console.log(this);
}); */
/* let arr = [10, 20, 30];
// arr.forEach(function (item, index) {
// console.log(this); //->window
// });
arr.forEach(function (item, index) {
console.log(this); //->forEach第二个参数「对象」 forEach内部做处理了
},{xxx:'xxx'});
数组的foreach方法,传的第二个参数会改变this的指向
*/
//一道题来了!!
var x = 3,
obj = {
x: 5
};
/**在全局上下文中创建了变量
* x-------3
* 对象obj-------指向堆地址 0x001
* 作用域
**/
obj.fn = (function () {
this.x *= ++x;
return function (y) {
this.x *= (++x) + y;
console.log(x);
}
})();
/*
自执行函数,在创建的时候会自己调用一次,指向堆地址0x002
作用域:全局 EC(G)
内容:
'this.x *= ++x;
return function (y) {
this.x *= (++x) + y;
console.log(x);'
执行: this.x=this.x*(++x),前面的this.x,是window.x,也就是3,后面的x也是全局的x,也是3 所以
此时里面的x都是3 全局x经过运算之后
this.x=this.x*(++x)
=3*4
=12
执行完毕,返回一个匿名函数,存储在0x003 同时在0x001堆内存中创建 fn-------0x003,被占用,形成不被释放的闭包
注意:自执行函数,创建时自调用一次之后,返回的值 赋给等号前面的东西
此时:
全局变量中:
x-----3 变为 x------4(因为++x),再变为x-----12
0x003的内容:
'this.x *= (++x) + y;
console.log(x)'
形成作用域EC(003)
执行完毕后,没有被占用,释放0x002内存
此时0x001中的变量
x-------5
fn------0x003
*/
var fn = obj.fn;
/*在全局中创建一个变量fn-------0x003
此时全局变量中存在的有:
x-------------12
obj--------0x001
fn------------0x003
*/
obj.fn(6);
/*
执行0x003中的代码段
this.x *= (++x) + y;
console.log(x)
形成私有上下文,私有作用域EC(1),私有变量
y--------传参6
this的指向为obj,根据点语法,obj.fn调用,this就是obj
this.x=this.x*((++x)+y)
=5*((全局x--12自增=13)+6)
=5*(13+6)
=95
此时obj中的x发生改变
obj中:
x-----5 变为x----95
全局变量中
x----12 因为自增,变成了x----13
*/
fn(4);
/*
函数调用:相当于0x003中传参4
因为没有被点,所以匿名函数的this 没有严格模式下为window
此时:
this.x *= (++x) + y;
console.log(x)
this.x是window中的x,为13,++x的x 也是全局的x 为13,y是此匿名函数执行时形成的新的私有上下文EC(2)中的私有变量
y------4
所以执行函数:
this.x=this.x*((++x)+y)
=13*((x--13自增为14)+4)
=13*18
=234
----也就是 此时全局的x变成了234
因为没被占用,执行完毕后释放
*/
console.log(obj.x, x,);
/*最终这道题的答案是:
obj.x为95
x为234
*/
js运行机制
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 参考文章:阮一峰博客:JavaScript 运行机制详解:再谈Event Loop 1. JS 为什么是单线程? ...
- ———-正文开始———- 最近发现有不少介绍JS单线程运行机制的文章,但是发现很多都仅仅是介绍某一部分的知识,而且...