什么是闭包?闭包的用途是什么?闭包的缺点是什么?
闭包:函数访问外部的变量 这个函数加变量的组合叫做闭包。
闭包的用途:
一、函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量。我们有时候需要获取到函数内部的局部变量,那就是在函数内部,再定义一个函数。
二、让变量的值始终保持在内存中,不会在 f1 调用后被自动清除。原因就在于 f1 是 f2 的父函数,而 f2 被赋给了一个全局变量,这导致 f2 始终在内存中,而 f2 的存在依赖于 f1,因此 f1 也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
function f1(){
var n=999;
function f2(){
alert(n); // 999
}
}
闭包的缺点:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,滥用闭包会造成网页的性能问题。
call、apply、bind 的用法分别是什么?
call: 在一个子构造函数中,你可以通过调用父构造函数的call方法来实现继承,call 方法第一个参数是要绑定给this的值,后面传入的是一个参数列表。当第一个参数为null、undefined的时候,默认指向window。 举个例子
var obj = {
message: 'My name is: '
}
function getName(firstName, lastName) {
console.log(this.message + firstName + ' ' + lastName)
}
getName.call(obj, 'Dot', 'Dolby')//My name is: Dot Dolby
apply: 事实上apply 和 call 的用法几乎相同, 唯一的差别在于:当函数需要传递多个变量时, apply 可以接受一个数组作为参数输入, call 则是接受一系列的单独变量。举例如下
var obj = {
message: 'My name is: '
}
function getName(firstName, lastName) {
console.log(this.message + firstName + ' ' + lastName)
}
getName.apply(obj, ['Dot', 'Dolby'])// My name is: Dot Dolby
bind:和call很相似,第一个参数是this的指向,从第二个参数开始是接收的参数列表。区别在于bind方法返回值是函数以及bind接收的参数列表的使用,bind可以让this的值不被改变
function f1(p1, p2){
console.log(this, p1, p2)
}
let f2 = f1.bind({name:'frank'})
f2(1,2)//{name: "frank"} 1 2 等价于f1.call({name:'frank'},1,2)
如下代码所示,call 是把第二个及以后的参数作为 fn 方法的实参传进去,而 fn1 方法的实参实则是在 bind 中参数的基础上再往后排。
function fn(a, b, c) {
console.log(a, b, c);
}
var fn1 = fn.bind(null, 'Dot');
fn('A', 'B', 'C'); // A B C
fn1('A', 'B', 'C'); // Dot A B
fn1('B', 'C'); // Dot B C
fn.call(null, 'Dot'); // Dot undefined undefined
请说出至少 10 个 HTTP 状态码,并描述各状态码的意义。(例如:状态码 200 表示响应成功。)
状态码的职责是当客户端向服务器发送请求时,描述返回的请求结果。借助状态码,用户可以知道服务器端是正常处理了请求还是出现了错误。
状态码的类别:
| 类别 | 原因短语 | |
|---|---|---|
| 1XX | Informational(信息性状态码) | 接受的请求正在处理 |
| 2XX | Success(成功状态码) | 请求正常处理完毕 |
| 3XX | Redirection(重定向状态码) | 需要进行附加操作以完成请求 |
| 4XX | Client Error(客户端错误状态码) | 服务器无法处理请求 |
| 5XX | Server Error(服务器错误状态码) | 服务器处理请求出错 |
2XX——表明请求被正常处理了
1、200 OK:请求已正常处理。
2、204 No Content:请求处理成功,但没有任何资源可以返回给客户端,一般在只需要从客户端往服务器发送信息,而对客户端不需要发送新信息内容的情况下使用。
3、206 Partial Content:是对资源某一部分的请求,该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的GET请求。响应报文中包含由Content-Range指定范围的实体内容。
3XX——表明浏览器需要执行某些特殊的处理以正确处理请求
4、301 Moved Permanently:资源的uri已更新,你也更新下你的书签引用吧。永久性重定向,请求的资源已经被分配了新的URI,以后应使用资源现在所指的URI。
5、302 Found:资源的URI已临时定位到其他位置了,姑且算你已经知道了这个情况了。临时性重定向。和301相似,但302代表的资源不是永久性移动,只是临时性性质的。换句话说,已移动的资源对应的URI将来还有可能发生改变。
6、303 See Other:资源的URI已更新,你是否能临时按新的URI访问。该状态码表示由于请求对应的资源存在着另一个URL,应使用GET方法定向获取请求的资源。303状态码和302状态码有着相同的功能,但303状态码明确表示客户端应当采用GET方法获取资源,这点与302状态码有区别。
当301,302,303响应状态码返回时,几乎所有的浏览器都会把POST改成GET,并删除请求报文内的主体,之后请求会自动再次发送。
7、304 Not Modified:资源已找到,但未符合条件请求。该状态码表示客户端发送附带条件的请求时(采用GET方法的请求报文中包含If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since中任一首部)服务端允许请求访问资源,但因发生请求未满足条件的情况后,直接返回304.。
8、307 Temporary Redirect:临时重定向。与302有相同的含义。
4XX——表明客户端是发生错误的原因所在。
9、400 Bad Request:服务器端无法理解客户端发送的请求,请求报文中可能存在语法错误。
10、401 Unauthorized:该状态码表示发送的请求需要有通过HTTP认证(BASIC认证,DIGEST认证)的认证信息。
11、403 Forbidden:不允许访问那个资源。该状态码表明对请求资源的访问被服务器拒绝了。(权限,未授权IP等)
12、404 Not Found:服务器上没有请求的资源。路径错误等。
5XX——服务器本身发生错误
13、500 Internal Server Error:貌似内部资源出故障了。该状态码表明服务器端在执行请求时发生了错误。也有可能是web应用存在bug或某些临时故障。
14、503 Service Unavailable:抱歉,我现在正在忙着。该状态码表明服务器暂时处于超负载或正在停机维护,现在无法处理请求。
原文链接:blog.csdn.net/qq_35689573…
著名面试题:如何实现数组去重?
假设有数组 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 分。
答案一:
function unique(array){
var hash=[]
var arr=[]
for (let i=0;i<array.length;i++){
if(hash[array[i]]===undefined){
hash[array[i]]=true
arr.push(array[i])
}
}
return arr;
}
unique([1,5,2,3,4,2,3,1,3,4]) // [1, 5, 2, 3, 4]
//缺点:多创建了一个数组,空间换时间
答案二:
const array = [1,5,2,3,4,2,3,1,3,4]
console.log([...new Set(array)]) // [1, 5, 2, 3, 4]
//无法去除相同对象
DOM 事件相关
什么是事件委托?
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)。
怎么阻止默认动作?
event.preventDefault()方法这是阻止默认事件的方法,调用此方法时,连接不会被打开,但是会发生冒泡,冒泡会传递到上一层的父元素;
IE:window.event.returnValue = false;//阻止事件的默认行为
怎么阻止事件冒泡?
event.stopPropagation()方法
这是阻止事件的冒泡方法,不让事件向documen上蔓延,但是默认事件任然会执行,当你调用这个方法的时候,如果点击一个连接,这个连接仍然会被打开
IE:window.event.cancelBubble = true;//停止冒泡
你如何理解 JS 的继承?
答出基于原型的继承给 5 分
原型链继承:
//父类
function Animals(name){
this.name= name
}
//添加原型属性
Animals.prototype.running=function (){console.log('I am running')}
Animals.prototype.age='100'
//原型链继承
function Dog(){
this.color= 'white'
}
Dog.prototype = new Animals('旺财')
let dog1 = new Dog()
console.log(dog1.name) //旺财
console.log(dog1.age) //100
console.log(dog1.running()) //I am running
答出基于 class 的继承给 5 分
class 的继承:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name) {
super(name); // 调用超类构造函数并传入name参数
}
}
var d = new Dog('Mitzie');
d.speak();// Mitzie makes a noise
数组排序
给出正整数数组 array = [2,1,5,3,8,4,9,5] 请写出一个函数 sort,使得 sort(array) 得到从小到大排好序的数组 [1,2,3,4,5,5,8,9] 新的数组可以是在 array 自身上改的,也可以是完全新开辟的内存。不得使用 JS 内置的 sort API
let quickSort = (arr)=>{
if(arr.length<=1){
return arr
}
let pivotIndex = Math.floor(arr.length/2)
let pivot = arr.splice(pivotIndex,1)[0]
let leftSort=[]
let rightSort=[]
for (let i =0;i<arr.length;i++){
if(arr[i]<pivot){
leftSort.push(arr[i])
}else{
rightSort.push(arr[i])
}
}
return quickSort (leftSort).concat([pivot],quickSort (rightSort))
}
let array = [2,1,5,3,8,4,9,5]
quickSort (array)
你对 Promise 的了解?
答题要点:
Promise 的用途
Promise 用来解决异步编程中回调地狱问题,使代码的可读性更强,并可以很方便的捕获错误。
如何创建一个 new Promise
return new Promise((resolve,reject)=>{})
如何使用 Promise.prototype.then
var p1 = new Promise((resolve, reject) => {
resolve('成功!');
// or
// reject(new Error("出错了!"));
});
p1.then(value => {
console.log(value); // 成功!
}, reason => {
console.error(reason); // 出错了!
});
如何使用 Promise.all
Promise.all 等待所有都完成(或第一个失败)。
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([p1, p2, p3]).then(values => {
console.log(values); // [3, 1337, "foo"]
});
如何使用 Promise.race
Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster
});
// expected output: "two"
说说跨域。
什么是同源
如果两个页面(接口)的协议,端口或者域名都相同,那么两个页面就有相同的源。
什么是跨域
跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制
JSONP 跨域
我们知道script标签是允许跨域请求的。利用这个特性,客户端使用script代替XHR( XMLHttpRequest)发起跨域请求,服务器在json响应数据前后填充一些额外的内容,就称为“填充式JSON”——JSONP,JSONP实现跨域请求的原理就是动态创建script标签,利用“src”不受同源策略约束的性质来实现跨域获取数据。
CORS 跨域
CORS是Cross-Origin Resources Sharing的简写,中文翻译为“跨域资源共享”,是W3C的标准。通过CORS,浏览器允许向其他源服务器发送资源请求,服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符(*)则表示所有网站都可以访问资源。
说说你对前端的理解
随着人们对服务的要求越来越高,用户体验也成了项目开发设计的重要环节,前端也变得越来越重要,前端工程师就是运用 HTML/CSS/JavaScript 等 Web 技术,在工作中配合设计师实现用户界面,和后端工程师进行数据对接,完成 Web 应用开发的职位。前端工程师是最贴近用户的程序员,主要负责实现页面交互,优化提升用户体验,如果后端是用来解决系统能不能用的问题,那么前端就用来解决系统好不好用的问题。同时,前端算是一个新兴岗位,历史很短暂,底蕴薄弱,前端的技术也日新月异,需要不断的去学习新的知识,才能更好地去适应前端的发展。