JavaScript常见面试题

705 阅读9分钟

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