标签(空格分隔): 面试题
[TOC]
(基础题目,比较细节,回答不全,可以稍作提示)
字符串,数字,布尔值,null,undefined五种基本数据类型,其他的全部属于Object
追问,ES6加入了一种新的基本数据类型,是什么,有什么用(难)
(ES6种比较冷的知识,可做加分题)
ES6种加入了一种新的基本数据类型Symbol
,提供一个独一无二的值,可以作为属性名,可以用来消除代码中的魔鬼数字等
ES6内部定义了一些Symbol值,用来作为内部属性名.
==
是不严格的相等,会做隐式类型转换,null == undefined
的结果是 true
===
是严格的相等,不会做隐式类型转换,null === undefined
的结果是 false
无论是==
还是===
都不能用来判断 NaN
(可做追问)
目前版本的JavaScript,这两个值的区别并不大.(一下的区别,回答一两点即可)
用 typeof
运算符得到的结果不一样,typeof null
得到object
,typeof undefined
得到undefined
.
null
表示空,undefined
表示没有初始值.
null == undefined
的结果是 true
,null === undefined
的结果是 false
最基础的方式,使用循环遍历实现(使用concat和apply来实现的比较好,使用for循环实现的细节把控不够)
追问:用一行代码实现,多种实现
var arr = [[1,2],[3,4],[5,6,7]];
// 使用Array的concat方法(标准方法)
var farr = [].concat.apply([],arr);
// 使用 reduce 方法实现(生僻方法,可加分)
var farr = arr.reduce(function(a,b){return a.concat(b)},[]);
// 使用ES6箭头函数写法,简化function(ES6知识点,可加分)
var farr = arr.reduce((a,b) => a.concat(b),[]);
// 使用reduceRight方法与reduce方法基本一样
// 使用ES6的 ... 运算符,告别apply(ES6知识点,可加分)
var farr = [].cancat(...arr)
call
和 apply
都用于修改函数运行时的this指向,
区别在于call
将第二个及之后的参数传给源函数,做为参数列表执行,
apply
的第二个参数是一个数组,这个参数在函数运行的时候会被打开,然后作为函数参数列表
call
,apply
在运行时改变this指向,调用后函数立即执行
bind
返回一个代理函数,需要手动调用,该函数在运行时使用bind
定义的this
指向
使用bind
生成的代理函数,无法再次使用call
,apply
,bind
修改this
指向(细节,加分)
追问:
一下代码,控制台会输出什么,为什么?
var a = 10;
function b(){
var a = 5;
console.log(this.a)
return function(){
console.log(a)
}
}
b()();
本题的考点为闭包
第一个console.log(this.a)
中,this
指向window,获取全局变量所以输出为10
第一个console.log(a)
中,这里的a
取的是函数定义时候的a
,所以输出为5
var length = 10
function fn(){
console.log(this.length);
}
var obj = {
length: 5,
method: function(fn) {
fn();
arguments[0]();
}
}
obj.method(fn);
本题考点为this
输出结果为 10,1
第一个fn()
调用时,this
指向window
,
第二个arguments[0]()
是难点,arguments是个对象,这里相当于调用对象的方法,this
指向arguments
写法多种多样
// 最常用的写法
(function(){})();
// 次常用的方法
(function(){}());
// 其他方法,在函数前加上任意的位运算符,都可以导致函数表达式立即生成函数,从而实现函数立即执行
+function(){}();
JSON字符串化再解析,实现一个简单的深度复制
追问:
- 如何解决函数的复制(难)
function的toString方法,会的到function得代码,用eval函数转换成函数
- 如何解决原型链的复制(难)
先获取原型,再将新的对象原型设置为原来的对象的原型
考点是Array
的sort
方法,默认是按照字符串来排序的,需要自己写一个sort的函数来实现排序
var arr = ["8","13","7","5","4","21","1","6"];
arr.sort((a,b) => a-b); // 这里包括了一个隐式类型转换
追问:
- 用递归实现(中等)
// 简单的递归,每次都要把之前的都算一遍,效率低下,复杂度高
function factirial(n){
if (n === 1) return 1;
return n * factirial(n -1);
}
- 优化递归实现(尾递归,加分)
// 尾递归实现,会被优化,但是需要一个额外参数
function factirial(n,total){
if (n === 1) return total;
return factirial(n-1,n*total);
}
- 使用curry化将函数变得优雅一些(加分)
// curring简单实现,这个function很简陋,只针对当前函数,用来示意一下
function currying(fn,n){
return function(m){
return fn.call(this,m,n);
}
}
function tailFactirial(n,total){
if (n === 1) return total;
return factirial(n-1,n*total);
}
var factirial = curring(tailFactirial,1);
// ES6参数默认值的方式,可以避免curry化
function factirial(n,total = 1){
if (n === 1) return total;
return factirial(n-1,n*total);
}
-
jQuery对象是一个类数组对象,使用选择器获取的DOM对象都被包装成jQuery对象,通过
[index]
方法,可以从jQuery对象中取出原生的DOM对象 -
DOM对象可以使用原生的dom方法,jQuery对象不可以使用原生dom方法,但是可以使用更加强大的jQuery方法
-
DOM对象可以使用 $(DOM对象)的方式包装成jQuery对象
-
window.onload
需要在页面所有元素全部加载结束才触发,包括图片下载,而且全局只能有一个,后写的会覆盖先写的 -
$(document).ready
通过多种检测,在页面dom结构完成时触发,不需要等到图片下载结束,触发速度更快,可以写多个
- 通过将事件绑定到父元素上,来代理子元素事件处理,可以减少绑定次数,同时可以处理后添加的DOM元素,不需要添加新的事件绑定
- 使用
trigger
方法
noConflict
方法,包括一个true
参数,可以把jQuery
也让出去
-
方法插件,通过
$.extends
来扩展jQuery的静态方法 -
原型插件,通过
$.fn.extentds
来扩展原型方法 -
写插件的时候可以做一个
noConflict
处理,避免将原有同名插件覆盖掉
-
同步的ajax并不建议使用,他会阻塞ajax请求,直到ajax返回,运行完回调函数才会之后的代码
-
异步的ajax调用后会立即执行后面的代码,ajax返回之后,会执行回调函数
-
jQuery的ajax中使用async参数来设置同步或者异步
使用节流函数来实现,实现思路是通过定时器的不断设定和取消,节流事件处理函数的运行.
提供了 let
和const
两种变量声明方式
追问:
- 与var的区别(中等,细节继续追问)
let
和const
属于块及作用域,var是函数及作用域,let
和const
声明的变量不能够重复声明
- 临时死区的概念(中等)
在作用域块中 let
和const
声明的变量,从块开始,到声明语句之间的地带,叫临时死区,在临时死区中,虽然不存在变量提升,但是如果使用了声明的变量,就会报错
- 对全局变量的影响(细节)
var 如果在全局中使用,会在全局挂载一个变量,如果原来有同名变量,则覆盖原来的变量,let
和const
在全局中使用,不会覆盖全局变量,只是遮盖他们
追问:
- 箭头函数中this的指向
箭头函数没有自己的this,在箭头函数中使用this调用的是外层的this
- 箭头函数中arguments是否可用
箭头函数中没有arguments变量,如果在一个普通函数内部使用,arguments指向外层函数的arguments
for...in...
用于遍历对象的属性,当遍历数组时,会把挂载在数组上的其他属性也遍历出来,遍历数组的键
for...of...
用于遍历数组,只遍历数组元素,不遍历数组上的其他属性,遍历数组的值
对于普通的对象for...of...
结构不能直接只用,必须部署Iterator接口,但是for...in...
循环依然可以遍历键名
-
可以用来打开数组,做数组的合并,代替apply方法
-
可以用来打开对象,做对象合并
-
可以用来设置rest参数
-
可以用来打开任何有Iteritor接口的对象
追问: 下面的代码,控制台依次输出什么?
function a({a,b} = {a:1,b:2}){
console.log(a);
console.log(b);
}
function b({a=1,b=2}){
console.log(a);
console.log(b);
}
function c({a=1,b=2} = {a:1,b:2}){
console.log(a);
console.log(b);
}
a(); // 1,2
a({a:2}); // 2,undefind
a({a:2,b:3}); // 2,3
b(); // 报错
b({a:2}); // 2,2
b({a:2,b:3}); // 2,3
c(); // 1,2
c({a:2}); // 2,2
c({a:2,b:3}); // 2,3
let arr = ["1","2","1","3","2"];
let dArray = Array.from(new Set(arr));