1、在javascript中如何检测一个变量是String类型,请写出函数实现?
答:typeof obj ==="string" 或者obj.constructor ==="String"
2、请用js去除字符串空格
答:(1)去除所有空格str.replace(/\s*/g,"") , 去除两端空格str.replace(/^\s* | \s*$/g,"")
(2)可以通过str.trim()去除两端空格,但这个方法不能去除中间的空格,str.trimLeft()是去除左边空格,str.trimRight()是去除右边空格
3、如何通过js获取url中的参数
(2)编写以下函数实现一个返回一个包含url参数信息的对象
function(){
var urlStr = url.split("?")
if(urlStr[0]==url){
return null
}
var argsStr = urlStr[1]
var args = argsStr.split("&")
var argObj = {}
for(var i =0;i<argObj.length;i++){
var content = argObj[i].split("=")
argObj[content[0]] = content[1]
}
return argObj
}
4、使用Promise对象实现暂停5秒再执行其他操作的函数,以下函数实现了通过Promise函数5秒后返回一个字符串data,接着在then里面输出该字符串,如果您没了解过Promise函数可能以下代码您没能看懂,但您如果想从事前端开发Primise是必须要懂的
var p = new Promise(function(resolve,reject){
setTimeout(function(){
resolve("data")
},5000)
})
p.then(function(data){
console.log(data)
})
5、使用nodejs的时候怎样使nodejs实现多线程的功能?
前言:nodejs的特点是事件驱动,单线程, 非阻塞I/O,这是的nodejs对于IO操作非常频繁的操作来说非常便利,效率非常高,例如说在从磁盘读一个文件非常大的文件的时候,如果是传统的后台开发语言,就要等到文件读取完毕再执行下面的函数,为node由于是异步的IO操作,所以在读取大文件时不用等待文件读取完毕,而是继续执行下面的内容,等文件读取完毕后再通知线程过来处理,大大提高了程序执行的效率,但同时有与nodejs是单线程的,所以nodejs是依靠事件驱动的方式来处理执行操作的,这就遇到了一个问题,就是同时多人访问时,nodejs只能把所有的请求都添加到消息队列中,而且又由于是单线程的,这是nodejs的优势就没了,因为消息队列的请求时间大于线程启动的时间,nodejs当初设计为单线程的原因就是想通过减少多线程启动所带来的时间消耗,从而提高开发效率,所以对于那些高并发的多计算操作的应来说多线程的功能也就成为了一个需求
答案:那么业界有哪些nodejs多线程的实现呢?成熟的技术解决方案是通过安装threads_a_gogo
通过这个模块很容易就可以实现nodejs多线程的功能,带来的好处是
(1)平行执行,无需排队,快速
(2)公平性,线程具有同一优先级
(3)完整利用资源,让更多的CPU参与task处理
6、this在js中四个典型的使用
(1)在html属性中使用,this指向当前节点
(2)在构造函数中使用,此时this指向当前对象
(3)在script中通过获取input标签的元素,同时添加点击事件,这是的this代表input标签元素,通过this.value可以获取input标签里面的内容
(4)在apply,call中使用
例如:var num = [20,15,12,5]
var max = Math.max.apply(this,number)
console.log(max) //20
通过以上方法即可把数组的最大值打印出来
7、typeof 和 instanceof的使用场景
答:
(1)typeof就是获取对象的类型,,js主要的数据类型为number,boolean,string,function,object,undefined,其中要注意null和Array都是Object类型,typeof常用来判断某变量是否存在例如:if(typeof a==="undefined")
(2)instanceof是判断变量是否为对象的实例,要注意的是instanceof判断的对象是js语法中的对象,而不是dom模型对象
8、什么是闭包?
答:定义和用法:当一个函数内部包含了另外一个函数,同时内部函数引用了外部函数的变量,如果这个内部函数在外部被调用,这时就形成了闭包
例如function sum(){
var add = 0
function count(){
add + +
console.log(add)
}
return count
}
var add = sum()
add() // 1
add() //2
9、前端开发过程中常遇到哪些安全问题
1、xss攻击(跨站脚本攻击),跨站脚本攻击指的是攻击者往web页面里面注入恶意的script代码,用户在浏览这些网页时会执行这些代码,从而盗取用户cookie信息,和进行会话劫持
解决方案:(1)输入过滤,通过对用户的输入进行过滤,判断输入是否为预期内容,从而避免xss攻击,但是这只能对xss攻击做一些初步的防御,因为攻击者可以通过抓包的形式(fiddler)绕过输入限制,修改发送请求中的内容,向后台发送恶意代码,所以需要在后台接收内容后,对特殊字符进行转义再存到后台当中,从而解决xss攻击的问题
(2)输出编码,服务器端输出到浏览器的数据可以使用系统的安全函数进行编码或转义,从而避免避免xss攻击,例如JavascriptEncode
(3)HttpOnly Cookie,预防xss攻击窃取用户的cookie信息最有效的方法,web应用程序在设置Cookie的时候设置为HttpOnly,就可以避免Cookie被JavaScript而已代码获取
(4)web应用防火墙
2、CSRF攻击(跨站请求伪造)
原理:CSRF攻击的过程是,用户登录A网站,输入个人信息,同时接收保存服务器返回的Cookie信息,然后在A网站点击一条由攻击者构建的恶意链接,这时用户跳转到了B网站,这时B网站就可以携带用户的Cookie信息去访问A网站,在A网站进行一些敏感的操作,例如转账等操作
解决方案:
(1)验证码:当用户进行一些敏感的操作时,例如转账等操作时,要求用户输入验证码,这样可以防止CSRF攻击
(2)CSRF Token:目前比较完善的解决方法是在发送http请求的时候加上一个随机的Token,并在服务端设计一个拦截器来验证这个Token,服务器读取浏览器当前域cookie中的token值和当前请求的token值是否一致,一致才给与通过
3、sql注入攻击
原理:应用程序在向后台数据库传递sql语句的时候,攻击者将sql命令插入到web表单提交或输入域名或页面请求的查询字符串,最终欺骗服务器执行恶意sql命令的操作
解决方案:
(1)防止敏感信息泄漏,返回给客户端的数据不要防护敏感信息
(2)数据转义:对于sql语句中的特殊字符例如单引号和双引号等特殊字符进行转义操作
4、文件上传攻击
原理:通过上传一些包含恶意代码的文件,该文件可以被服务器端执行,从而可以在服务器端执行恶意代码
(1)限制文件上传的后缀及类型
10、什么是跨域,跨域请求资源的方法有哪些
跨域:由于浏览器的同源策略,凡是发送请求的url的协议,端口,域名三者之间任意一个与当前页面的url不同即为跨域
(1)协议不同:例如当前的是http协议,请求的资源是https协议
(2)端口不同:当前端口是8081,而访问的端口是8080
(3)域名不同:当前url为join.qq.com,而访问的域名为baidu.com
只要存在以上其中一种情况,即形成跨域
解决方案:
(1)proxy代理,通过将请求发送给服务器,由服务器发起请求,将请求的结果返回给客户端,从而解决跨域问题,常见的proxy代理实现是通过nginx服务器
(2)CORS(跨域资源分享),后端开发人员在处理请求的时候,添加允许跨域的操作代码
nodejs实现代码如下:
res.write(200,{
"Content-Type":"text/html;charset=UTF-8",
"Access-Controll-Allow-Origin":"*",
"Access-Controll-Allow-Methods":"GET,POST,OPTIONS",
"Access-Controll-Allow-Headers":"X-Requested-With,Content-Type"
})
(3)JSONP实现跨域
原理:浏览器对于html标签(script,img,iframe)的外部请求没有同源策略限制,资源加载到页面后也会立即执行,不会产生阻塞的情况,所以JSON其实就是往页面里面添加一个script标签,有script标签去发送外部请求,但由于是通过script标签去发送请求,所以JSONP只对get请求有效对于post请求无效
11、http请求过程
一次完整的http请求经过域名解析,通过三次握手进行tcp/ip连接,接送客户端向服务全发送请求,服务端向客户端返回资源,客户端接收服务器返回的数据并在浏览器进行渲染
三次握手过程:
(1)客户端首先发起一个连接试探,ACK=0,表示确认号无效,SYN=1表示这是一个连接请求,同时表示这个报文不能携带数据,seq=x表示请求的序列号,发送请求完毕后客户端进入syn_send的状态,表示客户端等待服务端的回应
(2)服务端在监听到连接请求之后,如果同意建立连接,则向客户端发送确认,确认TCP报文中SYN和ACK都设置为1,ack=x+1表示期望收到客户端的下一个报文端的第一个数据字节为x+1,并且表示x位置的所有数据都已经收到,发送完毕后服务端进入syn_rcvd状态,表示服务端已经接收到客户端的连接请求,等待客户端进行确认
(3)客户端在收到服务端的确认请求后,还需再次向服务端发送确认报文,把ACK置为1,表示ack=x+1有效,客户端的序号seq=x+1(表示这是我的第1个包,相对于第0个包来说),服务端在收到客户端的这个确认报文后TCP连接就建立起来了,状态转为ESTABLISH
12、http1与http2的区别
(1) http1是使用文本进行传送数据,http2是使用二进制的方式进行传送
(2)多路复用,因为http2是采用二进制的方式去传送数据,而二进制的格式是帧和流,而且帧和流都有ID,这就引出了另外一个概念多路复用,应为有流ID,可以通过同一次TC
P/IP连接来实现多次http请求,可以通过流ID去判断这是哪次http请求
(3)头部压缩,http2通过gzip和compress压缩头部再发送请求,同时客户端和服务端同时维护一个头信息表,所有的头信息都保存在这张表当中,以后每次传输就只传输表的ID就可以了,通过ID就可以知道头信息了
(4)服务端推送,http2可以主动向客户端推送内容
13、js怎样判断一个变量为Array类型
基本的判断js的类型一般都是通过typeof去判断,但是这种办法对于Array类型不起作用,那么Array类型怎么进行判断呢?
(1)instanceof 通过使用instanceof可以很简单的判断某个数组是否为Array类型,例如
var arr = [1,2,3]
var flag = alert(arr instanceof Array)
(2)constructor 每种数据类型都有constructor,所以可以通过alert(arr.constructor===Array)也可以判断变量是否为数组类型
(3)Array.isArray()函数,通过使用该函数可以很简单的达到我们判断数组的目的
(4)Object.prototype.toString.call(arr) ==="[Object Array]",通过原型链的方式也可以判断数组类型
14、js引用类型,基本类型,堆、栈
堆:堆是动态分配的,jvm不会自动释放这部分的内存,内存会等系统回收机制进行回收
栈:栈是系统静态分配的,系统会自动释放这部分的内容
基本类型:Number String Boolean Null undefined
引用类型:Object Array Date RegExp Function
(1)基本数据类型的变量标识符和值都是保存在栈区间的
(2)对于引用类型的话,由于js语言的特殊性,其实我们是不能直接操作对象的内存空间的,那我们怎么对对象进行操作呢?我们可以通过对象的引用去访问内存区间中的对象,所以对于引用类型来说,其对象标识符是保存在栈内容中,对象的内容保存在堆内存中,对象标识符指向堆内存中该对象的指针
15、垃圾回收机制
原理:垃圾回收机制(GC),垃圾回收机制会定期找出那些不再使用的变量,然后释放其内存,垃圾回收策略分为标记清除和引用计数
(1)标记清除的意思是说当变量进入内存的时候会标记为已经进入,当变量离开环境的时候会标记为离开环境,定期的过滤掉环境中已经不使用的变量
(2)引用计数是跟踪每个变量被引用的次数,当引用次数为1的时候说明该变量可以被回收了
16、内存泄漏
原理:内存泄漏是指一块被分配的内存既不能被使用,也不能被回收,直到浏览器的进程被关闭
(1)内存泄漏发生的原因,例如收某个元素被浏览器移除,但是元素绑定的事件没有被移除,这就造成了内存泄漏的发生,或者在js中使用了闭包,闭包里面的局部变量被保存在内存中得不到释放也可能会引起内存泄漏
(2)解决方法,在从dom里删除某元素的时候把该元素绑定的事件也删掉,当变量不再使用时手动把改变量变成null
17、 javascript面向对象中继承实现?
面向对象的基本特征有封闭,继承,多态
在javascrip中实现继承有以下几种方式
(1)原型链
function animal(type,food){
this.type=type
this.food=food
}
animal.prototype.eat = function(){
console.log(this.food)
}
function cat(type,food){
this.type = type
this.food = food
}
cat.prototype = new animal()
var cat1 = new cat("cat","fish")
cat1.eat() //fish
(2)call/apply
function anima(type,food){
this.type = type
this.food = food
this.eat = function(){
console.log(this.type+"吃"+this.food)
}
}
function cat(name,food){
var args = arguments
animal.apply(this,arguments)
}
var cat1 = new cat("cat","fish")
cat1.eat() //fish
(3)对象冒充
function anima(type,food){
this.type = type
this.food = food
this.eat = function(){
console.log(this.type+"吃"+this.food)
}
}
function cat(name,food){
this.Cat = animal
this.Cat(name,food)
delete this.Cat
}
var cat1 = new cat("cat","food")
cat1.eat() //fish
18、JavaScript中的作用域,作用域链
原理:作用域、代码中函数和变量的使用范围
作用域链、包含了函数被创建的作用域中对象的集合
先上三个小实例,看你能不能猜对
(1)var a = "global"
function test(){
console.log(a)
var a = "inner"
console.log(a)
}
console.log(a)
(2)var a = "global"
function test(){
console.log(a)
a = "inner"
console.log(a)
}
console.log(a)
(3) var a = "global"
function test(a){
console.log(a)
a = "inner"
console.log(a)
}
console.log(a)
上面的输出分别为1、undefined,inner,global 2、global,inner,inner 3、undefined,inner,global
如果你没有猜对的话,那么javascript的基础还不是很扎实
解析:在第一个案例中,在函数的内部定义了一个和外部一样的变量,由于js的变量提升,所以函数内部变量a的定义被提升到函数的开始相当于函数变成了以下形式
(1)var a = "global"
function test(){
var a
console.log(a)
a = "inner"
console.log(a)
}
console.log(a)
从上面函数可以看到内部变量a只是定义了,还没有赋值,所以这是第一个console.log的职为undefined,程序运行到第二个log的时候,这时a赋值为inner,所以第二个输出打印为inner,由于函数内部定义了a,内部的变量a的职更改后不会影响外部的变量a,所以,这时a还是等于函数外部定义的a的值,也就是global
只要第一个案例理解了其他两个案例就可以明白了
19、ajax请求过程
(1)首先通过var XMLHttp=new XMLHttpRequest()来创建一个XMLHttpt对象,在Ie中是var XMLHttp=new ObjectActive()
(2)操作XMLHttp对象设置请求参数,设置一个处理服务端响应的回调函数onreadystatechange,获取readyStatus的状态,
通过判断readyStatus的状态来查看响应状态
0 请求未初始化(在调用 open() 之前)
1 请求已提出(调用 send() 之前)
2 请求已发送(这里通常可以从响应得到内容头部)
3 请求处理中(响应中通常有部分数据可用,但是服务器还没有完成响应)
4 请求已完成(可以访问服务器响应并使用它)
(3)如果readyStatus等于4并且服务端返回的状态码等于200的时候说明服务器运行正常并放回数据,接下来就可以进行数据的处理了
因篇幅问题不能全部显示,请点此查看更多更全内容