前端开发那些事让前端飞Web前端之路

【面试向】极简前端知识点(不断更新)

2018-05-16  本文已影响101人  _月光临海

强烈推荐:https://github.com/mqyqingfeng/Blog

别人总结的前端面试题:https://github.com/BearD01001/front-end-QA-to-interview


CS / BS 架构

RESTful

将URL看作资源,URL 中用 名词 表示。各种操作通过不同的请求方式来识别。目的是 只看接口和请求方式就能知道这是干嘛的,比如
顺便知道一下,除了 GET,POST 外,还有 HEAD, PUT,PATCH,DELETE 等请求方式

GET /api/libraries/123/books?keyword=game&sort=price&limit=10&offset=0

含义就是:从一堆图书馆中,找到第 123 个图书馆的书,在书里查询所有关键词为 game ,以价格排序,从 0 开始的前 10 条数据


幂等 / 非幂等

请求

关于 meta 标签的 content="width=device-width"

目前总结的理解方式为:让你当前正在写的 html 的宽度等于设备宽度


Object.freeze() 冻结
var obj = {
    arr: [1, 2]
}

function freezen(obj) {
    Object.freeze(obj);
    Object.keys(obj).forEach(function(it, i) {
        if(typeof obj[it] === 'object') {
            freezen(obj[it])
        }
    })
}
freezen(obj)

类数组转数组

关于 var let 和 for 循环

map,foreach,$.each,each
# map
数组.map(function(值,下标,数组) {
    console.log(arguments)
})

# foreach
数组.foreach(function(值,下标,数组) {
    console.log(arguments)
})

# $.each(jQuery)
$.each(任何可遍历的对象, function(key, value) {
    console.log(arguments)
})

# each(jQuery)
DOM对象.each(function(key, value) {
    console.log(arguments)
})

箭头函数两句话攻略

事件委托
祖先.addEventListener('click', function(e){
    var target = e.target || e.srcElement;
    if (!!target && target.nodeName.toLowerCase()==='目标元素') {
        console.log(target.innerHTML)
    }
})

关于获取属性的 []. 的区别

Object.assign()

Object.defineProperty() / Object.defineProperties() 添加属性描述
Object.defineProperty(obj, "key", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: "static"
});
var obj = {};
Object.defineProperties(obj, {
  'property1': {
    value: true,
    writable: true
  },
  'property2': {
    value: 'Hello',
    writable: false
  }
  // etc. etc.
});

目标对象.hasOwnProperty()

Object.getPrototypeOf() / Object.setPrototypeOf()

Object.create()
# 创建新对象 clone,其原型为 obj 的原型,添加 newProp 属性
const obj = {
    'a': 'aa',
    222: 3123,
    'unenumerable': '不可枚举属性'
}

const clone = Object.create(Object.getPrototypeOf(obj), {
    'newProp': {
        value: '新值',
        enumerable: true
    }
});

Object.getOwnPropertyDescriptors(clone)
//  newProp:{value: undefined, writable: false, enumerable: true, configurable: false}
//  未指定的属性均为 false

也可以:

const obj = {
    'a': 'aa',
    222: 3123,
    'unenumerable': '不可枚举属性'
}

Object.defineProperty(obj, 'unenumerable', {
    enumerable: false
})

const clone = Object.create(Object.getPrototypeOf(obj),
    Object.getOwnPropertyDescriptors(obj)
);

Object.getOwnPropertyDescriptors(clone)

结果:

结果
这样就等同于 浅克隆 了一个 obj 对象 clone
Object.getOwnPropertyDescriptor()
const obj = {
    'a': 'aa',
    222: 3123
}
Object.getOwnPropertyDescriptor(obj, 'a')
//  {value: "aa", writable: true, enumerable: true, configurable: true}
const obj = {
    'a': 'aa',
    222: 3123,
    'unenumerable':'不可枚举'
}
Object.defineProperty(obj,'unenumerable',{enumerable:false})  // 设置为不可枚举
Object.getOwnPropertyDescriptors(obj)

/**
*   222: {value: 3123, writable: true, enumerable: true, configurable: true}
*   a: {value: "aa", writable: true, enumerable: true, configurable: true}
*   unenumerable: {value: "不可枚举", writable: true, enumerable: false, configurable: true}
**/

for ... in / for ... of / Object.keys / Object.values / Object.entries / Object.getOwnPropertyNames(obj)
名称 目标 类别
for...in... 自身及继承的属性名或索引 可枚举
Object.keys 自身 可枚举
Object.values 自身 可枚举
Object.entries 自身 可枚举
Object.getOwnPropertyNames(obj) 自身 可枚举 / 不可枚举
let arr = [3, 5, 7];
arr.foo = 'hello';
Array.prototype.baz='world';

for (let i in arr) {
  console.log(i); // "0", "1", "2", "foo", "baz"
}

for (let i of arr) {
  console.log(i); //  "3", "5", "7"
}

构造函数原型对象上的方法和属性是给实例调用的,构造函数本身无法调用

Set / Map 数据结构

外部脚本 <script> 标签及 defer,async
// module_test.js
let delay = +new Date();
console.log('外部脚本');
while(+new Date() - delay < 3000);

// index.html
<script src="js/module_test.js" type="text/javascript"></script>
<script type="text/javascript">
    console.log('本地脚本')
</script>

// 结果
外部脚本
---- 3s later ----
本地脚本

解决 jQuery 中 $ 冲突
var j = jQuery.noConflict();
// 基于 jQuery 的代码
j("div p").hide();
// 基于其他库的 $() 代码
$("content").style.display = 'none';

解决 jQuery 中 $ 原理

数组操作 / 字符串操作
名称 用法 返回
concat() arrayObject.concat(arrayX,arrayX,......,arrayX) 新数组
join() arrayObject.join(分隔符) 字符串
pop() arrayObject.pop() 最后一个元素
push() arrayObject.push(newelement1,newelement2,....,newelementX) 添加后的长度
reverse() arrayObject.reverse() 改变原数组
shift() arrayObject.shift() 第一个元素
slice() arrayObject.slice(start,end) 不改变原数组,返回新数组,支持负数
sort() arrayObject.sort(function) 改变原数组
splice() arrayObject.splice(index,howmany,item1,.....,itemX) 改变原数组
名称 描述 返回
charAt() 返回在指定位置的字符
concat() 连接字符串
indexOf() 检索字符串 布尔值
match() 找到一个或多个正则表达式的匹配 布尔值
replace() 替换与正则表达式匹配的子串 新字符串
search() 检索与正则表达式相匹配的值 第一个匹配子串的起始位置
slice() 提取字符串的片断,并在新的字符串中返回被提取的部分
split() 把字符串分割为字符串数组
substr() 从起始索引号提取字符串中 指定数目 的字符
substring() 提取字符串中两个 指定的索引号 之间的字符

回流(reflow)和重绘(repaint)

表格的 cellpadding 和 cellspacing
cellpadding 和 cellspacing
确切的判断一个对象 / 数组 / null 等的类型

=== 和 Object.is
区别 === Object
+0,-0 true false
NaN,NaN false true

原生 ajax
var xhr = new XMLHttpRequest();
xhr.open('get','getStar.php?starName='+name,true);
xhr.send();

xhr.onreadystatechange = function () {
   if (xhr.readyState==4 && xhr.status==200) {
    console.log(xhr.responseText);    //输入相应的内容
    }
}
var xhr = new XMLHttpRequest();
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.open('post', '02.post.php' ,true);
xhr.send('name=fox&age=18');
xhr.onreadystatechange = function () {
  if (xhr.readyState == 4 && xhr.status == 200) {
    console.log(xhr.responseText);
  } 
};

创建对象的几种模式
function createPerson(){
    var Child = new Object();
    Child.name = "欲泪成雪";
    Child.age = "20";
    return Child;
};

var x = createPerson();
function Person(){
    this.name = "欲泪成雪";
    this.age = "20";
    this.say = function(){
        alert("Hello!")
    }
};

function Fruit(){
    this.name = "水果";
    this.price = "13";
};


var x = new Person();
var y = new Fruit();

但这种模式每次实例化都会重新初始化属性 arr 和方法 say ,并且不同实例的 arrsay 并不是一个玩意

function Person() {
    this.name = "欲泪成雪";
    this.age = "20";
    this.arr = [0,1];
    this.say = function(){
        alert("Hello")
    }
};

var Tom = new Person();
var Jerry = new Person();

console.log(Tom.name === Jerry.name)    //  true
console.log(Tom.arr === Jerry.arr)      //  false
console.log(Tom.say === Jerry.say)      //  false
function Person(){};
Parent.prototype.name = "欲泪成雪";
Parent.prototype.age = "20";

var x = new Person();
function Person(){
  this.name = "欲泪成雪";
  this.age = 22;
};

Person.prototype.lev = function(){
  return this.name;
};

var x = new Person();

get / post
get post
URL中发送 消息主体
可缓存 不可缓存
可历史记录 不可保留为历史记录
可书签 不可书签
有长度限制 没有长度限制

关于 getElementsByTagName 和 querySelectorAll
<ul>
    <li>aaa</li>
    <li>ddd</li>
    <li>ccc</li>
</ul>

<script type="text/javascript">
    var ul = document.getElementsByTagName('ul')[0];
    var get_num = ul.getElementsByTagName("li");
    var query_num = ul.querySelectorAll('li');
    console.log(get_num.length, query_num.length)   //  3,3
    
    ul.appendChild(document.createElement("li"));   //  动态添加 li
    
    console.log(get_num.length, query_num.length)   //  4,3
</script>

HTML5 新特性

响应式布局
@media screen and (min-width:960px) and (max-width:1200px){
    body{background:yellow;}
}
<link rel="stylesheet" href="styleA.css" media="screen">  
<link rel="stylesheet" href="styleB.css" media="screen and (max-width: 800px)">  
<link rel="stylesheet" href="styleC.css" media="screen and (max-width: 600px)">

链式调用原理
function Foo(){}

Foo.prototype = {
    css:function(){
        console.log("设置css样式");
        return this;
    },
    show:function(){
        console.log("将元素显示");
        return this;
    },
    hide:function(){
        console.log("将元素隐藏");
    }
};

var foo = new Foo();
foo.css().css().show().hide();

flex
属性名 描述
flex-direction 主轴的方向
flex-wrap 如何换行
flex-flow 上两个的缩写
justify-content 项目在主轴的对齐方式
align-items 项目在交叉轴的对齐方式
属性名 描述
order 项目排列顺序,越小越靠前
flex-grow 项目放大比例
flex-shrink 项目缩小比例
flex-basis 属性定义了在分配多余空间之前,项目占据的主轴空间
flex 上三个的缩写
align-self 项目在交叉轴上的对齐方式

vue 虚拟 DOM
//虚拟dom,参数分别为标签名、属性对象、子DOM列表
var VElement = function(tagName, props, children) {
    //保证只能通过如下方式调用:new VElement
    if (!(this instanceof VElement)) {
        return new VElement(tagName, props, children);
    }

    //可以通过只传递tagName和children参数
    if (util.isArray(props)) {
        children = props;
        props = {};
    }

    //设置虚拟dom的相关属性
    this.tagName = tagName;
    this.props = props || {};
    this.children = children || [];
    this.key = props ? props.key : void 666;
    var count = 0;
    util.each(this.children, function(child, i) {
        if (child instanceof VElement) {
            count += child.count;
        } else {
            children[i] = '' + child;
        }
        count++;
    });
    this.count = count;
}
var vdom = velement('div', { 'id': 'container' }, [
    velement('h1', { style: 'color:red' }, ['simple virtual dom']),
    velement('p', ['hello world']),
    velement('ul', [velement('li', ['item #1']), velement('li', ['item #2'])]),
]);
<div id="container">
    <h1 style="color:red">simple virtual dom</h1>
    <p>hello world</p>
    <ul>
        <li>item #1</li>
        <li>item #2</li>
    </ul>   
</div>

Vue 的计算属性 computed 和监听属性 watch
<div id="demo">{{ fullName }}</div>

//  watch
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },
  watch: {
    firstName: function (val) {      //  firstName 和 lastName 都是 data 中已有的属性
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
})

//  computed
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {        // fullName 在 data 中并没有
      return this.firstName + ' ' + this.lastName
    }
  }
})

margin 塌陷

图片下的小空白
图片下小空白
BFC 是什么?

公有方法,私有方法,静态属性
function Foo(){
    //  公有方法
    this.name = function(){
        alert("Hello")
    }
    //  私有方法
    function age(){
        alert("World")
    }
}
# ES5
function Foo(){}
Foo.age = 12;               //  静态属性
Foo.getAge = function(){    //  静态方法
    console.log(this.age)
}
# ES6 
class Foo{
    static age(){      //  静态方法
        console.log(12)
    }
}
Foo.sex = 'boy'        //  静态属性(ES6 类内没有静态属性)

ES6 继承
class Son extends Dad {}

数据属性 / 访问器属性

实现一个深拷贝
function deepClone(obj) {
    var newObj = obj instanceof Array ? [] : {};
    //obj属于基本数据类型,直接返回obj
    if(typeof obj !== 'object') {
        return obj;
    } else {
    //obj属于数组或对象,遍历它们
        for(var i in obj) {
            newObj[i] = typeof obj[i] === 'object' ? deepClone(obj[i]):obj[i]; 
        }
    }
    return newObj;
}

取出嵌套数组的全部数值
//  常规版
let newArr = [];

function getArr(arr) {
    for(let i = 0; i < arr.length; i++) {
        if(arr[i] instanceof Array) {
            getArr(arr[i])
        } else {
            newArr.push(arr[i])
        }
    }
}

const arr = ["a", "b", "c", "d", ["aa", "bb"]];
getArr(arr);
console.log(newArr)
const arr = ["a", "b", "c", "d", ["aa", "bb"]];

function* tree(item) {
    if(Array.isArray(item)) {    // 如果是数组,就依次取出,再调用自己
        for(var i = 0; i < item.length; i++) {        
            yield* tree(item[i])
        }
    } else {    // 如果不是数组,直接输出
        yield item
    }
}

const it = tree(arr);
// 可以
for(var k of it) {
    console.log(k)
}

// 也可以
console.log([...it]) // ["a", "b", "c", "d", "aa", "bb"]

克隆对象及原型链
// 写法一
const clone1 = Object.assign(
  Object.create(Object.getPrototypeOf(obj)),
  obj
);

// 写法二
const clone2 = Object.create(
  Object.getPrototypeOf(obj),
  Object.getOwnPropertyDescriptors(obj)
)

几道面试题
function create(obj){
    obj.name = '粉粉';
    obj = new Object();
    obj.name = '娇娇';
}
var person = new Object();
create(person);
console.log(person.name);       // 粉粉
function create() {
    var obj;
    obj.name = '粉粉';
    obj = new Object();
    obj.name = '娇娇';
}
function create() {
    var obj = person;       //  此时 obj 和 person 指向一块内存
    obj.name = '粉粉';      //  为同一块内存添加属性,这是 obj 和 person 共有的属性
    obj = new Object();     //  然后让 obj 指向另一块内存
    obj.name = '娇娇';      //  obj 已经指向另一块内存,再为 obj 添加属性当然跟 person 无关了
}

var a = '小旭';
(function(){
    console.log(typeof a)       //  undefined
    console.log(typeof fun1)    //  function
    console.log(typeof fun2)    //  undefined
    var a = '旭旭';
    function fun1(){};
    var fun2 = function(){}
    console.log(typeof a);      // string
    console.log(typeof fun1);   //  function
    console.log(typeof fun2);   //  function
})(window)
var a = '小旭';
(function(){
    var a;
    function fun1(){};
    var fun2;
    console.log(typeof a)       //  undefined
    console.log(typeof fun1)    //  function
    console.log(typeof fun2)    //  undefined
    a = '旭旭';
    fun2 = function(){}
    console.log(typeof a);      //  string
    console.log(typeof fun1);   //  function
    console.log(typeof fun2);   //  function
})(window)

var foo = {
    bar:function(){
        return this.baz;
    },
    baz:1
};
(function(){
    console.log(arguments[0]());            //  undefined
    console.log(foo.bar());                 //  1
    console.log(arguments[0].call(foo));    //  1
})(foo.bar)

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();              //  1
new Foo.getName();      //  2
new Foo().getName();    //  3
var getName;
function Foo(){
    getName = function(){console.log(1);}
    return this;
}
function getName(){console.log(5);}
Foo.getName = function(){console.log(2);}
Foo.prototype.getName = function(){console.log(3);}
getName = function(){console.log(4);}
Foo.getName();          //  2
getName();              //  4
Foo().getName();        //  1
getName();              //  1
new Foo.getName();      //  2
new Foo().getName();    //  3

var fullName = 'language';
var obj = {
    fullName:'javascript',
    prop:{
        getFullName:function(){
            return this.fullName;
        }
    }
}
console.log(obj.prop.getFullName());        //  undefined
var test = obj.prop.getFullName;
console.log(test());                        //  language
var fullName = 'language';
var obj = {
    fullName:'javascript',
    prop:{
        getFullName:function(){
            return this.fullName;
        }
    }
}
console.log(obj.prop.getFullName());        //  undefined
var test = function(){
    return this.fullName
}
console.log(test());        

var name = 'Jerry';
var Tom = {
    name:'Tom',
    show:function(){
        console.log(this.name)
    },
    wait:function(){
        var fun = this.show;
        fun();
    }
};
Tom.wait();     //  Jerry
var name = 'Jerry';
var Tom = {
    name:'Tom',
    show:function(){
        console.log(this.name)
    },
    wait:function(){
        function fun(){
            console.log(this.name)    //  这里的 this 指向 window
        }
        fun();
    }
};
Tom.wait();     //  Jerry

setTimeout(function() {      //  定时器1
    var end = +new Date();
    console.log(end - start)
}, 1000)
            
setTimeout(function() {      //  定时器2
    console.log('哈哈哈')
}, 0)

console.time('circle')

let delay = +new Date();
while(+new Date() - delay < 1500);

console.timeEnd('circle')

var start = +new Date();
结果
var value = 1;

function foo() {
    console.log(value);
}

function bar() {
    var value = 2;
    foo();
}

bar();    //  1

实现 bind 方法

bind / call 的区别
var obj = {
    name : 24
}

function fn(){
    console.log(this.name);
}
            
fn.bind(obj)()      //  24
fn.call(obj)        //  24

new 操作符做了什么

1.创建一个新对象
2.将构造函数的 this 指向新对象
3.执行构造函数
4.返回新对象

function Foo(){
    this.name = '我亦飘零';
};

var obj = {}; 
obj.__proto__ = Foo.prototype;
Foo.call(obj)

函数柯里化

常见的浏览器兼容问题 js / css
* png24位的图片在iE6浏览器上出现背景,解决方案是做成PNG8.也可以引用一段脚本处理.

* 浏览器默认的margin和padding不同。解决方案是加一个全局的*{margin:0;padding:0;}来统一。

* IE6双边距bug:块属性标签float后,又有横行的margin情况下,在ie6显示margin比设置的大。 

* 浮动ie产生的双倍距离(IE6双边距问题:在IE6下,如果对元素设置了浮动,同时又设置了margin-left或margin-right,margin值会加倍。)
  #box{ float:left; width:10px; margin:0 0 0 100px;} 

 这种情况之下IE会产生20px的距离,解决方案是在float的标签样式控制中加入 ——_display:inline;将其转化为行内属性。(_这个符号只有ie6会识别)

*  渐进识别的方式,从总体中逐渐排除局部。 

  首先,巧妙的使用“\9”这一标记,将IE游览器从所有情况中分离出来。 
  接着,再次使用“+”将IE8和IE7、IE6分离开来,这样IE8已经独立识别。

  css
      .bb{
       background-color:#f1ee18;/*所有识别*/
      .background-color:#00deff\9; /*IE6、7、8识别*/
      +background-color:#a200ff;/*IE6、7识别*/
      _background-color:#1e0bd1;/*IE6识别*/ 
      } 

*  IE下,可以使用获取常规属性的方法来获取自定义属性,
   也可以使用getAttribute()获取自定义属性;
   Firefox下,只能使用getAttribute()获取自定义属性. 
   解决方法:统一通过getAttribute()获取自定义属性.

* IE下,event对象有x,y属性,但是没有pageX,pageY属性; 
  Firefox下,event对象有pageX,pageY属性,但是没有x,y属性.

* 解决方法:(条件注释)缺点是在IE浏览器下可能会增加额外的HTTP请求数。

* Chrome 中文界面下默认会将小于 12px 的文本强制按照 12px 显示, 
  可通过加入 CSS 属性 -webkit-text-size-adjust: none; 解决.

* 超链接访问过后hover样式就不出现了 被点击访问过的超链接样式不在具有hover和active了解决方法是改变CSS属性的排列顺序:
L-V-H-A :  a:link {} a:visited {} a:hover {} a:active {}

* 怪异模式问题:漏写DTD声明,Firefox仍然会按照标准模式来解析网页,但在IE中会触发怪异模式。为避免怪异模式给我们带来不必要的麻烦,最好养成书写DTD声明的好习惯。现在可以使用[html5](http://www.w3.org/TR/html5/single-page.html)推荐的写法:`<doctype html>`

* 上下margin重合问题
ie和ff都存在,相邻的两个div的margin-left和margin-right不会重合,但是margin-top和margin-bottom却会发生重合。
解决方法,养成良好的代码编写习惯,同时采用margin-top或者同时采用margin-bottom。
* ie6对png图片格式支持不好(引用一段脚本处理)

常用的自适应解决方案

cookie,localStorage,sessionStorage 差异及使用场景

发布 - 订阅模式

多行文本垂直居中
// css
div {
    height:500px;
    width:300px;
    border:1px solid red;
    font-size: 30px;
    display: table;
}
            
p {
    display: table-cell;
    vertical-align: middle;
}

//  html
<div>
    <p id="">
        啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦
    </p>
</div>

未知大小图片水平垂直居中
a{display:inline-block; width:1.2em; font-size:128px; text-align:center; vertical-align:middle;}
img{vertical-align:middle;}

溢出显示省略号
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;

伪类 / 伪元素
属性 描述 CSS
:active 向被激活的元素添加样式。 1
:focus 向拥有键盘输入焦点的元素添加样式。 2
:hover 当鼠标悬浮在元素上方时,向元素添加样式。 1
:link 向未被访问的链接添加样式。 1
:visited 向已被访问的链接添加样式。 1
:first-child 向元素的第一个子元素添加样式。 2
:lang 向带有指定 lang 属性的元素添加样式。 2
属性 描述 CSS
:first-letter 向文本的第一个字母添加特殊样式。 1
:first-line 向文本的首行添加特殊样式。 1
:before 在元素之前添加内容。 2
:after 在元素之后添加内容。 2

去掉 ul 前面的点
list-style:none

引用的阿里矢量图为什么能改颜色

BOM
BOM & DOM
关于 Vue 双向绑定 和 虚拟DOM

几个常用的正则

/^1[34578][0-9]{9}$/
/^\d{4}[/-]\d{2}[/-]\d{2}$/
//  1983-12-27
//  1983/12/16
/^[a-zA-Z0-9_][a-zA-Z0-9_-]*@[a-zA-Z0-9]+(\.[a-zA-Z]+)+$/
/((a)|(b{1,2}))abc/g

Vue 中 data 为什么使用 return


Vue 中使用 data 中的一个数组属性渲染页面,修改数组属性时,页面是否响应


oninput / onchange


Vue 组件通信

上一篇 下一篇

猜你喜欢

热点阅读