- 对 ajax 的理解,实现一个 ajax 请求 ```typescript // method GET POST function ajax(url, method, options) { let xhr = new XMLHttpRequest() xhr.open(method, url, true) xhr.opreadystatechange = function () { if (this.readyState !== 4) return if (this.status === 200) { handle(this.response) } else { console.error(this.statusText) } } xhr.onerror = function () { console.error(this.statusText) } xhr.responseType = ‘json’ for(let head in options) { xhr.setRequestHeader(head, options[head]) } xhr.send(null) }
// Promise 处理 function ajaxPromise(url, method, options) { return new Promise((resolve, reject) => { let xhr = new XMLHttpRequest() xhr.open(method, url, true) xhr.opreadystatechange = function () { if (this.readyState !== 4) return if (this.status === 200) { resolve(this.response) } else { reject(new Error(this.statusText)) } } xhr.onerror = function () { reject(new Error(this.statusText)) } xhr.responseType = ‘json’ for(let head in options) { xhr.setRequestHeader(head, options[head]) } xhr.send(null) }) }
17. JavaScript 为什么要变量提升?导致了什么问题
- 表现:当变量在声明前就可以访问到而不报错,这里的现象就是变量提升
- 造成变量提升的本质原因,是因为 **JS 代码存在解析执行上下文的过程 **。当访问一个变量时,会到当前执行上下文的作用域链中去查找,而作用域链会包含当前所有函数形参、所有的函数、所有的变量声明,这在代码解析时就已经创建好了
- 解析阶段:JS 检查语法,对函数进行预编译。解析会创建全局执行上下文,把函数、变量等都拿出来,变量先初始化为 undefined,函数先声明好可以使用
- 执行阶段:按照代码顺序依次执行
- 为什么会进行变量提升?
- 提高性能,提前解析会进行语法检查和预编译,能够提前报错、处理一些固定的变量。比如可以提前解析函数并为函数分配栈、提前为变量分配内存空间。解析过程还会为函数生成**预编译代码**,预编译时会统计变量和函数、代码压缩、取出注释空白等等
- 容错性更好,访问未定义的变量不会直接报错
- 总结
- 解析和预编译的过程中,变量提升可以提高性能,比如让函数可以提前为变量分配栈空间
- 变量提升可以提高 JS 代码的容错性,使用一些不规范的代码也可以正常执行
- 变量提升也会导致一些结构或者代码上的问题
- 现在一般建议要么就将变量提升到代码顶端,要么直接使用 ES6 的 let 和 const 变量
```typescript
var tmp = new Date();
function fn(){
console.log(tmp);
if(false){
var tmp = 'hello world';
}
}
fn(); // undefined,tmp 被内层的 tmp 覆盖了
- 什么是尾调用?使用尾调用有什么好处
- 尾调用指的是函数的最后一步调用另外一个函数。代码的执行是基于执行栈的,所以当一个函数调用另一个函数时,会保留当前的执行上下文,然后新建另外一个执行上下文加入栈中。使用尾调用,因为已经是函数的最后一步,因此不需要保留当前的执行上下文,从而节省内存,这就是尾调用优化。
- 但是 ES6 的尾调用优化只在严格模式下开启,正常模式无效
- ES6 模块与 CommonJS 模块有什么异同?
- ES6 Module 是静态引用,是对模块的引用,ES6 Module 只存只读,不能改变值,即指针的指向
- CommonJS 是动态引用,是对模块的浅拷贝。
- import 的接口是 read-only 只读状态。不能修改其变量值,即不能修改其变量的指针指向,但可以改变变量内部指针指向,可以对 CommonJS 重新赋值。但是对 ES6 Module 赋值会编译报错
- ES6Module 和 CommonJS 的共同点:都可以对引入的对象进行赋值。即对对象内部属性的值进行改变。但是不会修改到文件当中,只能修改内存中读取到的。也就是说如果还有其他的文件读取,那么读取到的还是初始值