JavaScript 预编译后的面试题
一、复习预编译
开始总结的那两条
1. 函数声明整体提升
2. 变量声明 提升
这两句话不用记了,是由预编译产生的环节。
由于预编译才产生了函数声明整体提升,由预编译才产生了变量 声明提升。
1、看一个问题
访问 b 输出的是什么值?
console.log(b); // undefined var b = function () { }
1. 访问 b 输出 undefined,
2. 因为 var b 走的是变量,不是走函数。
预编译弄懂了之后,函数执行的任何顺序。一行一行怎么去执行,都没有任何问题了,预编译就是解决执行顺序问题的。
2、看第二题
下面的题有一个小 bug
if 判断里面定义函数 function c(){},大约在 2016 年之前谷歌浏览器内核浏览器是允许这么定义的,现在不允许了,但就当做它允许为了练题。
现在 if 判断里面定义一个函数声明,是语法不通过的,但是过去可以。
a = 100; function demo(e){ function e(){} arguments[0] = 2; console.log(e); if(a){ var b = 123; function c(){ // 过去谷歌浏览器内核是允许,if里面定义函数的,现在if里面定义函数声明是语法不通过的 } } var c; a = 10; var a; console.log(b); f = 123; console.log(c);// 这里应该打印function,现在打印的是undefined,因为现在if里不能定义函数 console.log(a); } var a; demo(1); console.log(a); console.log(f);
全局预编译
第一步,生成 GO{} 对象
第二步,GO 里面一个变量 a
GO{
a: undefined
}
第三步,然后还有一个函数声明
GO{
a: undefined,
demo: function(){code...}
}
GO完事了,开始执行
全局第一行 a = 100 先把 GO 里面的 a 变成100
GO{
a: 100,
demo: function(){code...}
}
全局
然后 demo 函数忽略
变量 a 也忽略
直接执行 demo(1)
在 demo(1) 执行的基础上,函数预编译
第一步,创建 AO{}
第二步,提升变量和形参
AO{
e: undefined,
b: undefined,
c: undefined,
a: undefined
}
第三步,实参形参相统一,实参e等于1
AO{
e: 1,
b: undefined,
c: undefined,
a: undefined
}
第四步:找函数声明,函数声明有 function e(){}、function c(){}
AO{
e: function e(){},
b: undefined,
c: function c(){} if里面声明函数语法是不允许的,这里当做它可以,if里面的函数声明c在预编译环节正常提升
a: undefined
}
预编译完了,下面开始执行 demo(1) 函数里面的语句
第一句,函数声明,不看了
第二句, arguments[0] = 2
实参列表与传的参数位置相映射,你改我也改,我改你也改,
也就是 arguments[0] 与形参 e 相映射,相当于让形参 e 的值也变成 2
AO{
e: 2,
b: undefined,
c: function c(){}, // 实际上c的值里是undefined
a: undefined
}
第三句,然后 console.log(e) 也输出 2
第四句, if(a) 此时a的值是 undefined,a 的值到 AO 里面找,不能通过判断 if 里面的语句不执行
第五句, var c 不看
第六句, a = 10 a 的值变成 10
AO{
e: 2,
b: undefined,
c: function c(){}, // 实际上c的值里是undefined
a: 10
}
第七句, var a 不看了
第八句, console.log(b) 再打印b输出AO里b的值是 undefined
第九句, f = 123 AO里没有 f,扔给GO,f是暗示全局变量放到GO里面
GO{
a: 100,
demo: function(){code...},
f: 123
}
第十句, console.log(c) 打印c其实理想中是function但现是undefined,因为现在语法if里不允许声明函数
第十一句, console.log(a) AO里a的值是10,打印输出10
函数执行完事了,外部全局
console.log(a) 全局上访问 a,输出GO里a的值是 100
console.log(f) 全局上访问 f,输出GO里的f值是 123
输出结果
2
undefined
undefined( IE老浏览器输入是function c(){} )
10
100
123
二、面试题
1、下面这些题处处是陷阱,考的全是隐式类型转换
第一题
加号两边只要没有"字符串",就是正常为数字相加,数字相加隐式转换类型成数字,false转化成数字是0,0加1等于1
var str = false + 1; document.write(str); // 1
第二题
这题这样解读,判断 false == 1 是否符相等,结果赋给demo。false不等于1,所以应该是false
var demo = false == 1; document.write(demo); // false
第三题
这道题是重点
if(typeof(a) && -true + (+undefined) + ""){ document.write("基础扎实"); }
1. 首先变量a未定义,typeof(a) 不报错并输出字符串类型的"undefined",
只有 typeof 这一种情况,用未定义的变量是不报错,而且返回字符串类型的 "undefined"
2. -true 转化结果是 -1, +undefined 趋势是转为 Number,但转不了转化值是 NaN,
隐式类型转换最多的是数学符号,凡是数学符号的趋势一般是转换成数字,转不了的一般是 NaN,但还是 number 类型。
3. -1 + NaN 还是NaN,NaN + ""(空字符串),结果是 "NaN" 的字符串
4. "undefined" || "NaN"
前面是字符串类型的"undefined",后面是字符串类型的"NaN",
"字符串类型"转化成布尔值都是 true,所以并且判断一定能通过的。
5. 判断能通过,可以打印出 "基础扎实"
第四题
if(11 + "11" * 2 == 33){ document.write("基础扎实"); }
1. "11" * 2 不管乘法两边是什么,都要转化成数字的,字符串 "11" 转成成数字 11,再乘2结果是数字类型的22
2. 数字 22 在加 11 等于 33
3. 33 == 33 打印基础扎实
类型转换除了加号以外,除、减、莫尔、乘等等都是把运算符两侧的东西转换成数字的,比如
document.write("11" - "2"); // 数字类型 9
第五题
这个题惊悚一点
!!" " + !!"" - !!false || document.write("你觉得能打印你就是猪");
首先知道一点"空字符串"和"空格字符串"不是一回事,
空格字符串转化是 true
空串转化是 false
document.write(Boolean("")); // false document.write(Boolean(" ")); // true
!!" " 非非空格字符串变成布尔值是 true
!!"" 非非空字符串转换成布尔值是 false
!!false 转换成布尔值是 false
true + false - false 转换数字 1 + 0 - 0 = 1
1 || document.write("你觉得能打印你就是猪"); 前面是true就不往后看了,所以后面的不可能打印出来
如果你觉得能打印,你就是 pork
2、写出下面程序的执行结果
var x = 1; if(function f(){}){ x += typeof(f); } console.log(x);
上面题没学到立即执行函数做不了,看下面这题
3、请写出window.foo的值(百度外卖的题)
这题是一个很简单的或运算符,但是或运算符暗藏杀机,但是这题考的挺缺心眼的
(window.foo || (window.foo = "bar"));
这题如果下面这样写,这道题就报错
(window.foo || window.foo = "bar");
首先清楚一点,这是一个优先级的问题,"或运算符"的优先级比赋值(等号)高
比如,下面 a 的值是 1,"或"是运算符要先计算的
var a = 1 || 2;
所以要是这样写 ( window.foo || window.foo = "bar" ) 成了,这两个 window.foo || window.foo 先计算然后在赋值,是坚决不可以的,会报错Uncaught ReferenceError:……
所以这题出的很精准,在里面加了一个小括号 ( window.foo || ( window.foo = "bar" ) );
解题顺序
1. 外面的括号,写不写没什么区别,反正先计算里面小括号里的
2. 先看里面括号 (window.foo = "bar"),先把bar赋值给 window.foo
3. 然后在看或运算符前面的 window.foo 的值是"bar",是"bar"就不往后读了
4. 最后是 window.foo 的结果是 bar
这题缺心眼,就是往错了分析也能答对
先看 window.foo 是 undefined,是 undefined 就往后看 (window.foo = "bar") 又变bar了,分析对分析错结果都是 bar
但是正确的理解一定是先看(window.foo = "bar"),先把bar赋进去
4、记录几个笔试题
1. css中display的属性有几种,分别是什么?block、none、inline、linline_block……
2. css中list-style的属性有几种,分别是什么?
3. 下面代码中,box_1和box_2平行排列均分父级的区域且没有边距,就是各占50%
<div class="box"> <div class="box_1"></div> <div class="box_2"></div> </div>
4. 写出下面程序的执行结果
var b = function a(){ return 23; } typeof a();