撩课-每天刷Web面试题(前10天汇总)-Day12

一、算法题部分

1. 如何获取浏览器URL中查询字符串中的参数

function getParamsWithUrl(url) {    
   var args = url.split('?');   
   if (args[0] === url) {        
       return "";
    }    
    var arr = args[1].split('&');    
    var obj = {};    
    for ( var i = 0;
     i < arr.length; i++) 
     {        
       var arg = arr[i].split('=');
        obj[arg[0]] = arg[1];
    }    
    return obj;
}
 
var href = getParamsWithUrl
('http://www.itlike.com?id=1022&name=撩课&age=1');
console.log(href['name']); // 撩课

2. 写一个深度克隆方法(es5)?

/**
 *  深拷贝
 * @param {object}fromObj 拷贝的对象
 * @param {object}toObj  目标对象
 */
function deepCopyObj2NewObj(fromObj, toObj) {   
   for(var key in fromObj){       
     // 1. 取出键值对
     var fromValue = fromObj[key];       
     // 2. 检查当前的属性值是什么类型
     // 如果是值类型,那么就直接拷贝赋值
     if(!isObj(fromValue)){
       toObj[key] = fromValue;
     }else {           
        // 如果是引用类型,
        // 那么就再调用一次这个方法,
        // 去内部拷贝这个对象的所有属性
        var tempObj = 
        new fromValue.constructor;
        console.log(fromValue.constructor);
        deepCopyObj2NewObj(fromValue, tempObj);
        toObj[key] = tempObj;
     }
   }
}

/**
 * 辅助函数, 判断是否是对象
 * @param {object}obj
 * @returns {boolean}
 */
function isObj(obj) {  
    return obj instanceof Object;
}

3. 对数组[1,2,3,8,2,8]进行去重,es5或者es6方法?

es5四种方式:
方式一:
Array.prototype.unique1 = function() {    
    // 1. 定义数组
    var temp = [];    
    // 2. 遍历当前数组
    for(var i = 0; 
       i < this.length; i++) {        
        // 3.如果当前数组的第i
        // 已经保存进了临时数组,
        // 那么跳过,否则把当前项
        // push到临时数组里面
        if (-1 === temp.indexOf(this[i])) 
        {
           temp.push(this[i]);
        }
    }    
    return temp;
};

方式二:
Array.prototype.unique2 = function() {    
    //1. hash为hash表,r为临时数组
    var hash = {}, temp=[];    
    // 2.遍历当前数组
    for(var i = 0; i < this.length; i++)
    {        
        // 3. 如果hash表中没有当前项
        if (!hash[this[i]])
        {            
            // 4.存入hash表
            hash[this[i]] = true;            
            // 5.把当前数组的当前项
            // push到临时数组里面
            temp.push(this[i]);
        }
    }    
    return temp;
};

方式三:
Array.prototype.unique3 = function() {    
    var n = [this[0]];    
    for(var i = 1; 
        i < this.length; i++){        
       if (this.indexOf(this[i]) === i) {
            n.push(this[i]);
        }
    }    
    return n;
};

方式四:
Array.prototype.unique4 = function() {    
    this.sort();    
    var re=[this[0]];    
    for(var i = 1; 
        i < this.length; i++) {        
     if( this[i] !== re[re.length-1]){
        re.push(this[i]);
     }
    }    
    return re;
};

es6实现方式:
Array.prototype.unique =
Array.prototype.unique || 
() =>{    
    return [...new Set(this)];
};

4. 如何判断一个对象是否为数组?

function isArray(arg) {    
   if (typeof arg === 'object') {        
       return 
       Object.prototype.toString.call(arg)
       === '[object Array]';
    }   
    return false;
}

5. 冒泡排序?

思路:
每次比较相邻的两个数,
如果后一个比前一个小,换位置;

var arr = [2, 0, 1, 9, 8, 7, 3];
function bubbleSort(arr) {   
   for (var i = 0;
        i < arr.length - 1; i++) {
      for(var j = 0; 
          j < arr.l    i - 1; j++) {
         if(arr[j + 1] < arr[j]) {
            var temp;
            temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
         }
       }
   }
  return arr;
}
console.log(bubbleSort(arr));

6. 快速排序?

思路: 采用二分法,取出中间数,
数组每次和中间数比较,
小的放到左边,大的放到右边;

var arr = [2, 0, 1, 9, 8, 7, 3];
function quickSort(arr) {
    if(arr.length == 0) {
       // 返回空数组
       return [];    
    }
    var cIndex = Math.floor(arr.length / 2);    
    var c = arr.splice(cIndex, 1);    
    var l = [];    
    var r = [];
    for (var i = 0; 
         i < arr.length; 
         i++) {  
      if(arr[i] < c) {
         l.push(arr[i]);
      } else {
         r.push(arr[i]);
      }
    }    
    return quickSort(l).concat(c, quickSort(r));
}
console.log(quickSort(arr));

7. 正则表达式验证邮箱格式?

var reg = /^(\w)+(\.\w+)*@(\w)+((\.\w{2,3}){1,3})$/;
var email = "[email protected]";
console.log(reg.test(email));  // true  

8. 正则表达式清除字符串前后的空格?

function trim(str) {
    if (str && typeof str === "string") 
    {        
        // 去除前后空白符
        return 
        str.replace(/(^\s*)|(\s*)$/g,""); 
    }
}

------------------------------------------------------------------华丽分割线--------------------------------------------------------------------

二、JS系列部分

1. var的变量提升的底层原理是什么?

JS引擎的工作方式是:
1) 先解析代码,获取所有被声明的变量;
2) 然后在运行。也就是说分为预处理和执行两个阶段。
补充:
变量提升:所有变量的声明语句都会被提升到代码头部。
但是变量提升只对var命令声明的变量有效,如果一个变量不是
用var命令声明的,就不会发生变量提升。
js里的function也可看做变量,也存在变量提升情况。

2. JS如何计算浏览器的渲染时间?

浏览器的渲染过程主要包括以下几步:
1) 解析HTML生成DOM树。
2) 解析CSS生成CSSOM规则树。
3) 将DOM树与CSSOM规则树合并在一起生成渲染树。
4) 遍历渲染树开始布局,计算每个节点的位置大小信息。
5) 将渲染树每个节点绘制到屏幕。

优化考虑:
CSS 优先:引入顺序上,CSS 资源先于 JavaScript 资源。
JS置后:通常把JS代码放到页面底部,且JavaScript 应尽量少影响 DOM 的构建。

3. JS的回收机制?

垃圾回收机制就是间歇的不定期的寻找到不再使用的变量,
并释放掉它们所指向的内存; 主要为了以防内存泄漏,
(内存泄漏: 当已经不需要某块内存时这块内存还存在着), 

JS有两种变量: 全局变量和在函数中产生的局部变量。
局部变量的生命周期在函数执行过后就结束了,
此时便可将它引用的内存释放(即垃圾回收); 
但全局变量生命周期会持续到浏览器关闭页面。

JS执行环境中的垃圾回收器有两种方式:
标记清除(mark and sweep)、
引用计数(reference counting)。

标记清除:  垃圾收集器给内存中的所有变量都加上标记,
然后去掉环境中的变量以及被环境中的变量引用的变量的标记。
在此之后再被加上的标记的变量即为需要回收的变量,
因为环境中的变量已经无法访问到这些变量。

引用计数(reference counting):  这种方式常常会引起内存泄漏,
低版本的IE使用这种方式。机制就是跟踪一个值的引用次数,
当声明一个变量并将一个引用类型赋值给该变量时该值引用次数加1,
当这个变量指向其他一个时该值的引用次数便减一。
当该值引用次数为0时就会被回收。

4. 写一下节点增删改?

//  注意:动态创建元素不会直接显示在页面当中,
// 前面必须是document,不能是其他
1)document.createElement(标签名); 

// 在指定父级子节点最后一个后面追加子元素
2)父级.appendChild(要追加的元素) ;   

// 在父级的指定子元素前面插入一个新元素
(注意:先判断如果第二个参数的节点是否存在)
3)父级.insertBefore(新的元素,指定的已有子元素); 

// 深克隆(负值标签、标签属性、标签里面内容); 
// 浅克隆(负值标签、标签属性不复制标签里面内容)
4)元素.cloneNode(true) 或者元素.cloneNode(false);
5)父级.removeChild(已有子元素);
6)父级.replaceChild(新的元素节点,原有元素节点);

5. 如何获取元素的父节点和兄弟节点,写一下?

获取父节点:
// 1. parentNode获取父节点
// 获取的是当前元素的直接父元素。
var p = document.getElementById("test").parentNode;
 
// 2. parentElement获取父节点
// parentElement和parentNode一样,
只是parentElement是ie的标准。
var p1 = document.getElementById("test").parentElement;

// 3. offsetParent获取所有父节点
var p2 = document.getElementById("test").offsetParent;

获取兄弟节点:
// 1. 通过获取父亲节点再获取子节点来获取兄弟节点
var brother1 = document.getElementById("test").parentNode.children[1];

// 2. 获取上一个兄弟节点
// 在获取前一个兄弟节点的时候可以使用previousSibling
// 和previousElementSibling。
// 他们的区别是previousSibling会匹配字符,
// 包括换行和空格,而不是节点。
// previousElementSibling则直接匹配节点。
var brother2 = document.getElementById("test").previousElementSibling;
var brother3 = document.getElementById("test").previousSibling;

// 3. 获取下一个兄弟节点
var brother4 = document.getElementById("test").nextElementSibling;
var brother5 = document.getElementById("test").nextSibling;

6. 给你一个乱序数组,你怎么排序?

撩课小编:  sort, 冒泡, 选择, 二分法....

7. 原生JS都有哪些方式可以实现两个页面间的通信?


1)  通过url地址栏传递参数;
    例如:点击列表页中的每一条数据,
    我们跳转到同一个详细页面,
    但是根据点击的不一样可以看到
    不同的内容,这样的话我们就可以
    在URL中传递不同的值来区分了;

2)  通过本地存储 cookie、localeStorage、
    sessionStroage...,例如:京东的登录,
    我们在登录页登录完成后,
    把用户信息存储到本地,
    然后在其它页面中如果需要使用的话,
    我们直接从本地的存储数据中拿
    出来用即可;

3)  使用iframe在A页面中嵌入B页面,
    这样的话,在A中可以通过一些属性
    和方法实现和B页面的通信;

4)  利用postMessage实现页面间通信, 
    父窗口往子窗口传递信息, 
    子窗口往父窗口传递信息。

8. 原生JS动态向一个div中插入1000个div标签,如何实现?

此题主要考性能!

1)  可以用JS中的createElement创建div,
    每当创建一个就把它添加到div中, 
    但会造成引发回流的次数太多;

2)  使用字符串拼接的方式,
    把1000个div都拼接完成后,
    统一的添加到页面中, 
    但会对div原有的元素标签产生影响:
    原来标签绑定的事件都消失了

3)  综合1和2可以使用文档碎片方式来处理。

追问:如果是创建1000万个呢?

可采用的方案: 数据分批异步加载
1)  首先把前两屏幕的数据量
    (例如:300条)先获取到,
    然后使用字符串拼接或者文档碎片
    的方式绑定到页面中; 

2)  当浏览器滚动到指定的区域的
    时候在加载300条...以此类推。

9. 程序出现bug了,你是如何调试的?

1)  在控制台加断点,
    F10->逐过程  F11->逐语句;
2) 在代码重点的位置加入console.log输出对应的值来进行调试;
3) debugger调试;
4) 代码分割还原调试;
5) 异常捕获机制, 记录运行日志;
6) 单元测试。

10. 开发中是如何进行性能优化的?

现在框架(vue, react,...)、构建工具(webpack, ...)
已经给我们解决掉大部分的性能优化问题, 
面试时, 可以就你了解的框架来深入剖析, 
但此题应该是考原生JS的范畴,
参考答案如下:
1) 雅虎35条性能优化黄金定律;
2) JS代码优化:
   a. 项目中的JS/CSS文件最好一个页面只用一个, 
      需要把JS/CSS进行合并压缩, 
      并且减少页面中的垃圾冗余代码。
      项目的资源文件在服务器上最好
      做一下GZIP压缩。
   
  b. 解除文件缓存; 
     我们修改代码并上传, 
     如果之前页面访问过该网站,
     很有可能不能立即见效; 
     我们在引入CSS/JS文件的时候, 
     在文件名的后面加上版本号(加时间戳), 
     比如:     
     ; 
     当我们上传新的文件后
     把时间戳改一下就可以清除缓存了。

  c. 移动端尽量少用图片:
      icon能用svg画的不用图片;
     静态资源图:做布局的时候就能确定下来的图片,
      比如:     
      1)css sprite图片合并(针对于小图片)
      2)做图片延迟加载
         (针对于大图片 头部的长条图片、背景大图...),
         开始给一张默认的小的图片
         (最好维持在10kb以内)
      3)base64
        (存在问题: 页面的代码太臃肿了,以后维护不好操作);  
        如果项目中由于图片太大实在解决不了, 
        改成base64就解决了
   
  d. 动态数据图:
     通过ajax从后台读取回来的图片 , 图片懒加载;

  e. 音视频文件的优化: 
     加载页面的时候,尽量不要加载音视频文件,
     当页面中的其他资源加载完成后,
     再开始加载音视频文件; 
     目前移动端经常给音视频做的优化是:
     走直播流文件(音频后缀名是m3u8格式);

  f. 减少页面资源请求的次数:
     如果当前只是一个宣传页,
     或者是一个简单的页面, 
     使用的css和js可以采用内嵌式开发;

  g. ajax数据请求分批请求, 
     例如:一次要请求10000条数据的话,
     我们每一次只请求100条,第一屏幕肯定能看全了,
     当页面滚动到对应的其它屏幕的时候,
     在加载下一个100条...

  h. 做数据的二次缓存,  
     能用CSS3做动画的绝对不用JS,
     能使用transform尽量使用,
     能用animation的进行不用transition...
     尽量减少同步操作,多用异步操作;
     能使用原生JS自己编写的,
     绝对不用插件或者框架;  

撩课-每天刷Web面试题(前10天汇总)-Day12_第1张图片
在这里插入图片描述

11. 请描述下JS中事件冒泡机制?

冒泡型事件:事件按照从最特定的
事件目标到最不特定的事件目标
(document对象)的顺序触发。

捕获型事件:事件从最不精确的对
象(document 对象)开始触发,然后
到最精确。(也可以在窗口级别捕获
事件,不过必须由开发人员特别指定)。

支持W3C标准的浏览器在添加事件时
用addEventListener(event,fn,useCapture)方法,
基中第3个参数useCapture是一个Boolean值,
用来设置事件是在事件捕获时执行,
还是事件冒泡时执行。

而不兼容W3C的浏览器(IE)用attachEvent()方法,
此方法没有相关设置,
不过IE的事件模型默认是在事件冒泡时执行的,
也就是在useCapture等于false的时候执行,
所以把在处理事件时把useCapture
设置为false是比较安全,
也实现兼容浏览器的效果。

如下图所示:

撩课-每天刷Web面试题(前10天汇总)-Day12_第2张图片
在这里插入图片描述

12. 为什么利用多个域名来提供网站资源会更有效?

1.CDN缓存更方便

2.突破浏览器并发限制
(一般每个域名建立的链接不超过6个)

3.Cookieless,节省带宽,
尤其是上行带宽一般比下行要慢;

4.对于UGC的内容和主站隔离,
防止不必要的安全问题
(上传js窃取主站cookie之类的)。
正是这个原因要求用户内容的域名
必须不是自己主站的子域名,
而是一个完全独立的第三方域名。

5.数据做了划分,
甚至切到了不同的物理集群,
通过子域名来分流比较省事。

补充: 关于Cookie的问题,
带宽是次要的,安全隔离才是主要的。
关于多域名,也不是越多越好,
虽然服务器端可以做泛解释,
浏览器做dns解释也是耗时间的,
而且太多域名,如果要走https的话,
还有要多买证书和部署的问题。

13. 请说出三种减少页面加载时间的方法?

1.优化图片;
精灵图片, 字体图标
SVG, GIF, WEBP
(可用在一些对颜色要求不高的地方)

2. 优化CSS
(压缩合并css,
如margin-top,margin-left...)

3. 网址后加斜杠
(如www.itlike.com/目录,
会判断这个“目录是什么文件类型,
或者是目录。)

4. 标签标明高度和宽度
(如果浏览器没有找到这两个参数,
它需要一边下载图片一边计算大小,
如果图片很多,
浏览器需要不断地调整页面。
这不但影响速度,也影响浏览体验。
当浏览器知道了高度和宽度参数后,
即使图片暂时无法显示,
页面上也会腾出图片的空位,
然后继续加载后面的内容。
从而加载时间快了,
浏览体验也更好了。)

5.减少http请求
(合并文件,合并图片)。

14. cookie 和session 的区别?

1. cookie数据存放在客户的浏览器上,
session数据放在服务器上。

2. cookie不是很安全,
别人可以分析存放在本地的COOKIE,
并进行COOKIE欺骗,
考虑到安全应当使用session。

3. session会在一定时间内保存在服务器上。
当访问增多,会比较占用你服务器的性能
考虑到减轻服务器性能方面,
应当使用COOKIE。

4. 单个cookie保存的数据不能超过4K,
很多浏览器都限制一个站点最多保存20个cookie。

5. 开发建议:将登录,用户等重要信息存放为session,
其他信息如果需要保留,可以放在cookie中。

PS: 额外阅读

应用场景

经常登录一个网站,
今天输入用户名密码登录了,
第二天再打开很多情况下就直接打开了
。这个时候用到的一个机制就是cookie。

session的一个场景是购物车,
添加了商品之后客户端处
可以知道添加了哪些商品,
而服务器端如何判别呢,
所以也需要存储一些信息,
这里就用到了session。

Cookie
Cookie是访问某些网站以后
在本地存储的一些网站相关的信息,
下次再访问的时候减少一些步骤。

另外一个更准确的说法是:
Cookies是服务器在本地机器上
存储的小段文本并随每一个请求
发送至同一个服务器,
是一种在客户端保持状态的方案。

Cookie的主要内容包括:
名字,值,过期时间,路径和域。

Session

Session是存在服务器的
一种用来存放用户数据的类
HashTable结构。

当浏览器 第一次发送请求时,
服务器自动生成了一个HashTable
和一个Session ID用来唯一标识这个HashTable,
并将其通过响应发送到浏览器。

当浏览器第二次发送请求,
会将前一次服务器响应中的Session ID
放在请求中一并发送到服务器上,
服务器从请求中提取出Session ID,
并和保存的所有Session ID进行对比,
找到这个用户对应的HashTable。

一般这个值会有一个时间限制,
超时后毁掉这个值,默认是20分钟。

Session的实现方式和Cookie有一定关系。
试想一下,建立一个连接就生成一个session id,
那么打开几个页面就好几个了,
这显然不是我们想要的,

那么该怎么区分呢?

这里就用到了Cookie,
我们可以把session id存在Cookie中,
然后每次访问的时候将
Session id带过去就可以识别了

15. 如何理解闭包?

为什么要使用闭包:
因为JS中变量的作用域分类:
全局变量和局部变量。

函数内部可以读取函数外部的全局变量;
在函数外部无法读取函数内的局部变量。

为了让函数执行完成后,内部的函数、变量还
能被调用,可以采用闭包延长
局部变量/函数的生命周期。

定义和用法:
当一个函数的返回值是
另外一个函数,而返回的那个函数
如果调用了其父函数内部的其它变量,
如果返回的这个函数在外部被执行,
就产生了闭包。

表现形式:
使函数外部能够调用
函数内部定义的变量。

使用场景:
排他、函数节流、网络...

使用闭包的注意点:

滥用闭包,会造成内存泄漏;
由于闭包会使得函数中的变量
都被保存在内存中,内存消耗很大,
所以不能滥用闭包,
否则会造成网页的性能问题,
在IE中可能导致内存泄露。
解决方法是,在退出函数之前,
将不使用的局部变量指向null。

16.JS有哪些手段可以实现继承?

1. 原型链继承
将父类的实例作为子类的原型;

2. 借助构造函数继承
使用父类的构造函数来增强子类实例,
等于是复制父类的实例属性给子类;
(没用到原型)

3. 寄生组合继承(完美)
通过寄生方式,
砍掉父类的实例属性,
这样,在调用两次父类的构造的时候,
就不会初始化两次实例方法/属性,
避免的组合继承的缺点

4. 组合继承
通过调用父类构造,
继承父类的属性并保留传参的优点,
然后通过将父类实例作为子类原型,
实现函数复用

5. 拷贝继承
支持多继承,无法获取父类
不可枚举的方法

6. 实例继承
为父类实例添加新特性,
作为子类实例返回

17. 用纯JS实现,点击一个列表时,输出对应的索引?

方式一:
for(let i = 0, 
    len = lis.length; 
    i < len; i++){
    lis[i].addEventListener('click',
      function () {        
        console.log(i);
      }, false);
}

方式二:
for(var i = 0, 
    len = lis.length; 
    i < len; i++) {
    (function (i) {
        lis[i].addEventListener
        ('click', function () {            
             console.log(i);
        }, false);
    })(i)
}

方式三:
let ul = document.querySelector('ul');
let lis = document.querySelectorAll('ul li');
ul.addEventListener('click', 
function (e) {    
  let target = e.target;    
  if(target.nodeName.toLowerCase() === 'li') {        
      console.log([].indexOf.call(lis, target));
    }
}, false);

18. 以下代码有内存泄漏吗?

var user = {    
    name: '撩课', 
    age: 12, 
    gender: '女'
};

var box = document.getElementById('box');
box.onclick = function() {
    box.innerHTML = user.name;
};
// ...其他操作
user = null; // 释放对象

答:存在内存泄漏,
这是js中垃圾回收的引用计数造成的。
完全去除内存泄漏是不现实的,但是,
如果采用下面的方法可以减少内存泄漏:

var user = {    
   name: '撩课',    
   age: 12,    
   gender: '女'
};

var box = document.getElementById('box');
(function (name) {
    box.onclick = function() {
        box.innerHTML = name;
    };
})(user.name);
// ...其他操作
user = null; // 释放对象

19. es6中let,const,var的区别是什么?

var :声明全局变量;
let :声明块级变量,即局部变量, 定义后可以修改;
const :用于声明常量,就是定义后不能再修改值或者引用值的常量,也具有块级作用域4

20. 说说对es6中=>的理解?

箭头函数相当于匿名函数,
并且简化了函数定义,
箭头左边是参数,
右边是返回值。

箭头函数看上去
是匿名函数的一种简写,
但实际上,箭头函数和
匿名函数有个明显的区别:

箭头函数内部的this是词法作用域,
由上下文确定。

21. 点击按钮发出ajax请求,如何防止用户在此请求方式返回之前再次点击?

// 点击提交按钮的时候,
// 把这个提交这个处理函数给解绑掉,
// 请求完成的时候在绑定回来
function clickHandler(){
  $(this).unbind('click', clickHandler);
    $.ajax({        
       url : 'url',        
       dataType : 'json',
       type : 'post',
       success : function (data) {
         if (data.success) { 
          //提交成功做跳转处理
         } else { 
          //处理失败,重新绑定点击事件
          $(self).click(clickHandler);
         }
        }
  });
}
                
$('#itlike').click(clickHandler);
                
// 可以点击后让按钮不可用,
// 如果提交失败可以再次设置为可用
// 1.让按钮不可用
$("#itlike").attr("disabled","disabled");
$.ajax({
    url : 'url',
    dataType : 'json',    
    type : 'post',    
    success : function (data) {
       if (data.success) {
       // 提交成功做跳转处理
       } else {            
       // 处理失败,重新绑定点击事件
       // 2. 让按钮可用
       $("#itlike").removeAttr("disabled");
      }
    }
});

22. 请说明ECMAScript, JavaScript, Jscript之间的关系?

ECMAScript提供脚本语言必须遵守的规则、
细节和准则,是脚本语言的规范。
比如:ES5,ES6就是具体的一js版本。

JavaScript是ECMAScript的一个分支版本, 
JavaScript 实现了多数 ECMA-262 中
描述的 ECMAScript 规范,但存在少数差异。 

JScript是微软公司对ECMA-262语言规范的
一种实现,除了少数例外(这是为了保持向后兼容 ),
微软公司宣称JScript完全实现了ECMA标准.

关系:
JavaScript和JScript都是ECMAScript的版本分支, 
二者在语法上没有多大的区别; 
只不过一个是NetScape公司的, 一个是微软的; 
IE系列默认是JScript, 其它的则反之用JavaScript。

23. 页面加载过程中可能触发哪些事件? 它们的顺序是?

页面加载时,大致可以分为以下几个步骤:
1)  开始解析HTML文档结构;
2)  加载外部样式表及JavaScript脚本;
3)  解析执行JavaScript脚本;
4)  DOM树渲染完成;
5)  加载未完成的外部资源(如 图片);
6)  页面加载成功

执行顺序:
1)  document readystatechange事件
2)  document DOMContentLoaded事件 
3)  window load事件

24. 函数中在声明变量a前使用a会产生错误吗? 为什么?

不会, JS中能够进行变量作用域提升, 
把所有变量、函数的声明提升到当前
作用域的最前面, 但不进行赋值操作;

所以可能造成获取的值是undefined。

25. 什么是hash, 以及hashchange事件?

先了解下什么是hash:hash即URL中"#"字符后面的部分:
a) 使用浏览器访问网页时,
如果网页URL中带有hash,
页面就会定位到id(或name)
与hash值一样的元素的位置;
b) hash还有另一个特点,
它的改变不会导致页面重新加载;
c) hash值浏览器是不会随请求发送到服务器端的;
d) 通过window.location.hash属性获取和设置hash值。

window.location.hash值的变化会直接
反应到浏览器地址栏(#后面的部分会发生变化),
同时,浏览器地址栏hash值的变化也会触发
window.location.hash值的变化,
从而触发onhashchange事件。

再来了解下什么是hashchange事件:
a) 当URL的片段标识符更改时,
将触发hashchange事件
(跟在#符号后面的URL部分,包括#符号)
b) hashchange事件触发时,
事件对象会有hash改变前的URL
(oldURL)和hash改变后的URL
(newURL)两个属性。

26. 什么是CDN, CDN对于网站有什么意义, 它有什么样的缺点?

CDN又称为内容分发网络;  本意在于
尽可能避开互联网上有可能影响数据
传输速度和稳定性的瓶颈和环节,
使内容传输的更快、更稳定。

主要目的:

解决因分布、带宽、服务器性能带来的访问延迟问题,
适用于站点加速、点播、直播等场景。

使用户可就近取得所需内容,
解决 Internet网络拥挤的状况,
提高用户访问网站的响应速度和成功率。

缺点:
a) 实施复杂 , 投资大;
b) 目前大部分的CDN还只是对静态内容加速,
对动态加速效果不好;
而双线对动态加速的效果跟静态是一样的。

27. 说说你对作用域链的理解?

作用域链的作用是保证执行环境里
有权访问的变量和函数是有序的,
作用域链的变量只能向上访问,
变量访问到window对象即被终止,
作用域链向下访问变量是不被允许的;

作用域就是变量与函数的可访问范围,
即作用域控制着变量与函数的可见性
和生命周期。

28. 请说说JavaScript原型,原型链 ?

原型: 
当我们访问一个对象的属性时, 
每个对象都会在其内部初始化一个属性,
就是prototype(原型);

原型链:
如果这个对象内部不存在这个属性,
那么他就会去prototype里找这个属性,
这个prototype又会有自己的prototype,
于是就这样一直找下去,
也就是我们平时所说的原型链;

两者关系:
instance.constructor.prototype = instance.__proto__

29. 请解释什么是事件代理?

事件代理(Event Delegation),
又称之为事件委托。
是 JavaScript 中常用绑定事件
的常用技巧。

“事件代理”即是把原本需要绑定
的事件委托给父元素,让父元素
担当事件监听的角色。

事件代理的原理是DOM元素的事件冒泡。
使用事件代理的好处是可以提高性能, 
可以大量节省内存占用,减少事件注册,
比如在ul上代理所有li的click事件;

此外, 还可以实现动态新增子对象时无需
再次对其绑定事件。

30. new操作符具体完成了哪几个操作?

1) 创建一个空对象, 定义this 变量引用该对象,同时还继承了该函数的原型;
2) 属性和方法被加入到 this 引用的对象中;
3) 新创建的对象由 this 所引用, 并且最后隐式的返回 this

31. 说几条写JavaScript的基本规范?

1) 不要在同一行声明多个变量;
2) 请使用===/!==来比较true/false或者数值;
3) 使用对象字面量替代new Object这种形式;
4) 减少使用全局函数, 全局变量;
5) switch语句必须带有default分支;
6) if语句必须使用大括号;
7) for-in循环中的变量;
应该使用var关键字明确限定作用域;
从而避免作用域全局污染。

32. 如何解决跨域问题?

1) jsonp
2) iframe
3) window.name 
4) window.postMessage 
5) 服务器上设置代理页面

33. XML和JSON的区别?

1) 数据体积方面JSON相对于XML来讲,
数据的体积小,传递的速度更快些。
2) 数据交互方面JSON与JavaScript的交互更加方便,
更容易解析处理,更好的数据交互。
3) 数据描述方面;JSON对数据的描述性比XML较差。
4) 传输速度方面:JSON的速度要远远快于XML。

34. 在Javascript中什么是伪数组?如何将伪数组转化为标准数组?

伪数组(类数组):
无法直接调用数组方法, 
length属性有什么特殊的行为,
但仍可以对真正数组遍历方法来遍历它们。

典型的是函数的argument参数,
还有像调getElementsByTagName,document.childNodes之类的,
它们都返回NodeList对象,  这些都属于伪数组。

可以使用Array.prototype.slice.call(fArray)将数组
转化为真正的Array对象。

35. 一次完整的HTTP事务是怎样的一个过程?

基本流程:
a. 域名解析;
b. 发起TCP的3次握手;
c. 建立TCP连接后发起http请求;
d. 服务器端响应http请求,浏览器得到html代码;
e. 浏览器解析html代码,并请求html代码中的资源;
f. 浏览器对页面进行渲染呈现给用户

36. 开发中有哪些常见的Web攻击技术?

a) XSS
(Cross-Site Scripting,跨站脚本攻击)
指通过存在安全漏洞的Web网站注册用户的浏览器
内运行非法的HTML标签或者JavaScript进行的一种攻击。
b)SQL注入
c) CSRF
(Cross-Site Request Forgeries,跨站点请求伪造)
指攻击者通过设置好的陷阱,强制对已完成的认证用户进行
非预期的个人信息或设定信息等某些状态更新。

----------------------------------------------------------------华丽分割线----------------------------------------------------------------------

三、H5+C3部分

1. 垂直水平居中的方式?

/**
方式一:  定位
父元素设置为:position: relative; 
子元素设置为:position: absolute; 
距上50%,据左50%,然后减去元素自身宽度的距离就可以实现 
*/

width: 100px;
height: 100px;
position: absolute;
left: 50%;
top: 50%;
margin: -50px 0 0 -50px;

/** 方式二:  flex布局 */
display: flex;  //flex布局
justify-content: center; // 使子项目水平居中
align-items: center; // 使子项目垂直居中

/** 方式三:  table-cell  (不推荐) */
display: table-cell;
vertical-align: middle;//使子元素垂直居中
text-align: center;//使子元素水平居中

2. 实现一个三栏布局,中间版块自适应方法有哪些?

// 方式一: 浮动和定位
left
right
center
.left{ float: left; width: 100px; height: 200px; } .right{ float: right; padding: 0; width: 100px; height: 200px; } .center{ margin: 0 100px 0 200px; } 方式二: 将父容器的position设置为relative,两个边栏的position设置成absolute。

3. margin坍塌?

当两个盒子在垂直方向上设置margin值时,会出现塌陷现象。

解决方案主要包括:
1. 给父盒子添加border;
2. 给父盒子添加padding-top;
3. 给父盒子添加overflow:hidden;
4. 父盒子position:fixed;
5. 父盒子display:table;
6. 给子元素的前面添加一个兄弟元素
属性为content:"";overflow:hidden;

4. 说说BFC原理?

BFC就是页面上的一个隔离的独立容器,
容器里面的子元素不会影响到外面的元素。

因为BFC内部的元素和外部的元素绝对不会互相影响,
因此,当BFC外部存在浮动时,
它不会影响BFC内部Box的布局,
BFC会通过变窄,而不与浮动有重叠。

同样的,当BFC内部有浮动时,
为了不影响外部元素的布局,
BFC计算高度时会包括浮动的高度。
避免margin重叠也是这样的一个道理。

5. 为什么要清除浮动?举个实际场景?

父元素的高度是由子元素撑开的,
且子元素设置了浮动,
父元素没有设置浮动,
子元素脱离了标准的文档流,
那么父元素的高度会将其忽略,
如果不清除浮动,
父元素会出现高度不够,
那样如果设置border或者background都得不到正确的解析。

方式:
.clearfix::after,
.clearfix::before{   
   content:"";  
   display:table;   
   clear:both;
}

6. 你能描述一下渐进增强和优雅降级之间的不同吗?

定义:
优雅降级(graceful degradation):
一开始就构建站点的完整功能,
然后针对浏览器测试和修复

渐进增强(progressive enhancement): 
一开始只构建站点的最少特性,
然后不断针对各浏览器追加功能。

优雅降级和渐进增强都关注于同一网站
在不同设备里不同浏览器下的表现程度。

区别:
“优雅降级”观点认为应该针对那些最高级、
最完善的浏览器来设计网站。

而将那些被认为“过时”或有功能缺失的浏览器下
的测试工作安排在开发周期的最后阶段,并把测试
对象限定为主流浏览器(如 IE、Mozilla 等)的
前一个版本。

“渐进增强”观点则认为应关注于内容本身。

总结:
"优雅降级"就是首先完整地实现整个网站,
包括其中的功能和效果. 然后再为那些无
法支持所有功能的浏览器增加候选方案, 
使之在旧式浏览器上以某种形式降级体验
却不至于完全失效。

"渐进增强"则是从浏览器支持的基本功能开始,
首先为所有设备准备好清晰且语义化的html及
完整内容, 然后再以无侵入的方法向页面增加无
害于基础浏览器的额外样式和功能。
当浏览器升级时, 它们会自动呈现并发挥作用。

7. 请说说浏览器内核的组成?

浏览器的结构:

1)用户界面(UI)
包括菜单栏、工具栏、地址栏、后退/前进按钮、书签目录等,
也就是能看到的除了显示页面的主窗口之外的部分;

2)浏览器引擎(Rendering engine)
也被称为浏览器内核、渲染引擎,主要负责取得页面内容、
整理信息(应用CSS)、计算页面的显示方式,然后会输出到
显示器或者打印机;

3)JS解释器
也可以称为JS内核,主要负责处理javascript脚本程序,
一般都会附带在浏览器之中,例如chrome的V8引擎;

4)网络部分
主要用于网络调用,例如:HTTP请求,
其接口与平台无关,并为所有的平台提供底层实现;

5)UI后端
用于绘制基本的窗口部件,比如组合框和窗口等。

6)数据存储
保存类似于cookie、storage等数据部分,
HTML5新增了web database技术,一种完整的轻量级客
户端存储技术。

主要浏览器:
IE、Firefox、Safari、Chrome、Opera。

它们的浏览器内核(渲染引擎):
IE--Trident
FF(Mozilla)--Gecko
Safari--Webkit
Chrome--Blink(WebKit的分支)
Opera--原为Presto,现为Blink

8. 为什么利用多个域名来请求网络资源会更有效?

动静分离需求,使用不同的服务器处理请求。
处理动态内容的只处理动态内容,不处理别的,
提高效率。

突破浏览器并发限制, 同一时间针对同一域名
下的请求有一定数量限制。超过限制数目的请
求会被阻止。不同浏览器这个限制的数目不一样。

Cookieless, 节省带宽,尤其是上行带宽一般比下
行要慢。用户的每次访问,都会带上自己的cookie
,久而久之耗费的带宽还是挺大的。

假如weibo 的图片放在主站域名下,那么用户
每次访问图片时,request header 里就会带有
自己的cookie ,header 里的cookie 还不能压缩,
而图片是不需要知道用户的cookie 的,所以这部分带
宽就白白浪费了。

避免不必要的安全问题(比如: 上传js窃取主站cookie之类的)

节约主域名的连接数,从而提高客户端网络带宽的利用率,
优化页面响应。

9. 说说前端开发中, 如何进行性能优化?

1) 减少http请求次数:css spirit,data uri;
2) JS,CSS源码压缩;
3) 前端模板 JS+数据,减少由于HTML标签导致
    的带宽浪费,前端用变量保存AJAX请求结果,每
    次操作本地变量,不用请求,减少请求次数;
4) 用innerHTML代替DOM操作,减少DOM操作次数;
5) 用setTimeout来避免页面失去响应;
6) 用hash-table来优化查找;
7) 当需要设置的样式很多时设置className而不
    是直接操作style; 
8) 少用全局变量;
9) 缓存DOM节点查找的结果;
10) 避免使用CSS Expression;
11) 图片预载;

12) 避免在页面的主体布局中使用table,
table要等其中的内容完全下载之后才会显示出来,
显示比div+css布局慢;

13) 控制网页在网络传输过程中的数据量; 
比如: 启用GZIP压缩或者保持良好的编程习惯,
避免重复的CSS,JavaScript代码,
多余的HTML标签和属性。   

10. 从前端角度出发, 谈谈做好网站seo需要考虑什么?

1) 语义化html标签;
2) 合理的title, description, keywords;
3) 重要的html代码放前面;
4) 少用iframe, 搜索引擎不会抓取iframe中的内容
5) 图片加上alt

11. HTTP状态码及其含义?

1XX:信息状态码
100 Continue 继续,一般在发送post请求时,
已发送了http header之后服务端将返回此信息,
表示确认,之后发送具体参数信息;

2XX:成功状态码
200 OK 正常返回信息
201 Created 请求成功并且服务器创建了新的资源
202 Accepted 服务器已接受请求,但尚未处理

3XX:重定向
301 Moved Permanently 请求的网页已永久移动到新位置。
302 Found 临时性重定向。
303 See Other 临时性重定向,且总是使用 GET 请求新的 URI。
304 Not Modified 自从上次请求后,请求的网页未修改过。

4XX:客户端错误
400 Bad Request 服务器无法理解请求的格式,
客户端不应当尝试再次使用相同的内容发起请求。
401 Unauthorized 请求未授权。
403 Forbidden 禁止访问。
404 Not Found 找不到如何与 URI 相匹配的资源。

5XX: 服务器错误
500 Internal Server Error 最常见的服务器端错误。
503 Service Unavailable 服务器端暂时无法处理请求
(可能是过载或维护)。

12. html5有哪些新特性、移除了那些元素?

HTML5 现在已经不是 SGML 的子集,
主要是关于图像,位置,存储,多任务等功能的增加:
1) 绘画标签canvas;
2) 用于媒介回放的 video 和 audio 元素;
3) 本地离线存储 localStorage 长期存储数据,
浏览器关闭后数据不丢失;
4) sessionStorage的数据在浏览器关闭后自动删除;
5) 语意化更好的内容元素,
比如article、footer、header、nav、section;
6) 表单控件,calendar、date、time、email、url、search;
7) webworker, websocket, Geolocation;

移除的元素:
1) 纯表现的元素:basefont,big,center,font, s,strike,tt,...
2) 对可用性产生负面影响的元素:frame,frameset,noframes

13. display: none;与visibility: hidden;的区别?

相同点:它们都能让元素不可见

不同点:
display:none;会让元素完全从渲染树中消失,
渲染的时候不占据任何空间;

visibility: hidden;不会让元素从渲染树消失,
渲染师元素继续占据空间,只是内容不可见;

display: none;是非继承属性,
子孙节点消失由于元素从渲染树消失造成,
通过修改子孙节点属性无法显示;

visibility: hidden;是继承属性,
子孙节点消失由于继承了hidden,
通过设置visibility: visible;可以让子孙节点显示;

修改常规流中元素的display通常会造成文档重排。
修改visibility属性只会造成本元素的重绘。

读屏器不会读取display: none;元素内容;
会读取visibility: hidden;元素内容

14. px和em的区别?

px和em都是长度单位;

区别是: 
px的值是固定的,指定是多少就是多少,
计算比较容易。

em得值不是固定的,并且em会继承父级元素的字体大小。

浏览器的默认字体高都是16px;
所以未经调整的浏览器都符合: 1em=16px;
那么12px=0.75em, 10px=0.625em

15. CSS 去掉inline-block元素间隙的几种方法?

间隙是怎么来的:

间隙是由换行或者回车导致的;
只要把标签写成一行或者
标签直接没有空格,就不会出现间隙;

怎么去除?

方法1:
元素间的间隙出现的原因
是元素标签之间的空格,
把空格去掉间隙自然就会消失。
撩课itlike撩课itlike
方法2: 利用HTML注释标签
撩课itlike 撩课itlike
方法3: 取消标签闭合
撩课itlike 撩课itlike 撩课itlike 撩课itlike
方法4: 在父容器上使用font-size:0;可以消除间隙
撩课itlike 撩课itlike 撩课itlike 撩课itlike
.demo {font-size: 0;}

你可能感兴趣的:(撩课-每天刷Web面试题(前10天汇总)-Day12)