1.函数声明和函数表达式的区别
show1();//show1
function show1(){ //函数声明
console.log("show1");
}
show1();//show1
console.log(show2);//undefined
var show2 = function(){ //函数表达式
console.log("show2");
}
show2();//show2
声明的函数会有提升,在声明前后均可使用,函数表达式声明的函数会有提升,但只是声明提升,函数名此时为undefined,并不能执行,只有在赋值操作后才能执行
2.什么是闭包,闭包的作用 什么是闭包:
当内部函数被保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放,造成内存泄露。
闭包的作用:
实现公有变量 eg:函数累加器
可以做缓存 eg:eater
可以实现封装,属性私有化。 eg: Person();
经典例题:
function fun(n,o){
console.log(o);
return {
fun:function(m){
return fun(m,n);
}
}
}
var a = fun(0); a.fun(1); a.fun(2); a.fun(3);//undefined 0 0 0
var b = fun(0).fun(1).fun(2).fun(3);//undefined 0 1 2
var c = fun(0).fun(1); c.fun(2); c.fun(3);// undefined 0 1 1
3.什么是跨域,如何解决跨域问题? 跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。
同源:域名,协议,端口均相同
不同源:协议不同(http/https),域名不同,域名的前缀不同,端口不同,域名和域名对应ip也属于跨域,请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。
1、后端配置cors:
本人对后端领域尚未涉足,推荐博客:blog.csdn.net/envon123/ar…
2、JSONP:
SONP只支持GET请求,不支持POST请求,此方法使用较少
3、Proxy(代理):
例如www.123.com/index.html需要调用www.456.com/server.php,可以写一个接口www.123.com/server.php,由这个接口在后端去调用www.456.com/server.php并拿到返回值,然后再返回给index.html,这就是一个代理的模式。相当于绕过了浏览器端,自然就不存在跨域问题。
4.浏览器请求一个url页面到显示完成,这个过程发生了什么 简单得讲:
浏览器根据请求的URL交给DNS域名解析,找到真实IP,向服务器发起请求;
服务器交给后台处理完成后返回数据,浏览器接收文件(HTML、JS、CSS、图象等);
浏览器对加载到的资源(HTML、JS、CSS等)进行语法解析,建立相应的内部数据结构(如HTML的DOM);
载入解析到的资源文件,渲染页面,完成。
详细得说:
1、当发送一个URL请求时,不管这个URL是Web页面的URL还是Web页面上每个资源的URL,浏览器会开启一个线程来处理这个请求,对URL 分析判断如果是 http 协议就按照 Web 方式来处理;
2、调用浏览器内核中的对应方法,比如 WebView 中的 loadUrl 方法;
3、在远程DNS服务器上启动一个DNS查询,这能使浏览器获得请求对应的IP地址。通过DNS解析获取网址的IP地址,设置 UA 等信息发出第二个GET请求;
4、进行HTTP协议会话,客户端发送报头(请求报头):浏览器与远程Web服务器通过TCP三次握手协商来建立一个TCP/IP连接。该握手包括一个同步报文,一个同步-应答报文和一个应答报文,这三个报文在 浏览器和服务器之间传递。该握手首先由客户端尝试建立起通信,而后服务器应答并接受客户端的请求,最后由客户端发出该请求已经被接受的报文。
5、进入到web服务器上的 WebServer,如 Apache、Tomcat、Node.JS 等服务器;
6、进入部署好的后端应用,如PHP、Java、JavaScript、Python 等,找到对应的请求处理;
7、处理结束回馈报头,此处如果浏览器访问过,缓存上有对应资源,会与服务器最后修改时间对比,一致则返回304;
8、浏览器开始下载html文档(响应报头,状态码200),同时使用缓存;
9、文档树建立,根据标记请求所需指定MIME类型的文件(比如css、js),同时设置了cookie;
10、浏览器会解析HTML生成DOM Tree,其次会根据CSS生成CSSRule Tree,而javascript又可以根据DOMAPI操作DOM,执行事件绑定等,页面显示完成。
(转自:www.cnblogs.com/calamus/p/5…)
5.冒泡排序算法 解析:1.比较相邻的两个元素,如果前一个比后一个大,则交换位置。
2.第一轮的时候最后一个元素应该是最大的一个。
3.按照步骤一的方法进行相邻两个元素的比较,这个时候由于最后一个元素已经是最大的了,所以最后一个元素不用比较。
性能 时间复杂度: 平均时间复杂度O(nn) 、最好情况O(n)、最差情况O(nn) 空间复杂度: O(1) 稳定性:稳定
时间复杂度指的是一个算法执行所耗费的时间 空间复杂度指运行完一个程序所需内存的大小 稳定指,如果a=b,a在b的前面,排序后a仍然在b的前面 不稳定指,如果a=b,a在b的前面,排序后可能会交换位置
let arr = [6,4,1,2,5];
let len = arr.length;
for(let i = 0;i < len; i++){
for(let j = 0;j < len-i-1;j++){
if(arr[j] > arr[j+1]){
let temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
以下代码是个人的习惯写法,每次都找到当前的最小元素放在开始位置:
for(var i = 0;i < len-1;i++){
for(var j = i + 1; j < len; j++){
if(arr[i] > arr[j]){
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
6.全局作用域,局部作用域 预编译发生在函数执行的前一刻
预编译 四部曲:
1.创建AO对象
2.找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
3.将实参值和形参统一
4.在函数体里面找函数声明,值赋予函数体
先生成GO后生成AO
var a = 10;
function f(){
var b = 2 * a;
var a =20;
var c = a + 1;
console.log(b);//NaN
console.log(c);//21
}
f();
7.JavaScript中的数据类型 js中有六种数据类型,包括五种基本数据类型(Number,String,Boolean,Undefined,Null,ES6新增Symbol,ES10新增bigint),
和一种复杂数据类型(Object)。
typeof 123 //Number
typeof 'abc' //String
typeof true //Boolean
typeof undefined //Undefined
typeof null //Object
typeof { } //Object
typeof [ ] //Object
typeof console.log() //Function
null类型进行typeof操作符后,结果是object,原因在于,null类型被当做一个空对象引用。
三大引用类型:Object,Array,Function
判断是是不是数组:
arr.constructor === Array //true
arr instanceof Array //true
Object.prototype.toString.call(arr)==="[object Array]" //true
8.Ajax的过程和原理 1.获取ajax异步对象
IE4~IE12 : 使用new ActiveXObject("microsoft.xmlhttp");
非IE : 使用new XMLHttpRequest();
2.ajax.open(method,url);
method是提交方式 有 get和post两种
url是提交路径
3.ajax.send()
4.ajax.onreadystatechange 这是一个监听函数
包括五中状态码:
0—ajax异步对象创建完毕,但是还未发送
1—ajax已经调用了open()方法,但是还未调用send()方法
2—已经调用send(),但是还未到达服务器端
3—表示请求已经到达服务端,正在服务端的处理,但是还未响应返回
4—ajax已经完全接收了服务器的响应信息,但是状态码未必是正确的
状态码有:
200:正确
404/500:错误
ps:a.每个浏览器的0,1,2,3这四种状态显示的不一样,但是4这个状态码每
个浏览器都有,所以我们只需要使用4即可
b. 0.1.2.3.4是ajax中的响应码,200/404/500是web中的状态码
5.ajax.readyState == 4
6.ajax.status == 200;
7.获取值 ajax.requestText或者ajax.requestXML
(测试见:www.w3school.com.cn/tiy/t.asp?f…
function getData(){
var xmlhttp;
if(window.XMLhttpRequest){
xmlhttp = new XMLhttpRequest();
}else{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("post","http://localhost:8080/api",true);//true异步
xmlhttp.send();
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
console.log(xmlhttp.responseText);
}
}
}
9.call apply bind区别 call和apply功能:改变this的指向,区别:传参列表不同
call需要把实参按照形参的个数传进去
apply需要传一个arguments
注意这里apply()的第一个参数是null,在非严格模式下,第一个参数为null或者undefined时会自动替换为指向全局对象
bind()的作用与call()和apply()一样,都是可以改变函数运行时上下文,区别是call()和apply()在调用函数之后会立即执行,而bind()方法调用并改变函数运行时上下文后,返回一个新的函数,供我们需要时再调用。
10.this指针问题 1.函数预编译过程 this —> window
预编译 arguments在AO里(函数中使用严格模式,this --> undefined )
2.全局作用域里 this —> window
3.call/apply 可以改变函数运行时this指向
4.obj.func(); func()里面的this指向obj
var num = 1;
var o = {
num:2,
print:function(){
this.num = 3;
(function(){
console.log(this.num); //1
})();
console.log(this.num);//3
}
}
o.print();
javascript经典面试题整理
一.类型转换
var a = false + 1;
console.log(a); //1
var b = false == 1;
console.log(b);//false
if(typeof(a) && (-true) + (+undefined) + ''){
console.log('通过了');
}
// typeof(a) --> 'undefined'
// -true --> -1 +undefined --> NaN
// -1 + NaN-->NaN NaN + '' --> 'NaN'
if(1+5*'3' === 16){
console.log('通过了');
}
console.log(!!' ' + !!'' + !!false ||'未通过');//1
window.a || (window.a = '1');
//()优先级高,先给a赋值,然后进行判断,window.a=='1',为true返回
二.
var fn = (
function test1(){
return '1';
},
function test2(){
return '2';
}
)();
console.log(typeof(fn));//string
var a = 10;
if(function b(){}){//不是false,所以为true
a += typeof b;//(function b(){})函数声明被()包含生成表达式,b被忽略
}
console.log(a);//'10undefined'
三.
var name = 'ddd';
name += 10;
var type = typeof name;
//如果想要输出string var type = new String(typeof name);
if(type.length === 6){
type.text = 'string';
}
console.log(type.text);//undefined
var x = 1,
y = z = 0;
function add(n){
return n = n + 1;
}
y = add(x);
function add(n){//预编译,将前面的add覆盖
return n = n + 3;
}
z = add(x);
console.log(x,y,z);//1,4,4
function test(x,y,a){
a = 10;
console.log(arguments[2]);//10 映射关系
arguments[1] = 9;
console.log(y);//9
}
test(1,2,3);
四.
var name = '222';
var a = {
name:'111',
say:function(){
console.log(this.name);
}
}
var fun = a.say;
//var fun = fuunction(){console.log(this.name)} this指向window
fun();//222
a.say();//111 对象里面的方法,this指向a
var b = {
name:'333',
say:function(fun){
fun();
}
}
b.say(a.say);//222 this指向window
b.say=a.say;
// b.say=fuunction(){console.log(this.name)}
b.say();//333
function Foo(){
getName = function(){//未经过var的变量会提升到全局,会把之前的getName覆盖
console.log(1);
}
return this;
}
Foo.getName = function(){
console.log(2);
}
Foo.prototype.getName = function(){
console.log(3);
}
var getName = function(){
console.log(4);
}
function getName(){
console.log(5);
}
Foo.getName();//2
getName();//4
Foo().getName();//1
getName();//1
new Foo.getName();//2 .运算优先级高于new
new Foo().getName();//3 new Foo()先执行
new new Foo().getName();//3