Go to comments

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)函数里面的语句


05/

第一句:函数声明,不看了


第二句: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的值是2,"或"是运算符要先计算的

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();



Leave a comment 0 Comments.

Leave a Reply

换一张