面试知识整理一

html + css基础

1.基本的布局(中间自适应旁边固定啥的)的几种实现方法;
http://blog.csdn.net/kongkongyou/article/details/54561760
2.垂直居中的几种实现方法;

方法一、(父块子块)对父容器使用display: table-cell+vertical-align: middle;使其内的子元素实现垂直居中

方法二、(父块子块)给父添加  display:flex; align-item:center;

方法三、(父块子行)特别是img,给子添加: vertical-align: middle; 给父添加 line-high:父
方法四、(父块子行)特别是文本,给父添加 line-high:父
关于vertical-align : 点击打开链接

3.盒模型;

box-sizingbox-sizing: content-box | border-box | inherit;

box-sizing:border-box;
width:200px;

padding:20px;

那么内容区高宽会自动调整,整个盒子固定为200px,盒子是指除了margin以外的部分。

4.position;
(1)static
static是position属性的默认值,默认情况下,块级元素和行内元素按照各自的特性进行显示
(2)relative
relative翻译成中文称相对定位,设置了这个属性后,元素会根据top,left,bottom,right进行偏移,关键点是它原本的空间仍然保留。

(3)absolute

元素设置成absolute后会脱离文档流,并且不占有原本的空间,后面的元素会顶替上去,而且不论元素是行内元素还是块级元素,都会生成一个块级框,也就是例如行内元素span设置了absolute后就可以设置height和width属性了。

(4)fixed

fixed的表现方式类似于absolute,但是相比于absolute相对于不确定的父元素进行偏移,fixed就是相对于浏览器窗口进行偏移。


5.行内元素和块元素;

一,下面从概念的角度来说一下块级元素和行内元素

1.块级元素,一般都是从新行开始,它可以容纳行内元素和其他块元素,常见块级元素比如div/p等。“form”这个快元素比较特殊,他只能来容纳其他块元素

2.行内元素:也叫做内联元素,一般都是语义级别的基本元素,内联元素已办只能容纳文本或者其他内联元素。

块元素(block element)和内联元素(inline element)都是html规范中的概念。块元素和内联元素的基本差异是块元素一般都是从新行开始的。而当加了css控制以后,块元素可以变为内联元素,内联元素也可以变为块元素。

3.行内元素包含替换元素和非替换元素:替换元素是浏览器根据其标签的元素与属性来判断显示具体的内容。 img、input、textarea、select、object 等都是替换元素, 可以设置宽高。大多数元素是不可替换元素,他们将内容直接告诉浏览器,将其显示出来。

这些元素都没有实际的内容

二,块级元素和内联元素的区别

1.块级元素会独占一行,其宽度自动填满其父元素宽度

行内元素不会独占一行,相邻的行内元素会排列到同一行里,直到一行排不下,才会换行,其宽度随元素的内容变化而变化,

2.一般情况下,块级元素可以设置width,height属性,行内元素设置width,height无效

(注意,块级元素设置了width宽度属性后仍然是独占一行的)

3.块级元素可以设置margin,padding属性,行内元素的水平方向的padding-left和padding-right都会产生边距效果,但是竖直方向上的padding-top和padding-bottom都不会产生边距效果。


6.BFC(块级格式化上下文Block Formatting Contexts,和浮动一起考);
  • 普通流 (normal flow)
在普通流中,元素按照其在 HTML 中的先后位置至上而下布局,在这个过程中,行内元素水平排列,直到当行被占满然后换行,块级元素则会被渲染为完整的一个新行,除非另外指定,否则所有元素默认都是普通流定位,也可以说,普通流中元素的位置由该元素在 HTML 文档中的位置决定。
  • 浮动 (float)
在浮动布局中,元素首先按照普通流的位置出现,然后根据浮动的方向尽可能的向左边或右边偏移,其效果与印刷排版中的文本环绕相似。
  • 绝对定位 (absolute positioning)
在绝对定位布局中,元素会整体脱离普通流,因此绝对定位元素不会对其兄弟元素造成影响,而元素具体的位置由绝对定位的坐标决定。

具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且 BFC 具有普通容器所没有的一些特性。相当于普通流。

通俗一点来讲,可以把 BFC 理解为一个封闭的大箱子,箱子内部的元素无论如何翻江倒海,都不会影响到外部。

只要元素满足下面任一条件即可触发 BFC 特性:

  • body 根元素
  • 浮动元素:float 除 none 以外的值
  • 绝对定位元素:position (absolute、fixed)
  • display 为 inline-block、table-cells、flex
  • overflow 除了 visible 以外的值 (hidden、auto、scroll)

BFC 特性及应用:

1. 同一个 BFC 下外边距会发生折叠
2. BFC 可以包含浮动的元素(清除浮动)

3. BFC 可以阻止元素被浮动元素覆盖

一般通过overflow:hidden触发BFC解决上面的问题

7.animation;



8.伪元素伪类;

伪元素是对元素中的特定内容进行操作,它所操作的层次比伪类更深了一层,也因此它的动态性比伪类要低得多。实际上,设计伪元素的目的就是去选取诸如元素内容第一个字(母)、第一行,选取某些内容前面或后面这种普通的选择器无法完成的工作。它控制的内容实际上和元素是相同的,但是它本身只是基于元素的抽象,并不存在于文档中,所以叫伪元素。

:first-letter     :first-line    :before     :after    :

伪类选择元素基于的是当前元素处于的状态,或者说元素当前所具有的特性,而不是元素的id、class、属性等静态的标志。由于状态是动态变化的,所以一个元素达到一个特定状态时,它可能得到一个伪类的样式;当状态改变时,它又会失去这个样式。由此可以看出,它的功能和class有些类似,但它是基于文档之外的抽象,所以叫伪类。

a:link {color:#FF0000;} /* 未访问的链接 */

a:visited {color:#00FF00;} /* 已访问的链接 */

a:hover {color:#FF00FF;} /* 鼠标划过链接 */

a:active {color:#0000FF;} /* 已选中的链接 */

:first-child :last-child :nth-child(n)


9.less、sass、stylus这种预处理器;

https://www.w3cplus.com/css/css-preprocessor-sass-vs-less-stylus-2.html

CSS预处理器用一种专门的编程语言,进行Web页面样式设计,然后再编译成正常的CSS文件,以供项目使用。

Sass是对CSS(层叠样式表)的语法的一种扩充,诞生于2007年,最早也是最成熟的一款CSS预处理器语言,它可以使用变量、常量、嵌套、混入、函数等功能,可以更有效有弹性的写出CSS。Sass最后还是会编译出合法的CSS让浏览器使用,也就是说它本身的语法并不太容易让浏览器识别,因为它不是标准的CSS格式,在它的语法内部可以使用动态变量等,所以它更像一种极简单的动态语言.

Less是2009年开源的一个项目,受Sass的影响较大,但又使用CSS的语法,让大部分开发者和设计师更容易上手。LESS提供了多种方式能平滑的将写好的代码转化成标准的CSS代码,在很多流行的框架和工具中已经能经常看到LESS的身影了(例如Twitter的Bootstrap框架就使用了LESS)。

Stylus,2010年产生,来自于Node.js社区,主要用来给Node项目进行CSS预处理支持,在此社区之内有一定支持者,在广泛的意义上人气还完全不如Sass和LESS。


js基础

深入理解js系列

1.原型链;

  • 原型是一个对象,其他对象可以通过它实现属性继承。任何一个对象都可以成为继承,所有对象在默认的情况下都有一个原型,因为原型本身也是对象,所以每个原型自身又有一个原型。任何一个对象都有一个prototype的属性,记为:__proto__。每当我们定义一个对象,其__proto__属性就指向了其prototype。示例如下:

 

[html]  view plain  copy
  1. var foo = {   
  2. x: 10,   
  3. y: 20   
  4. };  
  • 原型对象链=原型对象继承
  • 对象的原型指向对象的父,而父的原型又指向父的父,这种原型层层的关系,叫做原型链

    在查找一个对象的属性时,javascript会向上遍历原型链,直到找到给定名称的属性为止,当查找到达原型链的顶部,也即是Object.prototype,仍然没有找到指定的属性,就会返回undefined。

2.闭包;

有权访问另一个函数作用域的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另外一个函数,并返回


闭包是使用可以带来以下好处: 
1. 希望一个变量长期驻扎在内存中 
2. 避免全局变量的污染 
3. 私有成员的存在

我们刚才说到过,闭包可以读取到函数内部的变量,这是由于闭包后函数的堆栈不会释放,也就是说这些值始终保持在内存中。这是一个优点,也是一个缺点。

我们可以通过闭包来实现一个计数器,而不用担心全局变量的污染:

 function f1(){
    var n=999;
    nAdd=function(){n+=1}//全局变量
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  result(); // 1000

可以看到n一直存储在内存中,并没有在f1调用后被自动清除。

我们再来看看如何通过闭包来模拟javascript中的私有成员:模块化开发

var aaa = (function(){
        var a = 1;
        function bbb(){
                a++;
                alert(a);
        }
        function ccc(){
                a++;
                alert(a);
        }
        return {
                b:bbb,             //json结构
                c:ccc
        }
})();
aaa.b();     //2
aaa.c()      //3

点击打开链接

3.类和继承(es5实现方法 + es6实现方法); 

  • ES5创建类:
‘use strict’;
function Person(name){
   this.name = name;
}
Person.prototype.sayName = function(){
   return this.name;
}
  • ES6创建类:
    class Person{
       constructor(name){
         this.name = name;
        }
        sayName(){
          return this.name;
        }
    }

4.let、const、var;

  • var: 函数作用域,变量提升
  • let:块级作用域,let的特点是不会变量提升,而是被锁在当前块中。
    临时死区的意思是在当前作用域的块内,在声明变量前的区域叫做临时死区。

  • const: 块级作用域,声明常量,一旦声明,不可更改,而且常量必须初始化赋值。
    声明常量,一旦声明,不可更改,而且常量必须初始化赋值。
    我们试试重新声明type,看看会报什么错:
    const虽然是常量,不允许修改默认赋值,但如果定义的是对象Object,那么可以修改对象内部的属性值。

5.promise;
6.异步处理方法;
7.写一个方法遍历所有文档树所有节点(考察递归);
8.cookie和webstorege;
9.jsonp和跨域;
10.sort排序相关(注意ascll这个坑)
11.数组和对象的深浅拷贝;

  • 浅拷贝就是流于表面的拷贝方式;当属性值为对象类型时,只拷贝了对象数据的引用,导致新旧数据没有完全分离,还会互相影响。array.concat()或者array.slice() 是特殊的实现数组浅拷贝的方式。
  • 实现对象浅拷贝
    function mixin(sourceObj,targetObj){
      for(var key in sourceObj){
        if(!(key in targetObj){
           targetObj[key] =  sourceObj[key];
         }
       }
    return targetObj;
    }
  • 深拷贝就是 ‘完全'拷贝,拷贝之后新旧数据完全分离,不再共用对象类型的属性值,不会互相影响。
  • 一定要理解造成浅拷贝的原因:对象类型数据复制时,复制了引用地址,用的还是同一个数据对象;所以实现深拷贝的方式就是要对 对象类型属性值递归进行深拷贝,避免直接赋值。
  • 取巧方式 JSON.parse(JSON.stringify(Obj))   

    ?
    1
    2
    3
    4
    5
    var test = [1, 'a' ,{name: 'lei' ,age:18}];
    var copy1 = JSON.parse(JSON.stringify(test)); //特殊方式
    console.log(copy1);
    copy1[2].name = 'zhang'
    console.log(test);  //[1,'a',{name:'lei',age:18}] 未受到影响

    注意:这种方式不能深拷贝有属性值为函数的对象,  可自行尝试


  • //实现深拷贝
    function deepCopy( target ){
     if(typeof target !== 'object') return ;
     //判断目标类型,来创建返回值
     var newObj = target instanceof Array ? [] : {};
      
     for(var item in target){
      //只复制元素自身的属性,不复制原型链上的
      if(target.hasOwnProperty(item)){
       newObj[item] = (typeof target[item] == 'object') ? deepCopy(target[item]) : target[item] //判断属性值类型
      }
     }  
     return newObj
    }

12.String + Array的一些基本操作;
13.写一个数组去重的方法;

let arr = [1,1,2,2,3,3];
let s = new Set(arr);

let newArr = Array.from(s);
[...new Set([1,2,3,1,'a',1,'a'])]

14.冒泡和捕获;
15.事件代理;
16.this相关(注意箭头函数的this指向问题);

javascript所有的函数作用域内都有一个this对象代表用该函数的对象。在全局作用域中。this代表全局对象window。

当一个函数作为对象的方法被调用时,默认this的值等于那个对象。

function sayName(){
 console.log(this.name)
}
var p1 = {
 name:'n',
 sayName:sayName
}
var p2 = {
 name:'m',
 sayName:sayName
}
var name = 'sophia';
p1.sayName();//n
p2.sayName();//m
sayName();//sophia

深入理解ES6箭头函数的this以及各类this面试题总结

window.val = 1;
 var obj = {
   val: 2,
   dbl: function () {
     this.val *= 2;
     val *= 2;
     console.log(val);
     console.log(this.val);
   }
 };
 // 说出下面的输出结果
 obj.dbl();
 var func = obj.dbl;
 func();
结果是:  2   4    8   8

17.call、apply、bind;

JavaScript中,一切皆对象,函数是对象,对象可以有方法,所以函数也有方法。
三种函数方法改变this的值

1. call()方法:第一个参数指定了函数执行时this的值,其后的所有参数都是需要被传入函数的参数

function sayName(label){
 console.log(label+“:”+this.name)
}
var p1 = {
 name:'n'
}
var p2 = {
 name:'m'
}
var name = 'sophia';
sayName.call(this,'global');  //global:sophia
sayName.call(p1,'p1');        //p1:p1
sayName.call(p2,'p2');        //p2:p2
2.apply()方法:第一个参数指定了函数执行时this的值,第二个参数是数组内含需要被传入函数的参数(eg:arguments)

3.bind()方法:第一个参数是要传给新函数的this的值,其他所有参数代表需要被永久设置在新函数中的命名参数
function sayName(label){
 console.log(label+“:”+this.name)
}
var p1 = {
 name:'n'
}
var p2 = {
 name:'m'
}
var sp1 = sayName.bind(p1);
sp1("p1");
var sp2 = sayName.bind(p2);
sp2("p2");
p2.sayName = sp1;
p2.sayName("p2");

18.变量提升;

JavaScript中,我们通常说的作用域是函数作用域,使用var声明的变量,无论是在代码的哪个地方声明的,都会提升到当前作用域的最顶部声明,这种行为叫做变量提升Hoisting
也就是说,如果在函数内部声明的变量,都会被提升到该函数开头,而在全局声明的变量,就会提升到全局作用域的顶部。
实际执行时,上面的代码中的变量a会提升到函数顶部声明,即使if语句的条件是false,也一样不影响a变量提升。
在函数嵌套函数的场景下,变量只会提升到最近的一个函数顶部,而不会提升到外部函数。
如果a没有声明,那么就会报错,没有声明和声明后没有赋值是不一样的,这点一定要区分开,有助于我们找bug。
//没有赋值是undefined,没有声明是not defined

19.高阶函数;
20.动画;
21.setTimeout、setInterval和requestAnimationFrame;
22.模块化开发;

通过使用闭包我们封装了私有变量和方法,而只暴露了一个接口供其他部分调用。

点击打开链接

23.引起内存泄漏的原因;

javascript中的变量分为两种,原始值和引用值。原始值指的是原始数据类型的值,比如undefined,null,number,string,boolean类型所表示的值。引用值指的是复合数据类型的值,即Object,Function,Array等。

 原始值和引用值存储在内存中的位置分别为栈和堆原始值是存储在栈中的简单数据段,他们的值直接存储在变量访问的位置。引用值是存储在堆中的对象

存储在栈中的值是一个指针,指向存储在堆中的实际对象。

我们来看一段代码:

[html]  view plain  copy
  1. function Person(id,name,age){   
  2. this.id = id;   
  3. this.name = name;   
  4. this.age = age;   
  5. }   
  6. var num = 10;   
  7. var bol = true;   
  8. var str = "abc";   
  9. var obj = new Object();   
  10. var arr = ['a','b','c'];   
  11. var person = new Person(100,"jxl",22);  

再看看内存分析图:

由上图可知我们无法直接操作存储在堆中的数据,但是我们可以通过栈中的引用来操作对象。那么为什么要分开呢?不都是存储在内存中吗?

栈的优势就是存取速度比堆要快,仅次于直接位于CPU中的寄存器,但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,垃圾收集器会自动地收走这些不再使用的数据,但是缺点是由于在运行时动态分配内存,所以存取速度较慢。

所以相对于简单数据类型而言,他们占用内存比较小,如果放在堆中,查找会浪费很多时间,而把堆中的数据放入栈中也会影响栈的效率。比如对象和数组是可以无限拓展的,正好放在可以动态分配大小的堆中。

  • 全局变量引起的内存泄漏
function leaks(){ leak = 'xxxxxx';//leak 成为一个全局变量,不会被回收 } 

  • 闭包引起的内存泄漏
var leaks = (function(){ var leak = 'xxxxxx';// 被闭包所引用,不会被回收 return function(){ console.log(leak); } })() 

  • dom清空或删除时,事件未清除导致的内存泄漏
<div id="container">  
</div>

$('#container').bind('click', function(){ console.log('click'); }).remove(); // zepto 和原生 js下,#container dom 元素,还在内存里jquery 的 emptyremove会帮助开发者避免这个问题 

<div id="container">  
</div>

$('#container').bind('click', function(){ console.log('click'); }).off('click').remove(); //把事件清除了,即可从内存中移除 

关于这个问题,更详细的内容可以参考我的另外一篇文章关于 dom清空的内存泄漏问题

  • 子元素存在引用引起的内存泄漏

  • 黄色是指直接被 js变量所引用,在内存里
  • 红色是指间接被 js变量所引用,如上图,refB 被 refA 间接引用,导致即使 refB 变量被清空,也是不会被回收的
  • 子元素 refB 由于 parentNode 的间接引用,只要它不被删除,它所有的父元素(图中红色部分)都不会被删除
24.ajax;
Ajax  即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。

$.ajax({
        async: true,
        type: "POST",
        url: domainName + "/institution/mine",
        dataType: "json",
        data: {
            token_key: IL.token_key,
        },
        success: function (data) {
       }

});

25.map、filter、reduce相关;
26.Map和Set;
27.移动端开发相关;

28.从浏览器打开到页面渲染完成,花费了多少时间

是的,这个问题有点熟悉,面试官比较常问的是从浏览器打开到页面渲染完成,发生了什么事情。这个问题网上很多回答,我也不就重复的细说了。主要的过程是:

浏览器解析->查询缓存->dns查询->建立链接->服务器处理请求->服务器发送响应->客户端收到页面->解析HTML->构建渲染树->开始显示内容(白屏时间)->首屏内容加载完成(首屏时间)->用户可交互(DOMContentLoaded)->加载完成(load)


框架和工具相关

1.单页面应用是什么

单页Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。

对于SPA ( single page application 单页面应用),尤其是做移动端的网页应用,由于使用 <a/> 标签实现页面的切换和跳转,会有一定的加载时间消耗。

将网页应用做成一个SPA单页面应用,用视图切换(隐藏和显示)来模拟页面的切换。而但你的项目使用了vue进行开发,那么在实现视图切换的时候,你就可以借助vue-router来帮助你方便地实现视图切换。


2.vue数据绑定原理;


数据劫持,就是通过Object.defineProperty()来劫持对象属性的setter和getter操作,在数据变动时做你想要做的事情

通过 Object.defineProperty 实现的

<body>
    <div id="app">
        <input type="text" id="txt">
        <p id="show-txt"></p>
    </div>
    <script>
        var obj = {}
        Object.defineProperty(obj, 'txt', {
            get: function () {
                return obj
            },
            set: function (newValue) {
                document.getElementById('txt').value = newValue
                document.getElementById('show-txt').innerHTML = newValue
            }
        })
        document.addEventListener('keyup', function (e) {//订阅者模式
            obj.txt = e.target.value
        })
    </script>
</body>

3.vue父子组件和兄弟组件的通信问题;

  • 父组件→子组件:props是单向绑定的(父→子),是vue为了防止子组件无意修改了父组件的数据和状态,如果多个子组件任意地对父组件进行修改,这会让这很整个应用的数据流难以阅读。如果你想修改父组件传过来的数据,最好是定义一个局部的变量,来依赖传过来的数据。
  • 组件→组件:自定义事件 
每一个 vue 实例都实现了事件接口,我们可以用它提供的 API $emit( eventName) 来触发一个事件。
<div id="app">
    <son @connect="say"></son>
 </div>
Vue.component('son',{
  template:`<button @click="send">
                点击
             </button>`,
 data(){//data必须是个函数
        return{
            msg:'大家好,我是子组件的数据'
        }
    },
methods:{ 
   send(){ 
     this.$emit('connect',this.msg); 
     } 
 });
const app = new Vue({ 
   el:"#app", 
   methods:{ 
      say(msg){ 
         console.log(msg); 
      } 
    }  
});

  • 非父子组件通信:除了父子组件的相互通信,非父子关系的组件该如何通信,我们可以巧妙地利用一个空的vue实例来作为一个中央事件总线。

4.vuex的原理;

uex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态。这里的关键在于集中式存储管理。这意味着本来需要共享状态的更新是需要组件之间通讯的,而现在有了vuex,就组件就都和store通讯了。问题就自然解决了。

这就是为什么官网再次会提到Vuex构建大型应用的价值。如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex


5.vuex的action和mutation的异步操作和同步操作问题;
6.vue的事件监听;
7.vue-router获取自定义参数;
8.vue-router的go相关;
9.vue组件设计相关;
10.模块化的工具;
11.webpack打包优化;
12.设计一个自己的打包工具需要设计哪些主要功能;
13.babel相关;
14.mvvm的好处;
15.jquery的一些基本用法;
16.lodash相关;
17.vue和react的对比;
18.vue和jquery的对比;......

技术拓展

设计模式相关(单例、发布订阅等);
浏览器渲染过程;
性能优化相关(这个点很大,设计很多方面,不要自以为优化就是网上经常看到的那一套);
设计一个模版引擎;
设计一个打包工具;
设计一个mvvm框架需要注意的case;
源码阅读相关;

......


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值