21、html5 有哪些新特性
-
拖拽释放(Drag and drop) API
-
语义化更好的内容标签(header,nav,footer,aside,article,section)
-
音频、视频 API(audio,video)
-
画布(Canvas) API
-
地理(Geolocation) API
-
本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失;
-
sessionStorage 的数据在浏览器关闭后自动删除
-
表单控件,calendar、date、time、email、url、search
-
新的技术 webworker, websocket, Geolocation
22、link和@import的区别:
- 从属关系区别 @import是 CSS 提供的语法规则,只有导入样式表的作用;link是HTML提供的标签,不仅可以加载 CSS 文件,还可以定义 RSS、rel 连接属性等。
- 加载顺序区别 加载页面时,link标签引入的 CSS 被同时加载;@import引入的 CSS 将在页面加载完毕后被加载。
- DOM可控性区别 可以通过 JS 操作 DOM ,插入link标签来改变样式;由于 DOM 方法是基于文档的,无法使用@import的方式插入样式。
23、防抖函数
//非立即执行版本
function debounce(func, wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args)
}, wait);
}
}
//立即执行版本
function debounce(func,wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
let callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
}
24、节流函数
//时间戳 立即执行版本
function throttle(func, wait) {
let previous = 0;
return function() {
let now = Date.now();
let context = this;
let args = arguments;
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}
}
//定时器 非立即执行版本
function throttle(func, wait) {
let timeout;
return function() {
let context = this;
let args = arguments;
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
25、常见状态码
100 Continue 继续
200 OK 正常返回信息
201 Created 请求成功并且服务器创建了新的资源
202 Accepted 服务器已接受请求,但尚未处理
301 Moved Permanently 请求资源被永久移动到新位置
302 Found 请求资源临时性重定向
303 See Other 临时性重定向,且总是使用GET请求新的url
304 Not Modified 自从上次请求后,请求的网页未修改过
307 Temporary Redirect 临时重定向。与302类似。使用GET请求重定向
400 Bad Request 服务器无法理解的请求格式,客户端不应当尝试使用相同的内容发起请求
401 Unauthorized 请求未授权
403 Forbidden 禁止访问
404 Not Found 找不到与URL相匹配的资源
500 Internal Server Error 服务器端错误
502 Bad Gateway
503 Service Unavailable 服务器暂时无法处理请求
26、let var const 区别
- var可以声明提前、let不能
- var可以重复定义、let不能
- let 是块级作用域 和 var函数作用域
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function() {
console.log(i);
};
}
console.log(a[1]()) //1
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function() {
console.log(i);
};
}
console.log(a[1]()) //10
//var 声明变量是全局的只有一个i,一直在发生改变,所有最终数组函数打印的都是同一个数
- 特别的for循环中,循环体和内部 i 不是同一个作用域
for(let i = 0; i<3;i++){
let i =1
console.log(i) // 1 1 1
}
- const 定义的变量并非全部不能修改 定义的变量包含基本变量和引用变量,引用变量不能修改地址 ,但是可以修改内容
- let在声明 变量之前 不能使用,成为暂时性死区
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
- typeof 也不是 百分百安全的操作
typeof x; // ReferenceError
let x;
console.log(typeof x) //undefiend
27、堆内存和栈内存
- 变量分为基本类型和引用类型
- 基本类型包括 Undefined、Null、Boolean、Number 和String, 引用类型包括Object
- 基本类型是存放在栈内存中,引用类型是存在于堆内存中
- 基本类型在当前执行环境结束时销毁(出栈即销毁),而引用类型不会随执行环境结束而销毁,只有当所有引用它的变量不存在时这个对象才被垃圾回收机制回收(V8 垃圾回收)。
- 对于引用数据类型是,将变量保存在栈内存中,指针指向堆内存地址,多以在使用的时候是先在栈内存中找到,然后寻找相应的堆地址
- 变量全局在整个应用的生命周期中从一打开就处于整个执行栈的最底层,所以难以释放对于垃圾回收的不利,也是少用全局变量的重要原因。
- 栈内存和栈数据结构 与 堆内存和堆数据结构是两种东西,但是机制类似
28、深拷贝、浅拷贝
如果B复制了A,当我们改变A的值时,如果B也发生了变化那就说明是浅拷贝,反之就是深拷贝。
var a = 1;
var b = a;
b = 2;
console.log(a); // a = 1
var obj1 = { a: 1, b: 2 };
var obj2 = obj1;
obj2.a = 3;
console.log(obj1.a); // obj1.a = 3
// 变量保存引用类型,只能保存到一个引用地址,变量与堆内存不直接绑定!
// obj1 和 obj2 都保存了同一个引用地址,指向同一个堆内存,所以堆内存改变会一起改变
var obj1 = { a: 1 };
var obj2 = obj1;
obj1 = null;
console.log(obj2); // obj2 = { a: 1 }
// 虽然前面 obj1、obj2 都保存了堆内存地址,但后面只有 obj1 把保存的值改成null,所以并不影响 obj2 保存的引用地址指向堆内存。
//序列化和反序列化
function deepClone(obj){
let _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj);
return objClone
}
let a=[0, 1, [2, 3], 4],
b=deepClone(a);
a[0]=1;
a[2][0]=1;
console.log(a); // [1, 1, [1, 3], 4]
console.log(b); // [0, 1, [2, 3], 4]
//迭代递归实现深拷贝
function deepClone(oldobj){
let newObj = oldObj instanceof Array ? [] : {};
for(let key in oldobj){
if(typeof oldobj[key] === 'object'){
newObj[key] = deepClone(oldObj[key])
}else{
newObj[key] = oldObj[key]
}
}
return newObj
}
let a=[1,2,3,4],
b=deepClone(a);
a[0]=2;
console.log(a,b);
29、垃圾回收
JS的垃圾回收机制是为了防止内存泄漏,就是间歇的不定期的寻找到不再使用的变量,并释放掉他们所指向的内存。
- 基础类型基本用完就回收
- 引用类型 当所有的引用对象都被回收,才被销毁
30、类型判断
- typeof
typeof 1 // "number"
typeof 'a' // "string"
typeof true // "boolean"
typeof undefined // "undefined"
typeof Symbol() // "symbol"
typeof 42n // "bigint"
可以识别基本数据类型,不能识别引用类型 2. instanceof 不能识别基本数据类型,但是可以识别引用数据类型object(除了null)、array、function
console.log(bool instanceof Boolean);// false
console.log(num instanceof Number);// false
console.log(str instanceof String);// false
console.log(und instanceof Object);// false
console.log(nul instanceof Object);// false
console.log(arr instanceof Array);// true
console.log(obj instanceof Object);// true
console.log(fun instanceof Function);// true
console.log(s1 instanceof Symbol);// false
- constructor null、undefined没有construstor方法,因此constructor不能判断undefined和null。
console.log(bool.constructor === Boolean);// true
console.log(num.constructor === Number);// true
console.log(str.constructor === String);// true
console.log(arr.constructor === Array);// true
console.log(obj.constructor === Object);// true
console.log(fun.constructor === Function);// true
console.log(s1.constructor === Symbol);//true
- object.property.toString.call
Object.prototype.toString.call(999) // "[object Number]"
Object.prototype.toString.call('') // "[object String]"
Object.prototype.toString.call(Symbol()) // "[object Symbol]"
Object.prototype.toString.call(42n) // "[object BigInt]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(true) // "[object Boolean]
Object.prototype.toString.call({a:1}) // "[object Object]"
Object.prototype.toString.call([1,2]) // "[object Array]"
Object.prototype.toString.call(new Date) // "[object Date]"
Object.prototype.toString.call(function(){}) // "[object Function]"