1. 什么是闭包?闭包的用途是什么?闭包的缺点是什么?
什么是闭包?
在一个函数中能读取其他函数内部变量的这个函数就称为闭包。
在js中,变量的作用域分为:全局作用域和局部作用域。
对一个函数而言,它内部的变量作用域仅仅是函数之内,如果它读取函数之外的变量,这个函数它就是闭包了。
function f1(){
let n=9;
addF = ()=>{return n += 1;}
function f2(){
console.log(n)
return 'hi,i am '+n
}
return f2;
}
const result=f1();
result(); // 9 'hi,i am 9'
addF();//10
result(); // 10 'hi,i am 10'
对f2而言,其中的变量n是f2函数之外的变量,而n的作用域是整个f1函数的内部,f2就是闭包。
闭包的用途?
闭包可以用在许多地方。它的最大用处有两个,一个是可以读取函数内部的变量,例如f2读取f1的变量;另一个就是让这些变量的值始终保持在内存中,不会在f1调用后被自动清除,在addF使用n后,n依然保留着。
闭包的优缺点?
优点:
变量保护,使得能跨作用域访问变量,让函数外部也可以访问到函数内的变量,内部函数有权访问外部函数作用域中的变量。函数可以嵌套使用,子函数可以访问到父函数中的变量和参数。
缺点:
(1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。 解决方法是,在退出函数之前,将不使用的局部变量全部删除。
(2)闭包会在父函数外部,改变父函数内部变量的值。 所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
2. call、apply、bind 的用法分别是什么?
call、apply、bind都是改变this指向的方法
fn.call([this],[param1],[param2]...)
在call中,如果不传参数,或者第一个参数是null或nudefined,this都指向window,如果传参数,就是第一个参数默认为this的指向。
apply:和call基本上一致,唯一区别在于传参方式,call是将第一个参数后的参数一个一个读入作为argumens中的一项,apply则是读取后面的一个数组作为arguments。
fn.call(obj, 1, 2);
fn.apply(obj, [1, 2]);
bind:语法和call一模一样,区别在于立即执行还是等待执行,bind不兼容IE6~8
fn.call(obj, 1, 2); // 改变fn中的this,并且把fn立即执行
fn.bind(obj, 1, 2); // 改变fn中的this,fn并不执行
3. 请说出至少 10 个 HTTP 状态码,并描述各状态码的意义。
HTTP状态码
HTTP Status Code是用以表示网页服务器超文本传输协议响应状态的3位数字代码。
状态码分类表
| 标题 | 类别 | 原因短语 |
|---|---|---|
| 1xx | Informational(信息性状态码) | 接受的请求正在处理 |
| 2xx | Success(成功状态码) | 请求正常处理完毕 |
| 3xx | Redirection(重定向) | 需要进行附加操作以完成请求 |
| 4xx | Client error(客户端错误) | 客户端请求出错,服务器无法处理请求 |
| 5xx | Server Error(服务器错误) | 服务器处理请求出错 |
各类别常见状态码:
2xx
200 OK:表示从客户端发送给服务器的请求被正常处理并返回;
204 No Content:表示客户端发送给客户端的请求得到了成功处理,但在返回的响应报文中不含实体的主体部分(没有资源可以返回);
206 Patial Content:表示客户端进行了范围请求,并且服务器成功执行了这部分的GET请求,响应报文中包含由Content-Range指定范围的实体内容。
3xx
301 Moved Permanently:永久性重定向,表示请求的资源被分配了新的URL,之后应使用更改的URL;
302 Found:临时性重定向,表示请求的资源被分配了新的URL,希望本次访问使用新的URL;
301与302的区别:前者是永久移动,后者是临时移动(之后可能还会更改URL)
303 See Other:表示请求的资源被分配了新的URL,应使用GET方法定向获取请求的资源;
302与303的区别:后者明确表示客户端应当采用GET方式获取资源
304 Not Modified:表示客户端发送附带条件(是指采用GET方法的请求报文中包含if-Match、If-Modified-Since、If-None-Match、If-Range、If-Unmodified-Since中任一首部)的请求时,服务器端允许访问资源,但是请求为满足条件的情况下返回改状态码;
307 Temporary Redirect:临时重定向,与303有着相同的含义,307会遵照浏览器标准不会从POST变成GET;(不同浏览器可能会出现不同的情况);
4xx
400 Bad Request:表示请求报文中存在语法错误;
401 Unauthorized:未经许可,需要通过HTTP认证;
403 Forbidden:服务器拒绝该次访问(访问权限出现问题)
404 Not Found:表示服务器上无法找到请求的资源,除此之外,也可以在服务器拒绝请求但不想给拒绝原因时使用;
5xx
500 Inter Server Error:表示服务器在执行请求时发生了错误,也有可能是web应用存在的bug或某些临时的错误时;
503 Server Unavailable:表示服务器暂时处于超负载或正在进行停机维护,无法处理请求;
4. 著名面试题:如何实现数组去重?
假设有数组 array = [1,5,2,3,4,2,3,1,3,4]
你要写一个函数 unique,使得
unique(array) 的值为 [1,5,2,3,4]
也就是把重复的值都去掉,只保留不重复的值。
要求写出两个答案:
一个答案不使用 Set 实现(6分)
另一个答案使用 Set (4分)
(附加分)使用了 Map / WeakMap 以支持对象去重的,额外加 5 分。
说出每个方案缺点的,再额外每个方案加 2 分。
使用Set
const array = [1,5,2,3,4,2,3,1,3,4]
const unique = (arr) => new Set(arr)
unique(array)
使用Map
const array = [1,5,2,3,4,2,3,1,3,4]
const unique = (arr)=>{
const map=new Map();
return arr.filter(item=>!map.has(item)&&map.set(item,1))
}
unique(array)
5. DOM 事件相关
什么是事件委托?4分
JS里的事件委托:就是当事件触发时,把要做的事委托给父元素来处理。
再通俗点:就是自己的事不想干,叫它爸爸,甚至爷爷、甚至祖先来干。
- 作用1:节约内存
- 作用2:监听动态元素 详情可点击查看代码演示
怎么阻止默认动作?3分
w3c 的方法是 e.preventDefault(),IE 则是使用 e.returnValue = false;
在支持 addEventListener() 的浏览器中,也能通过调用时间对象的 preventDefault()
方法取消时间的默认操作。不过,在 IE9 之前的 IE 中,可以通过设置事件对象的 returnValue 属性为 false来达到同样的效果。
var $a = document.getElementsByTagName("a")[0];
$a.onclick = (e)=>{
alert("跳转动作被我阻止了")
e.preventDefault();
//return false;//也可以
}
怎么阻止事件冒泡?3分
w3c 的方法是 e.stopPropagation(),IE 则是使用 e.cancelBubble = true
function stopBubble(e){
if(e&&e.stopPropagation){//非IE
e.stopPropagation();
} else{//IE
window.event.cancelBubble=true;
}
}
6. 你如何理解 JS 的继承?
答出基于原型的继承给 5 分
答出基于 class 的继承给 5 分
构造函数继承
function person(){this.kind="person";}
person.prototype.eat=function(food){console.log(this.name+" is eating "+food);}
function student(name) {
person.apply(this,arguments)
this.name=name;
}
利用call或者apply方法将父类构造函数的this绑定为子类构造函数的this
缺点:这种方式的继承只能继承父类构造函数中的属性和方法,对于原型对象无法继承
原型实例继承
student.prototype=new person()
student.prototype.construct=student
原型直接继承
student.prototype=person.prototype;
student.prototype.constructor=student;
缺点:这种方式无法继承父类构造函数中的属性与方法,但是可以继承父类构造函数的原型对象。还有因为子类原型student.prototype和父类原型person.prototype指向的是同一个地址,所以student.prototype任何的改变都会引起person.prototype的改变。
ES6中Class继承
Class可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多。
extends 子类的继承
super() 调用父类的构造方法,只能在子类中执行\
class的使用
//class的使用
class Person{
//本质上实例属性和方法是声明在Person.prototype中的
//constructor构造器,当我们用class类new一个对象时,会默认调用构造器
//里面声明实例属性
constructor(name,age){
this.name=name;
this.age=age
}
//实例方法
sayName(){console.log(this.name)}
//而静态属性和方法要用关键字 static 来修饰,本质上他们都是放在构造函数Class上的,只能通过class构造函数来调用
//静态属性
static weight = '50KG'
//静态方法
static sayWeight(){
console.log(this.weight);}
}
//class实例化
let tom =new Person('tom', 20, 'male')
class的继承
//父类class构造函数
class Animal {
static animalAttr = 'Animal静态属性';
constructor(name,age){
this.name = name;
this.age = age
}
animalFun(){console.log('Animal实例方法');}
static animalStaFun(){console.log('animalStaFun静态方法');}
}
//子类构造函数 用extends关键字来表明继承的父类对象,
class Dog extends Animal{
constructor(name,age,color,weight){
// 显示调用super并传递继承的属性就会去寻找extends继承的父构造函数中的数据
super(name,age)
this.color = color;
this.weight = weight;
}
}
//子构造函数实例化,并验证是否继承了父类的实例属性和方法
let dog = new Dog('二狗',4, 'black', '10kg')
//调用父构造函数的属性和方法
console.log(dog); //Dog { name: '二狗', age: 4, color: 'black', weight: '10kg' }
dog.animalFun(); //Animal实例方法
//验证Dog是否继承了父类的静态属性和方法
console.log(Dog.animalAttr); //Animal静态属性
Dog.animalStaFun() //animalStaFun静态方法
//验证总结
//子类原型对象继承父类原型对象
console.log(Dog.prototype.__proto__ === Animal.prototype); //true
//子类对象指向父类对象
console.log(Dog.__proto__ === Animal); //true
7. 数组排序
给出正整数数组 array = [2,1,5,3,8,4,9,5]
请写出一个函数 sort,使得 sort(array) 得到从小到大排好序的数组 [1,2,3,4,5,5,8,9]
新的数组可以是在 array 自身上改的,也可以是完全新开辟的内存。
不得使用 JS 内置的 sort API
const array = [2,1,5,3,8,4,9,5]
const sort = (arr)=>{
for(let i=0;i<arr.length-1;i++){
for(let j = 0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
[arr[j],arr[j+1]]=[arr[j+1],arr[j]]
}
}
}
return arr
}
sort(array)
8. 你对 Promise 的了解?
Promise 的用途
解决异步回调的问题。 它对比其余解决异步回调方法的优点是:能解决其余方法不规范,五花八门的命名、解决回调地狱、错误处理无法就行(try catch)等等的问题。
如何创建一个 new Promise(课堂里让大家背过)
return new Promise( (resolve,reject)=>{……})
如何使用 Promise.prototype.then(可查 MDN)
then() 方法返回一个 Promise
它最多需要有两个参数:Promise 的成功和失败情况的回调函数。
它的语法是
p.then(onFulfilled, onRejected);
onFulfilled 可选
- 当 Promise 变成接受状态(fulfilled)时调用的
函数。该函数有一个参数,即接受的最终结果(the fulfillment value)。如果该参数不是函数,则会在内部被替换为(x) => x,即原样返回 promise 最终结果的函数
onRejected 可选
- 当 Promise 变成拒绝状态(rejected)时调用的
函数。该函数有一个参数,即拒绝的原因(rejection reason)。 如果该参数不是函数,则会在内部被替换为一个 "Thrower" 函数 (it throws an error it received as argument)。
返回值
当一个 Promise 完成(fulfilled)或者失败(rejected)时,返回函数将被异步调用(由当前的线程循环来调度完成)
如何使用 Promise.all(可查 MDN)
Promise.all() 方法接收一个 promise 的 iterable 类型(注:Array,Map,Set 都属于 ES6 的 iterable 类型)的输入,并且只返回一个Promise实例, 那个输入的所有 promise 的 resolve 回调的结果是一个数组。
Promise.all(iterable);
如何使用 Promise.race(可查 MDN)
Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝。
语法
Promise.race(iterable);
返回值
一个待定的 Promise 只要给定的迭代中的一个 promise 解决或拒绝,就采用第一个 promise 的值作为它的值,从而异步地解析或拒绝(一旦堆栈为空)。
9. 说说跨域。
要点:
什么是同源
同源:当两个接口的协议、域名、端口号都相等时,这俩接口是同源的,只要有一个条件不相等,则非同源。不是同源的两个页面不能互相访问本地缓存、不能互相修改dom节点、不能使用ajax请求对方接口数据。
什么是跨域
在不同源的网页资源之间进行数据传输或者通信如:从 www.baidu.com 页面去请求 www.google.com 域:协议、域名、端口三者中有一者不同就是不同源,它们之间的访问就需要跨域。
JSONP 跨域
不同源的两个网站,以A方取请求B方的资源为例,jsonp跨域就是A在网页中创建一个script标签,去请求另一个网站的js,js会夹带一些数据,这些数据会在A的网站中调用一个函数去运行。
CORS 跨域
CORS跨域就是被请求的网站把请求的网站加入白名单。 CORS全称Cross-Origin Resource Sharing,也就是我们常说的跨域资源共享,CORS是通过新增一组HTTP头部字段,允许服务器声明那些源站有权限访问哪些资源。
response.setHeader('Access-Control-Allow-Origin','http://localhost:8889')
10.说说你对前端的 理解
评分标准:
- 0 分:言之无物,看不下去
- 5 分:人云亦云,流于平庸
- 10 分满分:见解深刻,有自己的想法
- 15 分:惊为天人 前端是将后台的程序以图形化的可交互的界面展示给用户,www = url + HTML + HTTP ,如果用收寄快递来理解,HTML是标记语言快递盒子,url相当于门牌号,HTTP是通信协议如何送件,前端的重点在于,如何让用户在收快递的时候更舒适,便捷,于是有了css和js、HTML的学习,HTML超文本标记语言,是一个界面内容的展示形式,决定了内容的结构是dom树,对内容进行操作,也是以树节点的方式操作,css是层叠样式表,让页面可以展示更多的样式,js是编程语言,可以让网页加载出更多的动态效果,以及与后台通信,AJAX用js发送请求和响应,操作HTML中的节点DOM,jQuery……。 在与其他服务器通信的时候也会遇到一些问题,例如:发送请求后不能直接拿到结果,对于处理异步和回调的问题,又到了Promise大显身手的时候了;又如,我发送的请求得不到服务器中的数据,解决跨域访问的问题,又有了Jsonp和CORS…… 总之,前端就是使通信正常顺畅的情况下,让页面更好地展示给用户。
`