1.JavaScript有几种类型的值?以及内置对象
-
栈:原始数据类型(Undefined,Null,Boolean,Number、String、symbol)
-
堆:引用数据类型(object、array、function) 两种类型的区别是:存储位置不同; 原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储; 引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定,如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体
-
Object 是 JavaScript 中所有对象的父对象 数据封装类对象:Object、Array、Boolean、Number 和 String 其他对象:Function、Arguments、Math、Date、RegExp、Error
2.如何判断数据类型?
推荐使用Object.prototype.toString方法进行数据类型判断,因为typeOf不能准确的判断出复杂数据类型,instanceOf只能判断复杂数据类型,constructor属性容易被篡改。
使用该方法我们可以封装一个isType方法来对类型进行判断
const type = (o) => {
let s = Object.prototype.toString.call(o);
return s.match(/\[object (.*?)\]/)[1].toLowerCase();
};
[
'Undefined',
'Null',
'String',
'Number',
'Boolean',
'Object',
'Array',
'Function',
'RegExp'
].forEach((t) => {
type['is' + t] = (o) => {
return type(o) === t.toLowerCase();
};
});
type.isObject({});
type.isArray([]);
3.一道闭包和运算符优先级的面试题?
var a=0,b=0;
function A(a){
A = function(b){
alert(a+b++);
}
alert(a++);
}
A(1); //1
A(2); //4
- A(1)变量A被赋值的funtion的内部有调用变量a,形成闭包alert(1)后,内容中的a存在并变成了2,所以A(2)结果为4。
4.设计一个异步任务类 Task?当任务函数执行 next 的时候,会跳转到下一个任务函数执行
class Task {
constructor() {
this.taskIndex = 0
this.taskList = []
this.stopRun = false
}
add(fn,context, ...args) {
const next = () => {
this.taskIndex++
if (!this.stopRun && this.taskList[this.taskIndex]) {
this.run()
}
}
this.taskList.push(fn.bind(context, next, ...args))
return this
}
run() {
this.taskList[this.taskIndex]()
}
stop() {
this.stopRun = true
}
}
function task1(next) {
setTimeout(() => {
console.log(1)
next()
},1000)
}
function task2(next,b) {
setTimeout(() => {
console.log(b)
next()
},1000)
}
let task = new Task()
task.add(task1).add(task2,null,3)
task.run()
5.ES6箭头函数this问题?
var name = 'window';
var obj1 = {
name: 'obj1',
fun1() {
console.log(this.name);
},
fun2: () => {
console.log(this.name);
},
fun3() {
return () => {
console.log(this.name);
}
},
fun4: () => {
return () => {
console.log(this.name);
}
}
};
obj1.fun1(); //obj1
obj1.fun2(); // window
obj1.fun3()(); //obj1
obj1.fun4()(); //window
非箭头函数和箭头函数的this指向区别:非箭头函数this的指向不是函数被创建时绑定,而是被怎么样的方式调用时绑定的。而箭头函数刚好相反,箭头函数的this指向是函数被创建时绑定的,它的指向就是当前词法作用域中的this,并且不会因为被怎么样的方式调用改变绑定。所以箭头函数的this指向关键是判断其定义时的词法作用域环境是哪个对象。
6.Array()和Array.of()区别?
Array(); //[]
Array(3); //[ , , ]并不是[3]
Array(1, 2, 3); //[1, 2, 3]
- Array方法没有参数、一个参数、三个参数时,返回结果都不一样。只有当参数个数不少于 2 个时,Array()才会返回由参数组成的新数组。参数个数只有一个时,实际上是指定数组的长度。
Array.of(); //[]
Array.of(3); //[3]
Array.of(1, 2, 3); //[1, 2, 3]
- 相对于Array方法,Array.of()在没有参数、一个参数、三个参数时,返回的都是数组,完全可以替代Array方法。
7.js获取宽高位置的常见方式区别?clientWidth,offsetWidth,scrollWidth
下面是css盒子模型图,css样式如下:
div {
width: 100px;
height: 100px;
padding: 10px;
border: 10px solid #ccc;
margin: 10px;
box-sizing: content-box;
}
以此div为例,我们说下几种获取宽高方式的区别:
- clientWidth(120) = width + 左右padding;
- clientHeight(120) = height + 上下padding;
- clientLeft(10) = border-left(左边框厚度);
- clientTop(10) = border-top(上边框厚度);
- offsetWidth(140) = width + 左右padding + 左右boder;
- offsetHeith(140) = height + 上下padding + 上下boder;
- offsetTop:当前元素上边框外边缘到第一个已定位父级(offsetParent)上边框 内边缘的距离。一直往上找,如果父级都没有定位,则分别是到body顶部的距离。offsetLeft类似;
- scrollWidth:获取指定标签内容层的真实宽度(可视区域宽度+被隐藏区域宽度)当前元素的scrollWidth可以理解为横向滚动条宽度;scrollHeight类似。
- scrollTop :内容层顶部 到 可视区域顶部的距离;
- scrollLeft:内容层左端 到 可视区域左端的距离;