在三大框架盛行的时代, 基本上会个Vue就能在小公司浑水摸鱼。但是当想突破的时候就会意识到基础的重要性。
JavaScript中有很多重要特性及概念。比如原型,原型链,this,闭包,作用域,隐式转换等等。如果不能熟练掌握,在进阶中级前端开发工程师的道路上必定是困难重重。
用一个小时把这些题做完。检测一下你的基础掌握程度。
正题
第 1 题
if(false){
var a = 1;
let b = 2;
}
console.log(a);
console.log(b);
解析:
// 输出
undefined
ReferenceError: b is not defined
var不会产生块级作用域,let会产生块级作用域。
伪代码相当于:
var a;
if(false){
a = 1;
let b = 2;
}
console.log(a);
console.log(b);
第 2 题
var a = 1;
if(true){
console.log(a);
let a = 2;
}
解析:
// 输出
ReferenceError: Cannot access 'a' before initialization
let声明的变量不会提升,并且会产生暂存死区。在let声明变量之前访问变量会抛出错误。
第 3 题
var a = {n: 1}
var b = a
a.x = a = {n: 2}
console.log(a.n, b.n);
console.log(a.x, b.x);
解析:
// 输出
2 1
undefined {n: 2}
复制代码
var b = a,此时a和b指向同一个对象。
.运算符比 = 运算符高,先计算`a.x`,此时
b = {
n:1,
x:undefined
}
相当于给对象添加了x属性。
a.x = a = {n:2};
计算完a.x,再计算 = ,赋值是从右向左,此时a指向一个新对象。
a = {
n:2
}
a.x已经执行过了,此时对象的x属性赋值为a,此时
对象 = {
n:1,
x:{
n:2
}
}
即:
a = {
n:2
}
b = {
n:1,
x:{
n:2
}
}
第 4 题
console.log(c);
var c;
function c(a) {
console.log(a);
var a = 3;
function a(){
}
}
c(2);
解析:
// 输出
function c(a){
console.log(a);
var a = 3;
function a(){
}
}
function a(){
}
变量提升也有优先级, 函数声明 > arguments > 变量声明。
第 5 题
var c = 1;
function c(c) {
console.log(c);
var c = 3;
}
console.log(c);
c(2);
解析:
// 输出
1
TypeError: c is not a function
由于函数声明会提升,当函数外的console.log©执行时,c已经被赋值为1。因此,执行c(2)时会抛出TypeError,因为1不是函数。
第 6 题
var name = 'erdong';
(function () {
if (typeof name === 'undefined') {
var name = 'chen';
console.log(name);
} else {
console.log(name);
}
})();
解析:
// 输出
chen
// 复制代码自执行函数执行时,会先进行变量提升(这里涉及到执行上下文不过多说,一定要搞懂执行上下文),在自执行函数执行时,伪代码为:
var name = 'erdong';
(function () {
var name; // 变量name会提升到当前作用域顶部
if (typeof name === 'undefined') {
name = 'chen'
console.log(name)
} else {
console.log(name)
}
})();
// 复制代码所以会执行if中的console.log(name)
第 7 题
var a = 10;
function test() {
a = 100;
console.log(a);
console.log(this.a);
var a;
console.log(a);
}
test();
解析:
// 输出
100
10
100
test()为函数独立调用,作用域中的this绑定为全局对象window。
test函数执行时,var a被提升到了作用域顶部,因此函数作用域中存在一个变量a。所以在函数中访问的a都是局部作用域中的a。
第 8 题
if (!('a' in window)) {
var a = 1;
}
console.log(a);
解析:
// 输出
undefined
// 复制代码由于if后的{}不会产生块级作用域(不包含let,const时),此时的伪代码为:
var a;
if (!(a in window)) {
a = 1;
}
console.log(a);
// 复制代码var a相当于window.a。因此!(a in window)转成布尔值为false,不会执行a = 1。所有console.log(a)输出undefined。
第 9 题
var a = 1;
function c(a, b) {
console.log(a);
a = 2;
console.log(a);
}
c();
解析:
//输出
undefined
2
// 跟第4题类似。
第 10 题
var val=1;
var obj={
val:2,
del:function(){
console.log(this);
this.val*=2;
console.log(val);
}
}
obj.del();
解析:
// 输出
obj(指向的值)
1
/* 复制代码当通过obj.del()调用del函数时,del函数作用域中的this绑定为obj。
在函数作用域中访问val时,由于函数中并没有变量val,因此实际上访问的是全局作用域中的val,即 1。
这里考察的是this的指向,一定要熟练掌握。*/