前端面试常见知识点总结
HTML
- 对html5的理解,web语义话,SEO
- 页面加载过程
- 新增API,本地存储,Canvas
CSS
- 经典圣杯布局
- CSS3 transition transform animate
- w3c盒模型和IE盒模型,box-sizing属性
- 居中
- 浮动,position
- 块级元素和行内元素
- 块级元素: div,h1,p,ul,ol,li
- 行内元素: a,span,img,em, input, label
- 区别:
- 块级元素占一行且宽度默认占满父元素,行内元素可以排在同一行;
- 块级元素可以设置宽高,当仍然占一行;行内元素设置宽高无效;
- 块级元素可以设置margin和padding属性,行内元素可以设置水平方向的margin和padding属性,竖直方向无效
- BFC
- 优先级
- less与sass
- background-*系列属性
JS
-
原型
-
对象
工厂模式
function createPerson(name, age, job) { var o = new Object(); o.name = this.name; o.age = this.age; o.job = this.job; o.sayName = function () { alert(this.name); }; return o; } var person1=createPerson('lin',29,'programmer'); var person2=createPerson('li',30,'teacher');
解决创建多个相似对象的问题,没解决对象识别的问题
构造函数模式
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = function () { alert(this.name); }; } var person1 = new Person('lin', 29, 'programmer'); var person2 = new Person('li', 30, 'teacher');
调用构造函数4个步骤:
- 创建一个对象;
- 将构造函数的作用域赋给新对象;(this指向新对象)
- 执行构造函数中的代码
- 返回新对象
主要问题:每个方法都要在每个实例上重新创建一遍,不同实例上的同名函数是不想等的。
原型模式
function Person() {} Person.prototype.name = 'lin'; Person.prototype.age = 29; Person.prototype.job = 'programmer'; Person.prototype.sayName = function () { alert(this.name); } var person1 = new Person();
- 创建函数会创建一个prototype属性,指向函数的原型对象
- Person的每个实例内部包含一个属性,指向Person.prototype
- 读取某个对象的某个属性,搜索先从对象实例本身开始,没有再搜索指针指向的原型对象
- 在实例对象上添加或修改同名属性,会屏蔽原型对象属性,但对于包含引用类型值的属性,会直接修改原型对象上的属性
- 对象字面量重写原型对象,其constructor属性会指向Object构造函数,切断现有原型与之前存在的实例对象之间的联系(即之前生成的的实例无法访问现有原型对象上的属性与方法)
function Person() { } var friend = new Person(); Person.prototype = { constructor: Person, name: 'lin', age: 29, sayName: function () { alert(this.name); } }; friend.sayName(); //error
原型模式问题:省略了构造函数参数传递,结果所有的实例在默认情况下都取得相同的属性值;实例改变包含引用类型值的属性时,会改变原型对象上的相应属性值,其他实例的相应属性值也会改变;
组合使用构造和原型模式
function Person(name.age,job) { this.name=name; this.age=age; this.job=job; this.friends=['lucy','lily'] } Person.prototype={ constructor:Person, sayName:function(){ alert(this.name); } } var person1=new Person('lin',29,'programmer');
动态原型模式
function Person(name.age,job) { this.name=name; this.age=age; this.job=job; if(typeof this.sayName !='function') { Person.prototype.sayName = function() { alert(this.name); } } } var person1=new Person('lin',29,'programmer');
注意不能使用对象字面量重写原型
寄生构造函数模式
稳妥构造函数模式
-
继承
原型链
每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象内部的指针;让原型对象等于另一个构造函数的实例,此时原型对象就有指向另一个原型的指针,另一个原型也包含着指向另一个构造函数的指针,以此类推构成实例与原型的链条。
function One() { this.oneprototype = true; } One.prototype.getOneValue = function () { return this.oneprototype; } function Two() { this.twoprototype = false; } Two.prototype = new One(); Two.prototype.getTwoValue = function () { return this.twoprototype; } var Three = new Two(); alert(Three.getOneValue()); //true
通过重写Two的原型对象,继承One,原本存在One的实例中的属性和方法,现在也存在Two.prototype中,新原型中还有一个指向One原型的指针。最终时Three指向Two的原型,Two的原型指向One的原型。oneprototype在Two.prototype中,但getOneValue()方法仍在One.prototype上。
给子类原型添加或则覆盖某个方法,添加方法的代码放在原型重写代码的后面。
原型链继承的问题:超类实例中属性的值为引用类型值时,子类的实例修改该属性,其他子类实例中也会相应改变。
function One() { this.color = ['red', 'blue']; } function Two() { } Two.prototype = new One(); var three = new Two(); three.color.push('black'); alert(three.color); // 'red,blue,black' var four = new Two(); alert(four.color); //'red,blue,black' var five = new One(); alert(five.color); //'red,blue'
借用构造函数
function One() { this.color = ['red', 'blue']; } function Two() { One.call(this); this.age=29; } var three = new Two(); three.color.push('black'); alert(three.color); // 'red,blue,black' alert(three.age) //29 var four = new new Two(); alert(four.color); //'red,blue'
问题:无法避免构造函数模式存在的问题。
组合继承
function Ono(name) { this.name = name; this.num = [1, 2, 3]; } One.prototype.sayName = function () { alert(this.name); } function Two(name, age) { One.call(this, name); this.age = age; } Two.prototype = new One(); Two.prototype.constructor = One; Two.prototype.sayAge = function () { alert(this.age); } var three = new Two('lin', 29); three.num.push(4); alert(this.num); //1,2,3,4 three.sayAge(); //29 three.sayName(); //'lin' var four = new Two('li', 30); alert(four.num); //1,2,3 four.sayAge(); //30 four.sayName(); //'li'
通过原型链对原型属性和方法继承,通过借用构造函数对实例属性继承。
问题:调用两次超类的构造函数,一次是创建子类型原型的时候,另一次是在子类型构造函数内部
原型式继承
function object(o) { function F(){}; F.prototype=o; return new F(); } ES5 Object.create() var person={ name:'lin', num:[1,2,3]; } var person2=Object.create(person); person2.name='li'; person.num.push(4); alert(person.num); //1,2,3,4
寄生式继承
function createAnother(original) { var clone = abject(original); clone.sayHi = function () { alert('hi'); } return clone; } var person = { name: 'lin', num: [1, 2, 3]; } var person2 = createAnother(person); person2.sayHi(); //'hi';
寄生组合继承
function inheritPrototype(Two,One) { var prototype = Object(One.prototype); prototype.constructor=Two; Two.prototype=prototype; } function One(name) { this.name=name; this.num=[1,2,3]; } One.prototype.sayName=function(){ alert(this.name); } function Two(name,age) { One.call(this,name); this.age=age; } inheritPrototype(Two,One); Two.prototype.sayAge=function() { alert(this.age); }
通过借用构造函数来继承实例属性,通过原型链的混成形式继承原型方法和属性。不必为了指定子类的原型而调用超类型构造函数,使用寄生式继承来继承超类型的原型,在将结果指定给子类型的原型
-
变量 作用域
变量
变量包含两种不同数据类型值,基本类型值和引用类型值。
基本类型值:简单的数据段;
number,string,boolean,null,undefined引用类型值:由多个值构成的对象;保存在堆内存中,复制对象的某个变量时实际上是操作对象的引用,但在为对象添加属性时,操作的是实际对象。
执行环境
定义变量或函数有权访问的其他数据;
环境中定义的所有变量和函数都保存在一个变量对象中;
作用域链
保证对执行环境有权访问的变量和函数的有序访问;
作用域链的前端,是当前执行代码所在环境的变量对象,接着是来自包含环境的变量对象,以此类推,一直延续到全局执行环境,全局执行环境的变量对象是作用域链的最后一个对象。
内部环境通过作用域链访问外部环境。
-
闭包
闭包是指有权访问另一个函数作用中的变量的函数,常见的创建方式,在一个函数内部创建另一个函数;
闭包的作用包含外部函数的变量对象;
闭包只能取得包含函数中任何变量的最后值
function fun() { var result = new Array(); for (var i = 1; i < 10; i++) { result[i] = function () { return i; }; } return result; } function fun() { var result = new Array(); for (var i = 1; i < 10; i++) { result[i] = function (num) { return function(){ return num; }; }(i); } return result; }
在匿名函数中定义的任何变量会在执行结束被销毁,从而限制像全局作用中添加更多的变量和函数
利用闭包的作用域链访问外部函数的变量,用于创建访问私有变量的公有方法
模块模式:为单例(只有一个实例的对象,通过对象字面量创建)创建私有变量和特权方法(有权访问私有变量和函数)
闭包的作用,通过作用域可以提供访问私有变量和函数的接口
-
函数调用方式
- 方法调用
- 函数调用
- 构造器调用
- apply调用
-
JSON
-
高阶函数
-
JSONP跨域iframe通信
-
Ajax
-
原生DOM操作,逆序DOM节点
-
事件捕获,冒泡,代理
事件流
* 手指放在同心圆的圆心,手指向的不是一个圆,而是所有的圆;即单击按钮的同时,也单击了按钮的容器元素,也单击了整个页面。
* 事件流描述的是从页面中接受事件的顺序。
* IE的事件流是事件冒泡,即事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点:div > body >html > document
* Netscape事件流是事件捕获,与IE相反;
* DOM 事件流包括三个阶段:事件捕获阶段,处于目标阶段和事件冒泡阶段事件处理
- DOM2级事件处理程序
var btn = document.getElementById('myBtn'); btn.addEventListener('click',handle,fasle); //fasle表示事件在冒泡阶段触发 btn.removeEventListener('click',handle,false) handle 如果为匿名函数则取消无效
- IE事件处理程序
var btn = document.getElementById('myBtn'); btn.attachEvent('onclick',handle); btn.detachEvent('onclick',handle) 只有IE和Opera支持
- 跨浏览器事件处理程序
var EventUtil = { addHandler: function (element,type,handler) { if (element.addEventListener) { element.addEventListener (type,handler,false); } else { element.attachEvent ('on'+type,handler); } else { element['on'+type] = handler; } }, removeHandler:function (element,type,handler) { if(element.removeEventListener) { element.removeEventListener (type,handler,false); } else { element.detachEvent ('on' + type,handle); } else { element['on'+type] = null; } } } var btn = document.getElementById('mybtn'); EventUtil.addHandler(btn,'click',handler); EventUtil.removeHandler(btn,'click',handler);
事件对象
-
DOM中的事件对象:event
-
this = currentTarget :事件处理程序存在对象;
-
target:事件的目标(如单击的按钮);
-
阻止特定的默认行为:event.preventDefault()
-
阻止事件冒泡:stopPropagation()
-
-
IE中的事件对象:window.event
- srcElemnt事件的目标
- 阻止特定的默认行为:window.event.returnvalue =false
- 阻止事件冒泡:window.event.cancelBubble()
var EventUtil = { addHandler: function (element, type, handler) { }, getEvent: function (event) { return event ? event : window.event; }, getTarget: function (event) { return event.target || event.srcElement; }, preventDefault: function (event) { if (event.preventDefault) { event.preventDefault(); } else { event.returnvalue = false; } }, stopPropagation: function (event) { if (event.stopPropagation) { event.stopPropagation(); } else { event.cancelBubble = true; } } }
事件委托
- 事件处理程序数量关系到页面性能,因为每个函数都是对象,会占用内存
- 利用事件冒泡,只指定一个事件处理程序,管理某一类型的所有事件;
- 为document对象添加一个事件处理程序,处理页面上发生的某种特点类型的事件:document对象访问快,只添加一个事件处理程序所需DOM的引用少,用时短,占内存空间小
-
Array常用函数
检测数组
if(Array.isArray(value)) { }
转换方法
var colors =['red','blue','green']; alert(colors.toString()); //red,blue,green alert(colors.join('-')); //red-blue-green
栈方法
- last-in-first-out
- push():将任意数量的参数,逐个添加到数组末尾,并返回修改后数组的长度;
- pop():从数组末尾移除最后一项,然后返回移除的项。
var colors = new Array(); var count = colors.push('red','blue'); alert(count.length); //2 count.push('black'); alert(count.length); //3 var item = count.pop(); alert(item); //'black' alert(count.length); //2
队列方法
- first-in-first-out
- shift():移除数组的第一项并返回该项,同时将数组长度减1;
- unshift():在数组前端添加任意个项,并返回新数组的长度。
var num = [1,2,3]; num.push(4); var item = num.shift(); alert(item); //1 alert(num.length) //3 num.unshift(5); alert(num.length); //4
重排序
- reverse():反转数组项的顺序
- sort():调用每个数组项的toString()转型方法,然后比较得到的字符串,确定如何排序
function compare(value1, value2) { if (value1 < value 2) { return -1; } else if (value1 > value2) { return 1; } else { return 0; } } var values = [0,1,4,2,10]; values.sort(compare); alert(values); //0,1,2,4,10
操作方法
- concat():创建当前数组的副本,将接收到的参数添加到副本的末尾,返回新构建的数组;
- slice():参数为起始和结束项位置,返回起始和结束位置之间的项不包括结束位置,没有结束位置,则到末尾,不影响原始数组;
- splice():参数为删除项的起始位置,项数,插入的项。返回一个数组,包含从原始数组中删除的项(如没有删除则返回一个空数组);
var colors = ['red','green']; var colors2 = colors.concat('yellow',['blue','purple']); alert(colors2); //red,green,yellow,blue,purple var colors3 = colors2.slice(2); //yellow,blue,purple var colors4 = colors2.slice(1,4); //green,yellow,blue var removed = colors2.splice(0,2); //red,green alert(colors2); //yellow,blue,purpel var removed2 = colors2.splice(1,0,'red','green'); //空数组 alert(colors2); //yellow,red,green,blue,purple
位置方法
- indexOf():参数为要查找的项和起点位置索引,返回查找项所谓位置索引,为找到返回-1
- lastIndexOf()
var num = [1,2,34,5,4,2,6]; alert(num.indexOf(2)); //1 alert(num.indexOf(2,3); //5
迭代方法
- every():数组中每一项运行给定函数,每一项都返回true,则返回true;
- some(): ...,任意项返回true,则返回true;
- filter(): ...,返回该函数会返回true的项组成的数组;
- forEach(): ...,没有返回值;
- map(): ...,返回每次函数调用的结果组成的函数。
var nums = [1,2,3,4,5]; var everyResult = nums.every(function(item,index,array) { return (item > 2); }) alert(everyResult); //false var someResult = nums.some(function(item,index,array) { return (item > 2); }) alert(someResult); //true var filterResult = nums.filter(function(item,index,array) { return (item > 2); }) alert(filterResult); //[3,4,5] var mapResult = nums.map(function(item,index,array) { return (item * 2); }) alert(mapResult); //[2,4,6,8,10];
归并方法
- reduce():四个参数,前一个值,当前值,项的索引,数组对象
var values = [1,2,3,4,5]; var sum = values.reduce(function(prev,cur,index,array) { return prev + cur }) alert(sum); //15
-
string常用函数
字符方法
var stringvalue = 'Hello, world!'; alert(stringvalue.charAt(2))
字符操作方法
- concat(): same as Array;
- slice(): same as Array;
- substring: same as slice;
- substr: 第二个参数表示返回的个数
字符串位置方法
- indexOf()
var stringValue = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit'; var positions = []; var pos = stringValue.indexOf('e'); while(pos > -1) { positions.push(pos); pos = stringValue.indexOf('e',pos + 1); } alert(positions); //[3,24,32,35,52]
trim()
创建一个字符串的副本,删除前置及后缀的所有空格,返回结果;
字符串大小写转换
- toLowerCase()
- toUpperCase()
- toLocalLowerCase()
- toLocalUpperCase()
字符串匹配方法
var text = 'cat, bat, sat, fat'; var result = text.replace('at','ond); //'cond, bat, sat, fat' result = text.replace(/at/g,'ond'); //'cond, bond, sond, fond' result.split(','); //['cond','bond','sond','fond']
-
ES5+ES6
-
框架
-
手动实现MVC
-
衍生部分
-
HTTP1/2理解,状态码,优化,缓存控制
-
页面加载过程
- 输入URL
- 解析URL获取协议,主机,端口,path,组装http请求报文,获取主机ip地址;
- 打开socket与目标ip地址建立TCP链接:浏览器与远程
Web
服务器通过TCP
三次握手协商来建立一个TCP/IP
连接。该握手包括一个同步报文,一个同步-应答报文和一个应答报文,这三个报文在 浏览器和服务器之间传递。该握手首先由客户端尝试建立起通信,而后服务器应答并接受客户端的请求,最后由客户端发出该请求已经被接受的报文。 - 发送HTTP请求,服务器接受,检查缓存,返回对应状态码
- 浏览器接受响应,关闭TCP,检查响应状态码,进行缓存,解码
- 解析HTML文档,构建DOM树,下载资源,构建CSSOM树,执行js脚本
-
TCP三次握手,四次挥手
-
XSS与CSRF
-
学习经历和方法
-
性能优化
-
单元测试
-
React+Reduct
-
模块机制 AMD CMD commonjs
-
webpack