使用Ajax的优缺点分别是什么
优点
- 交互性更好。来自服务器的新内容可以动态更改,无需重新加载整个页面。
- 减少与服务器的连接,因为脚本和样式只需要被请求一次。
- 状态可以维护在一个页面上。JavaScript 变量和 DOM 状态将得到保持,因为主容器页面未被重新加载。
- 基本上包括大部分 SPA 的优点。
缺点
- 动态网页很难收藏。
- 如果 JavaScript 已在浏览器中被禁用,则不起作用。
- 有些网络爬虫不执行 JavaScript,也不会看到 JavaScript 加载的内容。
- 基本上包括大部分 SPA 的缺点。
https://github.com/yangshun/f...
Ajax和Fetch区别
- ajax是使用XMLHttpRequest对象发起的,但是用起来很麻烦,所以ES6新规范就有了fetch,fetch发一个请求不用像ajax那样写一大堆代码。
- 使用fetch无法取消一个请求,这是因为fetch基于Promise,而Promise无法做到这一点。
- 在默认情况下,fetch不会接受或者发送cookies
- fetch没有办法原生监测请求的进度,而XMLHttpRequest可以
- fetch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理
- fetch由于是ES6规范,兼容性上比不上XMLHttpRequest
变量提升
var会使变量提升,这意味着变量可以在声明之前使用。let和const不会使变量提升,提前使用会报错。
变量提升(hoisting)是用于解释代码中变量声明行为的术语。使用var关键字声明或初始化的变量,会将声明语句“提升”到当前作用域的顶部。 但是,只有声明才会触发提升,赋值语句(如果有的话)将保持原样。
使用let、var和const创建变量有什么区别
用var声明的变量的作用域是它当前的执行上下文,它可以是嵌套的函数,也可以是声明在任何函数外的变量。let和const是块级作用域,意味着它们只能在最近的一组花括号(function、if-else 代码块或 for 循环中)中访问。
function foo() { // 所有变量在函数中都可访问 var bar = 'bar'; let baz = 'baz'; const qux = 'qux'; console.log(bar); // bar console.log(baz); // baz console.log(qux); // qux } console.log(bar); // ReferenceError: bar is not defined console.log(baz); // ReferenceError: baz is not defined console.log(qux); // ReferenceError: qux is not defined
if (true) { var bar = 'bar'; let baz = 'baz'; const qux = 'qux'; } // 用 var 声明的变量在函数作用域上都可访问 console.log(bar); // bar // let 和 const 定义的变量在它们被定义的语句块之外不可访问 console.log(baz); // ReferenceError: baz is not defined console.log(qux); // ReferenceError: qux is not defined
var会使变量提升,这意味着变量可以在声明之前使用。let和const不会使变量提升,提前使用会报错。
console.log(foo); // undefined var foo = 'foo'; console.log(baz); // ReferenceError: can't access lexical declaration 'baz' before initialization let baz = 'baz'; console.log(bar); // ReferenceError: can't access lexical declaration 'bar' before initialization const bar = 'bar';
用var重复声明不会报错,但let和const会。
var foo = 'foo'; var foo = 'bar'; console.log(foo); // "bar" let baz = 'baz'; let baz = 'qux'; // Uncaught SyntaxError: Identifier 'baz' has already been declared
let和const的区别在于:let允许多次赋值,而const只允许一次。
// 这样不会报错。 let foo = 'foo'; foo = 'bar'; // 这样会报错。 const baz = 'baz'; baz = 'qux'; https://github.com/yangshun/f...
对象浅拷贝和深拷贝有什么区别
在 JS
中,除了基本数据类型,还存在对象、数组这种引用类型。
基本数据类型,拷贝是直接拷贝变量的值,而引用类型拷贝的其实是变量的地址。
let o1 = {a: 1} let o2 = o1
在这种情况下,如果改变 o1
或 o2
其中一个值的话,另一个也会变,因为它们都指向同一个地址。
o2.a = 3 console.log(o1.a) // 3
而浅拷贝和深拷贝就是在这个基础之上做的区分,如果在拷贝这个对象的时候,只对基本数据类型进行了拷贝,而对引用数据类型只是进行了引用的传递,而没有重新创建一个新的对象,则认为是浅拷贝。反之,在对引用数据类型进行拷贝的时候,创建了一个新的对象,并且复制其内的成员变量,则认为是深拷贝。
怎么实现对象深拷贝
let o1 = {a:{ b:1 } } let o2 = JSON.parse(JSON.stringify(o1))
另一种方法
function deepCopy(s) { const d = {} for (let k in s) { if (typeof s[k] == 'object') { d[k] = deepCopy(s[k]) } else { d[k] = s[k] } } return d }
数组去重
ES5
function unique(arry) { const temp = [] arry.forEach(e => { if (temp.indexOf(e) == -1) { temp.push(e) } }) return temp }
ES6
function unique (arr) { return Array.from(new Set(arr)) }
数据类型
- Undefined
- Null
- Boolean
- Number
- String
- Object
- symbol(ES6新增)
内置函数(原生函数)
- String
- Number
- Boolean
- Object
- Function
- Array
- Date
- RegExp
- Error
- Symbol
原始值 "I am a string" 并不是一个对象,它只是一个字面量,并且是一个不可变的值。
如果要在这个字面量上执行一些操作,比如获取长度、访问其中某个字符等,那需要将其
转换为 String 对象。
幸好,在必要时语言会自动把字符串字面量转换成一个 String 对象,也就是说你并不需要
显式创建一个对象。
如何判断数组与对象
Array.isArray([]) // true Array.isArray({}) // false typeof [] // "object" typeof {} // "object" Object.prototype == [].__proto__ // false Object.prototype == {}.__proto__ // true Array.prototype == [].__proto__ // true Array.prototype == {}.__proto__ // false
自动分号
有时 JavaScript 会自动为代码行补上缺失的分号,即自动分号插入(Automatic SemicolonInsertion,ASI)。
因为如果缺失了必要的 ; ,代码将无法运行,语言的容错性也会降低。ASI 能让我们忽略那些不必要的 ; 。
请注意,ASI 只在换行符处起作用,而不会在代码行的中间插入分号。
如果 JavaScript 解析器发现代码行可能因为缺失分号而导致错误,那么它就会自动补上分
号。并且,只有在代码行末尾与换行符之间除了空格和注释之外没有别的内容时,它才会
这样做。
浮点数精度
https://www.css88.com/archive...
cookie、localStorage、sessionStorage区别
特性 | cookie | localStorage | sessionStorage |
由谁初始化 | 客户端或服务器,服务器可以使用Set-Cookie 请求头。 |
客户端 | 客户端 |
数据的生命周期 | 一般由服务器生成,可设置失效时间,如果在浏览器生成,默认是关闭浏览器之后失效 | 永久保存,可清除 | 仅在当前会话有效,关闭页面后清除 |
存放数据大小 | 4KB | 5MB | 5MB |
与服务器通信 | 每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题 | 仅在客户端保存 | 仅在客户端保存 |
用途 | 一般由服务器生成,用于标识用户身份 | 用于浏览器缓存数据 | 用于浏览器缓存数据 |
访问权限 | 任意窗口 | 任意窗口 | 当前页面窗口 |
自执行函数?用于什么场景?好处?
自执行函数:1、声明一个匿名函数2、马上调用这个匿名函数。
作用:创建一个独立的作用域。
好处:防止变量弥散到全局,以免各种js库冲突。隔离作用域避免污染,或者截断作用域链,避免闭包造成引用变量无法释放。利用立即执行特性,返回需要的业务函数或对象,避免每次通过条件判断来处理
场景:一般用于框架、插件等场景
多个页面之间如何进行通信
有如下几个方式:
- cookie
- web worker
- localeStorage和sessionStorage
css动画和js动画的差异
- 代码复杂度,js 动画代码相对复杂一些
- 动画运行时,对动画的控制程度上,js 能够让动画,暂停,取消,终止,css动画不能添加事件
- 动画性能看,js 动画多了一个js 解析的过程,性能不如 css 动画好
https://zhuanlan.zhihu.com/p/...
如何实现文件断点续传
断点续传最核心的内容就是把文件“切片”然后再一片一片的传给服务器,但是这看似简单的上传过程却有着无数的坑。
首先是文件的识别,一个文件被分成了若干份之后如何告诉服务器你切了多少块,以及最终服务器应该如何把你上传上去的文件进行合并,这都是要考虑的。
因此在文件开始上传之前,我们和服务器要有一个“握手”的过程,告诉服务器文件信息,然后和服务器约定切片的大小,当和服务器达成共识之后就可以开始后续的文件传输了。
前台要把每一块的文件传给后台,成功之后前端和后端都要标识一下,以便后续的断点。
当文件传输中断之后用户再次选择文件就可以通过标识来判断文件是否已经上传了一部分,如果是的话,那么我们可以接着上次的进度继续传文件,以达到续传的功能。
有了HTML5 的 File api之后切割文件比想想的要简单的多的多。
只要用slice 方法就可以了
var packet = file.slice(start, end);
参数start是开始切片的位置,end是切片结束的位置 单位都是字节。通过控制start和end 就可以是实现文件的分块
如
file.slice(0,1000); file.slice(1000,2000); file.slice(2000,3000); // ......
在把文件切成片之后,接下来要做的事情就是把这些碎片传到服务器上。
如果中间掉线了,下次再传的时候就得先从服务器获取上一次上传文件的位置,然后以这个位置开始上传接下来的文件内容。
https://www.cnblogs.com/zhwl/...
new一个对象经历了什么
function Test(){} const test = new Test()
- 创建一个新对象:
const obj = {}
- 设置新对象的constructor属性为构造函数的名称,设置新对象的__proto__属性指向构造函数的prototype对象
obj.constructor = Test obj.__proto__ = Test.prototype
- 使用新对象调用函数,函数中的this被指向新实例对象
Test.call(obj)
- 将初始化完毕的新对象地址,保存到等号左边的变量中