面试题

1、var let const 区别实例

<script type="text/javascript">
    var aa = 1;
    function fn(n) {
       console.log(aa);
       var aa = 2;
    }
    fn();//undefinde   var 定义变量会变量提升,提升到函数局部的顶部,但是变量的赋值不会提升,所以是函数内部变量有声明而未定义,
    console.log(aa);//1
</script>

<script type="text/javascript">
    let aa = 1;
    function fn(n) {
       console.log(aa);
       let aa = 2;
    }
    fn();
    console.log(aa);//程序报错  aa is not defined     let 声明变量不会变量提升,let不能重复赋值 let会形成暂时性死区 不会向函数外去找已定义的变量 所以会报错
</script>
<script type="text/javascript">
    const aa = 1;
    function fn(n) {
       console.log(aa);
       const aa = 2;
    }
    fn();
    console.log(aa);//程序报错  aa is not defined    const继承了let的特性,且const声明变量不可更改
</script>

 2、

 var arr2 = [1,2,3,4];
 function aa(arr){  
  //形参预解析 var arr = arr2;
  console.log(arr); //[1,2,3,4,5] arr.push(
5)
    console.log(arr2); //[1,2,3,4,5]
 }
 aa(arr2);
console.log(arr2);//[1,2,3,4,5]

 3、

getName(); //5  函数提升优先级比变量提升要高,且不会被变量声明覆盖,但是会被变量赋值覆盖。
var getName = function () {
    console.log(4);
};

function getName() {
    console.log(5);
}
getName(); //4  被变量赋值覆盖  

 4、this指向

var fullname = 'John Doe';
var obj = {
    fullname: 'Colin Ihrig',
    prop: {
        fullname: 'Aurelio De Rosa',
        getFullname: function () {
            return this.fullname;
        }
    }
};

console.log(obj.prop.getFullname()); //Aurelio De Rosa
// 函数的最终调用者 obj.prop 

var test = obj.prop.getFullname;
console.log(test()); //John Doe
// 函数的最终调用者 test()  this-> window

obj.func = obj.prop.getFullname;
console.log(obj.func()); //Colin Ihrig
// 函数最终调用者是obj

var arr = [obj.prop.getFullname, 1, 2];
arr.fullname = "JiangHao"; //JiangHao
console.log(arr[0]()); // 函数最终调用者数组

 5、面向对象

        function Foo() {
            getName = function () {
                console.log(1);
            };
            return this;
        }

        Foo.getName = function () {
            console.log(2);
        };

        Foo.prototype.getName = function () {
            console.log(3);
        };

        var getName = function () {
            console.log(4);
        };

        function getName() {
            console.log(5);
        }

        Foo.getName(); //2
        getName(); //4
        Foo().getName();//1
        getName(); //4
        new Foo.getName();//2
        new Foo().getName(); //3
        new new Foo().getName();//3 

做这道题时,首先要明白一点:就是一开始的函数申明,function Foo(),在没有调用之前,始终是不会运行的.

1.Foo.getName()输出2!

  此处函数Foo()没有调用,不执行函数,后面的输出均于此函数什么时候调用有密切关系.

  此处的Foo是一个实例化对象,跟1行处的Foo除了同名再无其他关系.所以直接找到第5行处.这里第5行表示给Foo对象添加一个输出为2的方法.

2.getName()输出4.

  此处直接调用getName(),1行处的函数未执行,从上往下寻找,首先找到

  第7行处,定义的getName对象.

3.Foo().getName()输出1

  此处先运行Foo(),这里就调用第1行的函数了,运行后return一个this,这里调用Foo()的是window,所以this就指window。后面相当于window.getName()就直接找到函数内部getName()方法了.

4.getName()输出1

  因为在3中已经执行过Foo()函数了,函数内部内容有效.getName()无直接写明调用对象,此处调用的对象就是window,函数体内部,getName也并未重新定义,而是一个全局的getName(即window的方法),此处直接找到第二行处.

5.new Foo.getName()输出2

  以先执行5行处 Foo.getName()得到function(){console.log(2);}然后在 new function(){console.log(2);}

6.new Foo().getName()输出3

  此处,先函数调用Foo(),接着运行new Foo(),再用new得到的这个实例化对象运行属性getName(),而getName()是通过6行处的原型链来定义的,所以找到第6行.

7.new new Foo().getName()输出3

  此处有2个new,先执行右边的new Foo()得到一个实例化对象,这时,就无法运行左边的new了(总不至于new 后边跟一个实例对象吧),只能先运行后边的 .getName()得到一个函数,最后执行最左边的new.

六、

for (var i = 0; i < 5; i++) {
    console.log(i);
}   //0,1,2,3,4 不解释



for (var i = 0; i < 5; i++) {
    setTimeout(function () {
        console.log(i);
    }, 1000 * i);
}  //setTimeout 会延迟执行,那么执行到 console.log 的时候,其实 i 已经变成 5 了 ,开始输出一个 5,然后每隔一秒再输出一个 5,一共 5 个 5。




for (var i = 0; i < 5; i++) {
    (function (i) {
        setTimeout(function () {
            console.log(i);
        }, i * 1000);
    })(i);
}  //运用闭包 i 以参数的形式传到函数内部,这时候i 就是函数的内部变量, 就不会更改了,所以是 0,1,2,3,4



for (var i = 0; i < 5; i++) {
    (function () {
        setTimeout(function () {
            console.log(i);
        }, i * 1000);
    })(i);
}  //这个函数中没有形参,实参i传不进去,所以函数内部没有变量i,然后会向函数外去找变量i,当延时器触发函数的时候,这时i已经是5了,所以会是 5个5



for (var i = 0; i < 5; i++) {
    setTimeout((function (i) {
        console.log(i);
    })(i), i * 1000);
}   //因为传入的是一个自执行函数,当执行到这个代码的时候已经执行了,所以 0,1,2,3,4 

    //JS预解释: 在进入执行上下文阶段的时候函数并不会执行,简单来说就是当你声明这个函数的时候,只要不调用就不会执行,上下文里面只会保存着这个函数的引用,可以看做这个函数保存在内存中,只有到调用的时候函数才会执行,延时器的作用就是稍后调用这个函数,当是自执行函数的时候,就回直接执行了了。





setTimeout(function () {
    console.log(1)
}, 0);


new Promise(function executor(resolve) {
    console.log(2);
    for (var i = 0; i < 10000; i++) {
        i == 9999 && resolve();
    }
    console.log(3);
}).then(function () {
    console.log(4);
});
console.log(5);
//首先先碰到一个 setTimeout,于是会先设置一个定时,在定时结束后将传递这个函数放到任务队列里面,因此开始肯定不会输出 1 。

// 然后是一个 Promise,里面的函数是直接执行的,因此应该直接输出 2 3 。

// 然后,Promise 的 then 应当会放到当前 tick 的最后,但是还是在当前 tick 中。

// 因此,应当先输出 5,然后再输出 4 。

// 最后在到下一个 tick,就是 1 。

// “2 3 5 4 1”

 6、vue刷新页面以后丢失store的数据问题?

  刷新页面时vue实例重新加载,store就会被重置,可以把定义刷新前把store存入本地localStorage、sessionStorage、cookie中,localStorage是永久储存,重新打开页面时会读取上一次打开的页面数据,sessionStorage是储存到关闭为止,cookie不适合存大量数据。根据我的需求,最合适的是sessionStorage。

  beforeunload在页面刷新时触发,可以监听这个方法,让页面在刷新前存store到sessionStorage中。

  当然,在页面刷新时还要读取sessionStorage中的数据到store中,读取和储存都写在app.vue中。

 7、隐式转换

  

var str = false + 1;
document.write(str);  //1

var demo = false == 1;
document.write(demo); //false

if(typeof(a)&&-true+(+undefined)+""){
    console.log(1); 
}
//能打印出1 
// typeof(a) typeof打印未声明的变量不会报错,结果为字符串  "undefined" 
//-true 为 -1 
//+undefined 隐式转换 undefined 转换为数字 转不成结果为 NaN

//-1+NaN+""  结果为字符串 "NaN"

//所以if("undefined" && "NaN") 为true ,结果能打印

if(11 + "11" * 2 == 33){
    console.log(1);
}
//"11" * 2 为 22  22+11 = 33  if结果为true  所以能打印

 
!!" " + !!"" - !!false||document.write(333);
//双叹号  !!  是将表达式强制转化为bool值的运算,运算结果为true或false,表达式是什么值,结果就是对应的bool值,不再取非。
// !!" " true  
// !!"" false
// !!false  false 
// 1+0-0 = 1 为真 不走后面 所以不会打印

8、js中的 async 和 defer 有什么区别

  1)没有这个两个属性时,浏览器遇到script时,文档解析停止,其他线程现在下载并执行js脚本,执行完后接续解析文档

  2)添加async 时,文档解析不会停止,其他线程下载js脚本,脚本下载完成后开始执行脚本,执行脚本时文档停止解析,直到脚本解析完成,再继续解析  (异步下载,并立即执行)

  3)添加defer时,文档的解析不会停止,其他线程下载脚本,待文档解析完成之后,脚本才会执行。 (一步下载,待文档解析完成后,执行)

9、新增数据类型  

  1)set集合 :是Object里面的一种, set与数组不同在于set中不可以有重复数据,常用语去重操作

  2)Map类型:可以允许任何类型作为对象的键,弥补了object只能使用字符串作为键的问题

  3)symbol : Symbol意思是符号,有一个特性—每次创建一个Symbol值都是不一样的。

      symbol是程序创建并且可以用作属性键的值,并且它能避免命名冲突的风险。

      创建的方式也有点奇怪,只能通过调用全局函数Symbol()来完成。      

      let firstSymbol = Symbol();

  

10、display:inline-block的间隙问题和解决办法

  1) block水平的元素inline-block后,IE6/7没有换行符间隙问题,其他浏览器均有,

  2)inline水平的元素 inline-block后,所有主流浏览器都换行符 空格间隙问题。

  3)解决方法:   

    ①移除标签间的空格。(代码不优雅)

    ②在父元素上加上font-size:0;以及 letter-spacing 为负值

11、块级元素,行内元素,空元素

  空元素就是单个标签的  <br/>  meta  <hr/>   input    img (这样的就叫空元素)

12、ajax的缺点

  1)ajax不支持浏览器返回按钮

  2)安全问题,ajax暴露了与服务器交互的细节

  3)对搜索引擎的支持比较弱

  4)破坏了程序的异常机制

  5)不容易调试

13、git fetch 和git pull 的差别

  1)git fetch 相当于是从远程获取最新到本地,不会自动merge

  2)git pull:相当于是从远程获取最新版本并merge到本地

  在实际使用中,git fetch更安全一些   注:用git pull更新代码的话就比较简单暴力了但是根据commit ID来看的话,他们实际的实现原理是不一样的,所以不要用git pull,用git fetch和git merge更加安全。

14、@supports CSS3新引入的规则之一,主要用于检测当前浏览器是否支持某个CSS属性并加载具体样式.(浏览器支持不完善)

@supports (display: grid) {
    .container {
        color: red;
    }
}

 当浏览器支持display:grid这个CSS属性时才应用其中的样式

15、@media 媒体查询

@media screen and (max- 300px) {
    body {
        background-color:lightblue;
    }
}

 16、-webkit-backface-visibility 属性定义当元素不面向屏幕时是否可见。

visible 背面是可见的。
hidden 背面是不可见的。
//隐藏被旋转的 div 元素的背面:
div { backface
-visibility:hidden; -webkit-backface-visibility:hidden; /* Chrome 和 Safari */ -moz-backface-visibility:hidden; /* Firefox */ -ms-backface-visibility:hidden; /* Internet Explorer */ }

17、overflow-scrolling 

  -webkit-overflow-scrolling 属性控制元素在移动设备上是否使用滚动回弹效果.
  auto: 使用普通滚动, 当手指从触摸屏上移开,滚动会立即停止。
  touch: 使用具有回弹效果的滚动, 当手指从触摸屏上移开,内容会继续保持一段时间的滚动效果。继续滚动的速度和持续的时间和滚动手势的强烈程度成正比。同时也会创建一个新的堆栈上下文。

18、touch-action 用于设置触摸屏用户如何操纵元素的区域(例如,浏览器内置的缩放功能)。

  —touch-action:none; (这句代码的意思是:禁止触发默认的手势操作

  touch-acion: auto | none | [ [ [ pan-x || pan-y || pinch-zoom ? ] | manipulation ] || double-tap-zoom ? ]

属性值 
auto: 
  默认值。浏览器允许一些手势(touch)操作在设置了此属性的元素上,例如:对视口(viewport)平移、缩放等操作。

none: 
  禁止触发默认的手势操作。

pan-x: 
  可以在父级元素(the nearest ancestor)内进行水平移动的手势操作。

pan-y: 
  可以在父级元素内进行垂直移动的手势操作。

manipulation: 
  允许手势水平/垂直平移或持续的缩放。任何auto属性支持的额外操作都不支持。

注:touch-action只支持具有CSS width和height属性的元素。这个限制的目的是帮助浏览器优化低延时的手势操作。对于默认不支持此属性的元素,如这种内联元素,可以给它设置display:block这样的CSS属性来支持width和height。未来W3C规范会将此API扩展到支持所有元素。

18、pointer-events CSS 属性指定在什么情况下 (如果有) 某个特定的图形元素可以成为鼠标事件的 target

  pointer-events: none;

  1 阻止用户的点击动作产生任何效果

  2 阻止缺省鼠标指针的显示

  3 阻止CSS里的hover和active状态的变化触发事件

  4 阻止JavaScript点击动作触发的事件

19、NaN :非数字  

  alert(NaN==NaN) //false  基于这个原因 :定义了isNaN()函数。  判断其参数 是否“不是数值

  NaN不是数字,但是它的数据类型是数字

  NaN在布尔运算时被当作false

  console.log(isNaN('abc')); //true

  console.log(Number.isNaN('abc')); //false
 
  Number.isNaN() 方法确定传递的值是否为 NaN和其类型是 Number。它是原始的全局isNaN()的更强大的版本。
  
Number.isNaN(NaN);        // true
Number.isNaN(Number.NaN); // true
Number.isNaN(0 / 0)       // true
Number.isNaN("NaN"); // false,字符串 "NaN" 不会被隐式转换成数字 NaN。 Number.isNaN(undefined); // false Number.isNaN({}); // false Number.isNaN("blabla"); // false
Number.isNaN = Number.isNaN || function(value) {
    return typeof value === "number" && isNaN(value);
}

20、 get和post请求的区别


1) url可见性:
  get,参数url可见;
  post,url参数不可见

2)数据传输上:
  get,通过拼接url进行传递参数;
  post,通过body体传输参数

3)缓存性:
  get请求是可以缓存的
  post请求不可以缓存

4)后退页面的反应
  get请求页面后退时,不产生影响
  post请求页面后退时,会重新提交请求

5)传输数据的大小

  get一般传输数据大小不超过2k-4k(根据浏览器不同,限制不一样,但相差不大)

  post请求传输数据的大小根据php.ini 配置文件设定,也可以无限大。

6)安全性

  这个也是最不好分析的,原则上post肯定要比get安全,毕竟传输参数时url不可见,但也挡不住部分人闲的没事在那抓包玩。安全性个人觉得是没多大区别的,防君子不防小人就是这个道理。对传递的参数进行加密,其实都一样。

 21、什么是js事件流?

  

事件的概念:

  HTML中与javascript交互是通过事件驱动来实现的,例如鼠标点击事件、页面的滚动事件onscroll等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。

   

    "DOM2事件流"规定的事件流包括三个阶段:

    1,事件捕获阶段。

    2,处于目标阶段。

    3,事件冒泡阶段。

   

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事件流</title>
    <script>

    window.onload = function(){

        var oBtn = document.getElementById('btn');

        oBtn.addEventListener('click',function(){
            console.log('btn处于事件捕获阶段');
        }, true);
        oBtn.addEventListener('click',function(){
            console.log('btn处于事件冒泡阶段');
        }, false);

        document.addEventListener('click',function(){
            console.log('document处于事件捕获阶段');
        }, true);
        document.addEventListener('click',function(){
            console.log('document处于事件冒泡阶段');
        }, false);

        document.documentElement.addEventListener('click',function(){
            console.log('html处于事件捕获阶段');
        }, true);
        document.documentElement.addEventListener('click',function(){
            console.log('html处于事件冒泡阶段');
        }, false);

        document.body.addEventListener('click',function(){
            console.log('body处于事件捕获阶段');
        }, true);
        document.body.addEventListener('click',function(){
            console.log('body处于事件冒泡阶段');
        }, false);

    };

    </script>
</head>
<body>
    <a href="javascript:;" id="btn">按钮</a>
</body>
</html>

 

  1,addEventListener

    addEventListener是DOM2级事件新增的指定事件处理程序的操作,这个方法接收3个参数:要处理的事件名,作为事件处理程序的函数和一个布尔值,最后这个布尔值如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。

  2,document,documentElement和document.body三者之间的关系:

    document代表的是整个html页面,

    document.documentElement代表是的<html>标签。

    document.body代表的是<body>标签。

 首先在事件捕获过程中,document对象首先接收到click事件,然后事件沿着DOM树依次向下,一直传播到事件的实际目标。就是id为btn的标签。

  接着在事件冒泡的过程中,时间开始是由具体的元素(a标签)接收,然后逐级向上传播到较为不具体的节点。

22、浏览器内核的理解?

  一般内核包含:渲染引擎:获取html,css,图片          js引擎:解析执行javascript

(1)Trident(IE内核)

  国内很多的双核浏览器的其中一核便是 Trident,美其名曰 "兼容模式"。

  代表: IE、傲游、世界之窗浏览器、Avant、腾讯TT、猎豹安全浏览器、360极速浏览器、百度浏览器等。

  Window10 发布后,IE 将其内置浏览器命名为 Edge,Edge 最显著的特点就是新内核 EdgeHTML。

(2)Gecko(firefox)

  Gecko(Firefox 内核): Mozilla FireFox(火狐浏览器) 采用该内核,Gecko 的特点是代码完全公开,因此,其可开发程度很高,全世界的程序员都可以为其编写代码,增加功能。 可惜这几年已经没落了, 比如 打开速度慢、升级频繁、猪一样的队友flash、神一样的对手chrome。

(3) webkit(Safari)

  Safari 是苹果公司开发的浏览器,所用浏览器内核的名称是大名鼎鼎的 WebKit。

  现在很多人错误地把 webkit 叫做 chrome内核(即使 chrome内核已经是 blink 了),苹果感觉像被别人抢了媳妇,都哭晕再厕所里面了。

  代表浏览器:傲游浏览器3、 Apple Safari (Win/Mac/iPhone/iPad)、Symbian手机浏览器、Android 默认浏览器,

(4) Chromium/Blink(chrome)

  在 Chromium 项目中研发 Blink 渲染引擎(即浏览器核心),内置于 Chrome 浏览器之中。Blink 其实是 WebKit 的分支。

​   大部分国产浏览器最新版都采用Blink内核。二次开发

(5) Presto(Opera)

  Presto(已经废弃) 是挪威产浏览器 opera 的 "前任" 内核,为何说是 "前任",因为最新的 opera 浏览器早已将之抛弃从而投入到了谷歌怀抱了。


  移动端的浏览器内核主要说的是系统内置浏览器的内核。

  Android手机而言,使用率最高的就是Webkit内核,大部分国产浏览器宣称的自己的内核,基本上也是属于webkit二次开发。

  iOS以及WP7平台上,由于系统原因,系统大部分自带浏览器内核,一般是Safari或者IE内核Trident的

23、css优先级

  1)优先级就近原则,同权重的样式谁离标签内容近谁就优先级高;
  2)载入样式以最后载入的定位为准;
  3)!important优先级最高;
  4)权重计算:
  (1)内联,如style=”“——1000,
  (2)id,如#content——100,
  (3)类、伪类和属性选择器,如.content——10,
  (4)标签选择器和伪元素选择器,如div p——1
  (5)通配符、子选择器和相邻选择器,如*,>,+——0 

24、什么是Cookie 隔离?

  请求资源的时候不要让它带cookie怎么做

  如果静态文件都放在主域名下,那静态文件请求的时候都带有的cookie的数据提交给server的,非常浪费流量,所以不如隔离开。

  因为cookie有域的限制,因此不能跨域提交请求,故使用非主要域名的时候,请求头中就不会带有cookie数据,这样可以降低请求头的大小,降低请求时间,从而达到降低整体请求延时的目的。

  同时这种方式不会将cookie传入Web Server,也减少了Web Server对cookie的处理分析环节,提高了webserver的http请求的解析速度。

原文地址:https://www.cnblogs.com/zjz666/p/11318537.html