自行整理面试知识(JS篇)(一)

AMD CMD CommonJS

AMD是来自于require.js的对模块化的定义

CMD是来自于sea.js的对模块化的定义

Commonjs是来自于Nodejs的对模块化的规范

AMD讲求依赖关系前置,即在定义模块的之前要求其先声明依赖的模块

CMD讲求依赖就近,即随用随声明即可。

前者实际上是为了能异步加载模块所进行的模块化定义,所以前者的用户体验会比较好。

后者放松了AMD的规范,对于开发会更加容易理解,且能够做到按需加载(用户用的时候再进行加载),所以性能会比较好

由于如今webpack等打包工具的出现,前端开发过程中也开始使用commonJS,所以如今require.js和sea.js使用得愈发少了,

Nodejs基于commonJS的规范开发。

阻止默认行为

e.preventDefault();与 window.event.returnValue = false;

多用于阻止a标签跳转,阻止浏览器默认右键,解决Safari的橡皮筋问题

阻止冒泡

e.stopPropagation();与window.event.cancelBubble = true;

用处可多了,父元素托管公用事件,子元素写独特事件的情况下就要取消子元素事件的冒泡行为

React中事件是托管在顶层元素document上以增强性能的,需要用React原生的取消冒泡事件             (e.nativeEvent.stopPropagation())或者stopImmediatePropagation()【阻止任何相同的事件的监听器被调用】取消事件

闭包问题

参考作者博客https://blog.csdn.net/u012312705/article/details/81749777

闭包的主要应用是缓存变量,封装局部变量避免被JS的垃圾回收机制回收,防止变量污染

原型链

所有的引用类型都有_proto_的隐式原型

所有的函数都有prototype的显式原型

prototype其实就是函数的一个实例化对象

_proto_就是他构造函数的prototype也就是其实例化对象

当调用某种方法或属性的时候,首先会查找自身prototype,找不到会查找其_proto_,再找不到继续向上找_proto_,直到来到原型链顶端null。

注意Function的构造器是Object噢。

主要的考察方式是考察new时发生了什么;

先创建一个空的Object对象 var obj = {};

将该对象的构造函数原型(_proto_)与其构造函数的原型(prototype)连接起来(定义都一样不连怎么行)

obj.__proto__ = ClassA.prototype;

然后把自己的this交给新对象(也就是用新的对象调用一次构造函数,让构造函数把this指针给他,从而继承来自实例的方法和属性)【是不是很像super()】ClassA.call(obj);(在这个时候就是传递给他自身this里所包含的属性和方法的时候)

异步(Promise与async/await)

Promise顾名思义就是承诺,承诺能拿到数据,没拿到数据就抛出reject,拿到了就抛出resolve(这么说可能不大对,实际上reject是resolv的变形,即resolve(null,reject))

Promise可以让你逃离回调地狱,因为then的链式调用中,每次都会返回Promise对象,可以让原本难以维护的回调函数得到解放,多用于AJAX得到数据后处理以及数据库查询时(Nodejs)使用

使用then捕获resolve,使用catch捕获reject

后者则是ES7的新语法,声明一个函数为异步函数,他不会阻塞后面代码的运行,同时async实际上返回的是一个Promise对象,在async函数中用return返回一个值会自动调用resolve,用throw会自动调用reject,当然可以用then和catch分别捕获

await只能在async函数中声明,await声明的函数会变为Promise对象(应当在await后面直接声明Promise),直到async函数中的所有await运行完后,才会进行状态的改变

注意一旦有一个await抛出错误,就会导致后面的所有await不执行,这个时候可以用try-catch把所有await包裹起来以捕获错误

原生AJAX

四步五步走

先创建XMLHttpRequest对象 (let ajax = new XMLHttpRequest())

get方法:

使用open设置请求的类型(get),请求的url(url可以带参数),是否异步

ajax.open('get','url');

发送请求(ajax.send())[注意兼容性问题,如果不发送数据,ie会报错,所以这里一般是要发送null或者""]

监听状态

ajax.onreadystatechange = ()=>{

if(ajax.readyState == 4 && ajax.status == 200){

//得到数据ajax.responseText()

}

}

post方法下,需要设置请求头

ajax.setRequestHeader("Content-type","application/x-www-form-urlencoded")(响应对象类型,这里的意思是用这种编码方式封装form),注意在传递file的时候需要换成multipart/form-data(你的form也得加上这个,form的enctype的默认值是前者)

其余的跟get无变化

跨域请求

同源策略:端口,域名,协议相同才能发起数据请求

一般的做法是jsonp,即用script标签包裹json的一种传递方式,因为浏览器对script标签就像对img标签一样,是没有资源限制的,所以你通常可以在服务器为数据包裹上用你自己设置的回调函数,再在js下动态添加script标签从而请求到json数据,回调函数就会运行,从而在回调函数里处理数据。

jsonp不能使用post方式,同时想要监听其是否失败比较麻烦,一般使用超时鉴定。

其次可以使用服务器代理,即服务器帮你完成这次请求的操作。

domain跨域,按照说法只能跨越同一级域名的子域,即兄弟之间的交流,在设置了document.domain之后,可以利用ajax访问其数据,小广告特别喜欢用domain+iframe或者CORS进行跨域拿到广告内容呢

CORS:simple Request下,即不添加自己自定义的请求头,且只使用get,post,head方法的情况下,且Content-Type是application/x-www-urlencoded,multipart/form-data,text/plain三种之一,只需要在服务器响应头中添加Acess-Control-Allow-Origin且使其包含请求的域,即可进行跨域请求。

app.all('/test', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header('Access-Control-Allow-Headers', 'Content-Type');
    next();
});

非simple Request下,即不满足上述情况,则需要向请求的服务器做一次预验证(preflighted),查看对方服务器是否支持请求所在域(Acess-Control-Allow-Origin),是否支持请求的方式(Acess-Control-Allow-Methods),是否支持请求的头(Acess-Control-Allow-Header)【CORS协议默认支持Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,这里是为了使其支持异步AJAX请求】

同时两种请求不同的地方还在于其验证的过程,前者是直接拿到响应再做对ACAO的解析,不满足直接丢弃数据,后者是先做一次预验证,不满足是不会发送真正的数据请求的。

解构赋值

解构赋值在针对伪数组(arguments等)中应用得较多,以前主要是用Array.prototype.slice.call()或者Array.from()来解决,现在可以直接用(...arg)=>{}来接收参数数组了,当然([x,y])=>{}也可以把传入的数组的前两个添加变量名xy。

同样的解构赋值在深拷贝中用得比较多,特别是Redux,由于其保证store的不变性,不对store的变量本身进行修改,所以需要复制一个新的数组,在新数组上进行修改,再返回给原来的数组,直接做替换。以前是用Object.assign({},数组)或者concat的方式来进行数组的克隆,现在可以直接使用[...oldArray] = newArray的方式克隆数组了 

深拷贝和浅拷贝的原生实现也是经常被问到的,留待下一章在做详解

const/let

老生长谈,主要是有可能会让你讨论实现手段。

let的实现手段及其原理:https://blog.csdn.net/u012312705/article/details/81750557 作者博客

const并非声明常量,而是声明一个不变的地址指针,并给他取了个名字,这个指针的指向是不能被改变的(所以要求初始化,实际上是要求初始化内存地址指针),但是他指向地址存放的值时可以更改的,更应当称其为常量索引

经典的栗子比如 const a = []; a.push("1");你看看a的值会不会改变,当然会咯,但是你要重复声明a(内存地址独一无二,所以其名字自然也独一无二)或者修改其指针再来一次a = [],这时候就会被报错啦。

 

你可能感兴趣的:(前端,javascrpit,面试,js,前端)