JavaScript前端面试
考查点:
- 基层工程师——基础知识
- 高级工程师——项目经验
- 架构师——解决方案
- 技术没有好坏,关键看使用场景
面试战术
- 拿到一个面试题,你的第一时间看到的是什么?(考点)
- 如何看待网上永远看不完的题海(不变应万变)
- 如何对待遇到的面试题?(题目到知识再到题目)
JS typeof 运算符
- undefined
- string
- number
- boolean
- object
- function
==运算符和===运算符
==会发生强制类型转换;===则不会。比如obj.a==null其实就相当于obj.a===null || obj.a===undefined,==属于一种简写形式,是JQuery推荐写法,其他情况一般使用===
如何理解JSON
在js中JSON不仅仅是一种数据格式,同时也是也是一个js对象。
构造函数
function Person( name){
this.name =name;
}
var p1=new Person('John');
注意:构造函数默认首字母大写
- var a={} 等价于 var a = new Object()
- var a=[] 等价于 var a = new Array();
- function Foo(){……} 等价于 var Foo = new Function(……);
- 使用instanceof判断一个函数是否是另一变量的构造函数
原型规则
1.所有引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(null除外)
2.所有引用类型(数组、对象、函数),都有一个proto(隐式原型)属性,属性值是普通对象
3.所有的函数,都有一个prototype(显式类型)属性,属性值也是一个普通对象。
4.所有的引用类型(数组、对象、函数),proto属性值指向它的构造函数的“prototype”属性值
var arr=[1,2,3];
arr._proto_===Array.prototype
5.当试图得到一个对象的属性时,如何这个对象本身没有这个属性,那么就会去它的proto(即它的prototype)中寻找。
instanceof判断逻辑
f instanceof Foo,f的proto一层层向上找,能否找到Foo.prototype
new一个js对象的过程
- 首先有一个构造函数创建一个新对象
- this指向这个对象
- 执行代码,即对this赋值
- 返回this(默认都没有写,其实系统已经实现了)
原型和原型链实例
function Elem(id){
this.elem = document.getElementsByClassName(id);
}
Elem.prototype.html=function(val){
var elem = this.elem;
if(val){
elem.innerHTML(val);
return this;
}else{
return elem.innerHTML;
}
}
Elem.prototype.on=function(type,fn){
var elem = this.elem;
elem.addEventListener(type,fn);
}
var div = new Elem('search-body');
div.html("<p>hello</p>").on('click',function(){
alert('click');
});
this
- this要在执行时才能确认,定义时无法确认。
使用场景: - 作为构造函数执行
function Foo(name){
this.name=name;
}
var foo =new Foo("tom");
- 作为对象属性执行
var obj = {
name="tom"
print:function(){
alert(this.name);
}
}
obj.print();
- 作为一个普通函数执行
function fn(){
alert(this);//window
}
fn();
- call、apply和bind
function fn(){
alert(this);//window
}
fn();
function fn(name){
alert(this); //[Object object]
}
fn.call({age:22},"tom");
>var fn =function (name){
alert(this);
}.bind({age:22});
fn("tom");
作用域
-
js没有块级作用域,有函数作用域和全局作用域
image.png -
作用域链
image.png - 一个函数的父级作用域是定义时的作用域,而不是运行时。
闭包
- 函数作为返回值
- 函数作为参数来传递
实际开发中的闭包的应用 - 用于封装变量,收敛权限
前端使用异步场景
- 定时任务:setTimeout,setInterval
- 网络请求:ajax请求,
- 动态<img/>加载
- 事件绑定
- 共同点:都需要等待
同步和异步的区别
- 同步会阻塞代码,而异步不会
- alert是同步,setTimeout是异步
其他API
获取2017-07-01格式的日期
function formatDate(dt){
if(!dt){
dt=new Date();
}
var year =dt.getFullYear();
var month=dt.getMonth()+1;
var date=dt.getDate();
if(month<10)
month="0"+month;
if(date<10)
date="0"+date;
return (year+"-"+month+"-"+date);
}
var dt=new Date();
var formatDate= formatDate(dt);
console.log(formatDate);
写一个能遍历对象和数组的forEach函数
function forEach(obj,fn){
if(obj instanceof Array){
obj.forEach(function(item,index){
fn(index,item);
});
}else{
for(key in obj){
fn(key,obj[key]);
}
}
}
var arr=[1,2,3];
forEach(arr,function(index,item){
console.log(index,item);
});
var obj ={x:1,y:2};
forEach(obj,function(key,value){
console.log(key,value);
});
DOM节点的Attribute和property有何区别
- property只是一个JS对象的属性的修改和获取
- Attribute是对HTML标签属性的修改和获取
如何检测浏览器类型
function checkBrower(){
var agent = navigator.userAgent;
if(agent.indexOf("chrome")>-1)
return "Chrome";
if(agent.indexOf("Firefox")>-1)
return "Firefox";
if (agent.indexOf("Safari")>-1)
return "Safari";
if(agent.indexOf("compatible")>-1 && agent.indexOf("MSIE")>-1)
return "IE";
}
通用事件绑定
function bindEvent(elem,type,fn){
elem.addEventListener(type,fn);
}
var a = document.getElementById("");
bindEvent(a,'click',function(e){
e.preventDefault();
alert("click");
});
事件代理
div1.addEventListener('click',function(e){
var target=e.target;
if(target.nodeName=='a')
alert(target.innerHTML);
})
代理的好处
* 代码简洁
* 减少浏览器内存的使用
通用事件绑定事件函数
function bindEvent(elem,type,selector,fn){
if(fn == null){
fn= selector;
selector =null;
}
elem.addEventListener(type,function(e){
var target;
if(selector){ //使用代理
target=e.target;
if(target.matches(selector)){
fn.call(target,e);
}
} else{ //不使用代理
fn(e);
}
})
}
手动编写一个ajax
var xmlhttp=null;//声明一个变量,用来实例化XMLHttpRequest对象
if (window.XMLHttpRequest)
{
xmlhttp=new XMLHttpRequest();// 新版本的浏览器可以直接创建XMLHttpRequest对象
}
else if (window.ActiveXObject)
{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");// IE5或IE6没有XMLHttpRequest对象,而是用的ActiveXObject对象
}
if (xmlhttp!=null)
{
xmlhttp.onreadystatechange=state_Change;//指定响应函数为state_Change
xmlhttp.open("GET","/example/xdom/note.xml",true);//指定请求,这里要访问在/example/xdom路径下的note.xml文件,true代表的使用的是异步请求
xmlhttp.send(null);//发送请求
}
else
{
alert("Your browser does not support XMLHTTP.");
}
//创建具体的响应函数state_Change
function state_Change()
{
if (xmlhttp.readyState==4)
{
if (xmlhttp.status==200)
{
// 这里应该是函数具体的逻辑
}
else
{
alert("Problem retrieving XML data");
}
}
}
跨域
- 浏览器有同源策略,不允许ajax访问其他域接口。
- 跨域条件:协议、域名、端口,有一个不同就算跨域。
- 三个标签无跨域障碍
1.<img>用于打点统计,统计网站可能来自其他域。
2.<link><script>可以使用CDN、CDN也是其他域。
3.<script>可以用于JSONP
- 所有的跨域请求都必须经过信息提供方允许
JSOP实现原理
- 加载 http://www.myname.com/index.html
- 不一定服务器端真正有一个index.html
- 服务器可以根据请求,动态生成一个文件,返回
- 同理于<script src="http://www.mycode.api/js>
jsop原理
服务器端设置http header解决跨域
描述一个cookie,sessionStorage和localStorage的区别
cookie
- 本身用户客户端和服务器端通信
- 但是它有本地存储的功能,于是被“借用了”
- 使用document.cookie=……
缺点 - 存储量太小,只有4KB
- 所有http请求都带着,会影响获取资源的效率
- API简单,需要封装才能用 document.cookie=…
locationStorage和sessionStorage - HTML5专为存储而设计,最大容量为5M
- API简单易用
- localStorage.setItem(key,value);
- localStorage.getItem(key);
- localStorage为持久存储,session为回话存储
区别:
- 容量
- 是否会携带到ajax中
- API易用性
多人协作常用git命令
- git.add .
- git checkout xxx 还原之前
- git commit -m "xxx"
- git push origin master
- git pull origin master
- git branch 查看当前分支
- git branch xxx(创建分支)/git checkout -b xxx(创建并切换分支) / git checkout xxx 切换分支
- git merge xxx 把xxx分支合并到当前分支(合并前先pull最新的代码,合并后还要push上去)
- git diff 查看变化
模块化
AMD
- require.js http://www.ruanyifeng.com/blog/2012/11/require_js.html
- 全局define函数
- 全局require函数
-
依赖的JS会自动、异步加载
image.png
CommonJS http://www.ruanyifeng.com/blog/2012/10/asynchronous_module_definition.html
- nodejs模块化规范,现被大量用于前端
- 前端开发依赖的插件和库,都可以从npm中获取
- 构建工具的高度自动化,使得使用npm的成本非常低
- CommonJS不会异步加载JS,而是同步一次性加载
AMD和CommonJS的使用场景
- 需要异步加载JS,使用AMD
- 使用了npm之后建议使用CommonJS
构建工具webpack
-
npm init (生成package.json文件)
-
**npm install webpack --save-dev **(简写:npm i webpack --save-dev)
"devDependencies": { //用于开发环境的依赖
"webpack": "^3.3.0"
},
npm install jquery--save
"dependencies": { //用于正式上线时的依赖
"jquery": "^3.2.1"
} -
卸载npm uninstall jquery--save
-
webpack.config.js配置
var path = require('path')
var webpack = require('webpack')
module.exports = {
context: path.resolve(__dirname,'./src'),
entry:{
app:'./app.js'
},
output: {
path: path.resolve(__dirname,'./dist'),
filename: 'bundle.js'
}
}
-
配置package.json文件中的
image.png -
执行 npm start,生成bundle.js文件
image.png
上线流程要点
- 将测试完成代码提交到git版本库的master分支
- 经当前服务器的代码全部打包并记录版本号,备份
- 将master分支的代码提交覆盖到线上服务器,生成新版本号
回滚流程要点
- 将当前服务器的代码打包并记录版本号,备份
- 将备份的上一个版本号解压,覆盖到线上服务器,并生成新的版本号。
页面加载资源的过程
- 浏览器根据DNS服务器得到域名的IP地址
- 向这个IP的机器发送http请求
- 服务器收到、处理并返回http请求
- 浏览器得到返回内容
浏览器渲染页面的过程
- 根据HTML生成DOM Tree
- 根据CSS生成CSSOM
- 将DOM和CSSOM整合形成RenderTree
- 根据RenderTree开始渲染和展示
- 遇到<script>时,会执行并阻塞渲染,所以放在</body>上面。
window.onload和DOMContentLoaded区别
- load事件是在页面的全部资源加载完才会执行,包括图片、视频等
- DOMContentLoaded事件是在DOM渲染完即可执行,此时图片、视频还可能没有加载完。
加载资源优化
- 静态资源的压缩合并
- 静态资源缓存
- 使用CDN让资源加载更快
- 使用SSR后端渲染,数据直接输出到HTML中
渲染优化
- CSS放前面,JS放后面
-
懒加载(图片懒加载、下拉加载更多)
懒加载 -
减少DOM查询,对DOM查询做缓存
DOM缓存 -
减少DOM操作,多个操作尽量合并在一起执行(documentFragment)
合并操作 -
事件节流(减少一些不必要的频繁行为,例如增加延迟)
事件节流 -
尽早执行操作(如DOMContentLoaded)
安全性(非重点)
- XSS跨站请求攻击
在别人的网站发布的信息中插入一段 <script>攻击代码,用于获取查看者cookie,发送到自己的服务器。
解决方案:- 前端替换关键字,例如替换<为<;>为>
- 后端替换
- XSRF跨站请求伪造
一些网站或邮箱中隐藏的伪造请求,比如<img src=xxx.com/pay?id=100
解决方案:- 增加验证流程,如输入指纹、密码、短信验证码
简历
- 简洁明了,重点突出项目经历和解决方案
- 把个人博客放在简历中,并且定期维护更新博客
- 把个人的开源项目放在简历中,并维护开源项目
- 简历千万不要造假,要保持能力和经历上的真实性
面试过程中
- 如何看待加班?加班就像借钱,救急不救穷
- 千万不可挑战面试官,不要反考面试官
- 学会给面试官惊喜,但不要太多
- 遇到不会回答的问题,说出你知道就可以了
- 谈谈你的缺点——说一下你最近正在学什么就可以了
PS常用
- 图像拖到透明图层中——裁切——透明像素
- 文件——编辑——首选项:性能和常规
- 查看图像大小——Ctrl+alt+I
- 合并图层——Ctrl+E
- 切图优化
- 颜色代替图片
- 雪碧图的制作
- 字体图标的使用
- 切图辅助
- TinyPng
- 前端自动化