1.什么是跨域?解决跨域的方法?
跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制。
同源策略
- ——是浏览器安全策略
- ——协议名、域名、端口号必须完全一致
- 举例:
http://www.123.com/index.html 调用 http://www.123.com/server.php (非跨域)
http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域)
http://abc.123.com/index.html 调用 http://def.123.com/server.php (子域名不同:abc/def,跨域)
http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)
http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/https,跨域)
请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。
浏览器执行javascript脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行
跨域
- 违背同源策略就会产生跨域
解决方法
- jsonp cors websocket Node中间件代理(两次跨域) ngix反向代理...
小提示:如果你回答跨域解决方案CORS,那么面试官一定会问你实现CORS的响应头信息Access-Control-Allow-Origin。
1. jsonp方法
所以JSONP的原理其实就是利用引入script不限制源的特点,把处理函数名作为参数传入,然后返回执行语句,仔细阅读以下代码就可以明白里面的意思了。
补充:1) JSONP和AJAX对比
JSONP和AJAX相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式。但AJAX属于同源策略,JSONP属于非同源策略(跨域请求)
2)JSONP优缺点
SONP优点是简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具有局限性,不安全可能会遭受XSS攻击。
<script>
//创建 script 标签
var script = document.createElement('script');
//设置回调函数
function getData(data) {
//数据请求回来被触发的函数
console.log(data);
}
//设置script的src属性,设置请求地址
script.src = 'http://localhost:3000?callback = getData';
//让script生效
document.body.appendChild(script);
</script>
2. cors(跨域资源共享 Cross-origin resource sharing)
允许浏览器向跨域服务器发出XMLHttpRequest请求,从而克服跨域问题,它需要浏览器和服务器的同时支持。
- 浏览器端会自动向请求头添加origin字段,表明当前请求来源。
- 浏览器端需要设置响应头的Access-Control-Allow-Methods,Access-Control-Allow-Headers,Access-Control-Allow-Origin等字段,指定允许的方法,头部,源等信息。
- 请求分为简单请求和非简单请求,非简单请求会先进行一次OPTION方法进行预检,看是否允许当前跨域请求。
只要同时满足以下两大条件,就属于简单请求
条件1:使用下列方法之一:
- GET
- HEAD
- POST
条件2:Content-Type 的值仅限于下列三者之一:
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器; XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
4. websocket
Websocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。WebSocket和HTTP都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。 同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。 原生WebSocket API使用起来不太方便,我们使用 Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
我们先来看个例子:本地文件socket.html向 localhost:3000 发生数据和接受数据
// socket.html
<script>
let socket = new WebSocket('ws://localhost:3000');
socket.onopen = function () {
socket.send('我爱你');//向服务器发送数据
}
socket.onmessage = function (e) {
console.log(e.data);//接收服务器返回的数据
}
</script>
// server.js
let express = require('express');
let app = express();
let WebSocket = require('ws');//记得安装ws
let wss = new WebSocket.Server({port:3000});
wss.on('connection',function(ws) {
ws.on('message', function (data) {
console.log(data);
ws.send('我不爱你')
});
})
总结:CORS支持所有类型的HTTP请求,是跨域HTTP请求的根本解决方案 JSONP只支持GET请求,JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。 不管是Node中间件代理还是nginx反向代理,主要是通过同源策略对服务器不加限制。 日常工作中,用得比较多的跨域方案是cors和nginx反向代理
2.什么是闭包?
- 密闭的容器,类似于set,map容器,存储数据的
- 闭包是一个对象,存放数据的格式:key:value 形成的条件:
- 函数嵌套
- 内部函数引用外部函数的局部变量 闭包的优点:
- 延长外部函数局部变量的生命周期 闭包的缺点:
- 容易造成内存泄漏 注意点:
- 合理使用闭包
- 用完闭包要及时清除(销毁)
3.axios是什么?怎么使用?描述使用它实现登录功能的流程?
(一).axios是什么?
- axios 是基于 promise 用于浏览器和nodejs的一个http客户端,主要用于向后台发送请求的,还有就是在请求中做更多控制。
- 支持 promise
- 提供了一些并发的方法
- 提供拦截器
- 提供支持CSRF(跨域请求伪造)
(二).axios fetch ajax(jquery)区别
- 前两者都是支持promise的语法,后者默认是使用callback方式
- fetch 本质上脱离的xhr 是新的语法(有自己的特性 默认不传cookie 不能像xhr这样 去监听请求的进度)
(三).怎么使用?
<script>
axios.get('').then(function(){
}).catch(function(){
})
axios.post('').then(function(){
}).catch(function(){
})
</script>
(四).描述使用它实现登录功能的流程?
3.const,var,let区别
4.new操作符原理解析
5.promise的回调机制
6.阻止冒泡,说说vue中事件的阻止冒泡以及原理
事件修饰符 在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在 methods 中轻松实现这点,但更好的方式是:methods 只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
为了解决这个问题, Vue.js 为 v-on 提供了 事件修饰符。通过由点(.)表示的指令后缀来调用修饰符。
- .stop
- .prevent
- .capture
- .self
- .once
<!-- 阻止单击事件冒泡 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件侦听器时使用事件捕获模式 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当事件在该元素本身(比如不是子元素)触发时触发回调 -->
<div v-on:click.self="doThat">...</div>
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 @click.prevent.self 会阻止所有的点击,而 @click.self.prevent 只会阻止元素上的点击。
7.基本数据类型
- 基本类型:null、undefined、boolean、number、string、symbol
- 引用类型:Object(Array,Date,RegExp,Function)
- tips: NaN 也属于 number 类型,并且 NaN 不等于自身。
那么问题来了,如何判断某变量是否为数组数据类型?
var obj = document.getElementsByTagName("div");
var arr = [1,2,3]
// 请问有几种方式可以确定arr是一个数组?
// 第一种方式:instanceof
instanceof运算符用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型上
console.log(arr instanceof Array); //true
console.log(obj instanceof Array); //false
console.log(arr instanceof Object); //true
console.log(arr instanceof Object); //true
// 第二种方式:查看构造函数
console.log(arr.constructor === Array); //true
console.log(obj.constructor === Array); //false
// 上面的方式写全为 arr._proto_.constructor === Array
// 第三种方式:转为字符串之后的结果
console.log(Object.prototype.toString.call(arr) === '[object Array]'); //true
console.log(Object.prototype.toString.call(obj) === '[object Array]'); //false
8.类型的判断
- Typeof
console.log(typeof 1); // number
console.log(typeof 'a'); // string
console.log(typeof true); // boolean
console.log(typeof undefined); // undefined
console.log(typeof function fn(){}); // function
console.log(typeof {}); // object
console.log(typeof null); // object
console.log(typeof []); // object
console.log(typeof new Error()); // object
tips:typeof 对于基本类型,除了 null 都可以显示正确的类型;对于对象,除了函数都会显示 object
- Object.prototype.toString
var number = 1; // [object Number]
var string = '123'; // [object String]
var boolean = true; // [object Boolean]
var und = undefined; // [object Undefined]
var nul = null; // [object Null]
var obj = {a: 1} // [object Object]
var array = [1, 2, 3]; // [object Array]
var date = new Date(); // [object Date]
var error = new Error(); // [object Error]
var reg = /a/g; // [object RegExp]
var func = function a(){}; // [object Function]
function checkType() {
for (var i = 0; i < arguments.length; i++) {
console.log(Object.prototype.toString.call(arguments[i]))
}
}
checkType(number, string, boolean, und, nul, obj, array, date, error, reg, func)
9.如果判断两个对象是否相等
先判断对象属性的长度是否相等,再判断每个属性的值是否相等
10.javascript两个变量互换值,你了解多少?
11.数组去重12种方法?
12.this指向问题?
this 的指向取决于函数以哪种方式调用:
- 作用函数调用:非严格模式下 this 指向全局对象,严格模式为 undefined
- 作用方法调用:this 指向调用函数的对象
- 构造函数调用:this 指向 new 创建出来的实例对象
- call()和apply:它们的第一个参数为 this 的指向
- 补充:箭头函数中的 this
function a() {
return () => {
return () => {
console.log(this)
}
}
}
console.log(a()()())
箭头函数其实是没有 this 的,这个函数中的 this 只取决于他外面的第一个不是箭头函数的函数的 this。在这个例子中,因为调用 a 符合前面代码中的第一个情况,所以 this 是 window。并且 this 一旦绑定了上下文,就不会被任何代码改变。
13. js 什么方法可以跳出循环
-
break;结束循环推荐使用
-
return 直接跳出方法,如果仅仅只想结束循环不建议使用,因其副作用是,这个方法不再执行
-
循环变量=最大值/最小值(看你循环是从高数字到低还是低到高,高到低设置成0,低到高设置成数组的length,该方法对for in语句无效)
//循环变量低到高
var arr=[1,2,3,4,5,6,7];
for(var i=0;i<arr.length;i++)
{
if(arr[i]==4)
{
//break; //方案1
//return; //方法后续代码不执行 方案2
i=arr.length; //方案3
}
console.log(arr[i]); //1,2,3
}
//循环变量从高到低
var arr=[1,2,3,4,5,6,7];
for(var i=arr.length-1;i>-1;i--)
{
if(arr[i]==4)
{
//break; //方案1
//return; //方法后续代码不执行 方案2
i=-1; //方案3
}
console.log(arr[i]); //7,6,5
}
//for in情况
//循环变量从高到低
var arr=[1,2,3,4,5,6,7];
for(var i in arr)
{
if(arr[i]==4)
{
break;//方案1
//return;//方法后续代码不执行 方案2
//方案3 对此不起作用
}
console.log(arr[i]); //1,2,3
}
14. JS 中的主要有哪几类错误?
- 1.SyntaxError解析错误
- 2.ReferenceError引用错误
- 3.RangeError范围错误
- 4.TypeError类型错误
- 5.URIError统一资源标识符函数错误
- 6.EvalError eval()函数执行错误
- 具体列子参照
15. JS中获取dom元素的方法?
- 1.getElementById() 最常用的通过元素的id属性来获取DOM元素
- 2.getElementsByTagName() 通过标签名获取DOM元素的一个集合
- 3.getElementsByName() 很少用,操作表单 通过元素名来获取DOM元素集合
- 4.querySelector() 通过合法的CSS选择器获取DOM元素 只获取第一个匹配的元素
- 5.querySelectorAll() 通过合法的CSS选择器来获元素,返回的是所有符合条件的,而不是第一个符合条件的元素
- 6.getElementsByClassName()
- 具体例子参照
16. 用纯JS编写一个程序来反转字符串
var str = "jquery";
str = str.split(""); //字符串转为数组,["j","q","u","e","r","y"]
str = str.reverse(); //数组反转, ["y","r","e","u","q","j"]
str = str.join(""); //数组转字符串,"yreuqj"
17. JS中如何将页面重定向到另一个页面?
* location.href //window.location.href ="https://www.xx.com/"
* location.replace //window.location.replace ="https://www.xx.com/"
18. JS中的Array.splice()和Array.slice()方法有什么区别?
var arr=[0,1,2,3,4,5,6,7,8,9]; //设置一个数组
console.log(arr.slice(2,7)); //2,3,4,5,6
console.log(arr.splice(2,7)); //2,3,4,5,6,7,8
//由此我们简单推测数量两个函数参数的意义,
slice(start,end)第一个参数表示开始位置,第二个表示截取到的位置(不包含该位置)
splice(start,length)第一个参数开始位置,第二个参数截取长度
var x=y=[0,1,2,3,4,5,6,7,8,9]
console.log(x.slice(2,5)); //2,3,4
console.log(x); //[0,1,2,3,4,5,6,7,8,9]原数组并未改变
//接下来用同样方式测试splice
console.log(y.splice(2,5)); //2,3,4,5,6
console.log(y); //[0,1,7,8,9]显示原数组中的数值被剔除掉了
slice 和 splice虽然都是对于数组对象进行截取,但是二者还是存在明显区别,函数参数上slice和splice第一个参数都是截取开始位置,slice第二个参数是截取的结束位置(不包含),而splice第二个参数(表示这个从开始位置截取的长度),slice不会对原数组产生变化,而splice会直接剔除原数组中的截取数据!
19. 如何在JS中动态添加/删除对象的属性?
var obj = {a:'1',b:'2'}
obj.c = '3';
console.log(obj,'1'); //{a:'1',b:'2',c:'3'}
delete obj.a
console.log(obj,'2'); //{b:'2',c:'3'}
20. 解释一下JS的展开操作符?
var mid = [3, 4];
var newarray = [1, 2, ...mid, 5, 6];
console.log(newarray); // [1, 2, 3, 4, 5, 6]
21. arr.flat(Infinity)数组扁平化
所谓数组扁平化就是将数组中并不规则的多维数组去除维度,使之变为一维数组。
let newArray = arr.flat(depth)
flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。 其中,depth指定要提取嵌套数组的结构深度,默认值为1。
但使用 Infinity 作为深度,展开任意深度的嵌套数组 For Example 将数组 var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10]; 扁平化并去除其中重复数据,最终得到一个升序且不重复的数组。
Array.from 转换为数组 new Set 数组去重 sort 数组或对象某个属性排序
Array.from(new Set(arr.flat(Infinity))).sort((a, b) => { return a - b })
22. JS 异步解决方案的发展历程以及优缺点
回调函数(callback)
setTimeout(() => {
// callback 函数体
}, 1000)
缺点:回调地狱,不能用 try catch 捕获错误,不能 return
回调地狱的根本问题在于:
- 缺乏顺序性: 回调地狱导致的调试困难,和大脑的思维方式不符;
- 嵌套函数存在耦合性,一旦有所改动,就会牵一发而动全身,即(控制反转);
- 嵌套函数过多的多话,很难处理错误。
ajax('XXX1', () => {
// callback 函数体
ajax('XXX2', () => {
// callback 函数体
ajax('XXX3', () => {
// callback 函数体
})
})
})
promise
Promise 就是为了解决 callback 的问题而产生的。
Promise 实现了链式调用,也就是说每次 then 后返回的都是一个全新 Promise,如果我们在 then 中 return ,return 的结果会被 Promise.resolve() 包装。
优点:解决了回调地狱的问题。
ajax('XXX1')
.then(res => {
// 操作逻辑
return ajax('XXX2')
}).then(res => {
// 操作逻辑
return ajax('XXX3')
}).then(res => {
// 操作逻辑
})
Async/await
async、await 是异步的终极解决方案。
优点是:代码清晰,不用像 Promise 写一大堆 then 链,处理了回调地狱的问题;
缺点:await 将异步代码改造成同步代码,如果多个异步操作没有依赖性而使用 await 会导致性能上的降低。
async function test() {
// 以下代码没有依赖性的话,完全可以使用 Promise.all 的方式
// 如果有依赖性的话,其实就是解决回调地狱的例子了
await fetch('XXX1')
await fetch('XXX2')
await fetch('XXX3')
}
23. 深浅拷贝
拷贝
首先可以通过Object.assign来解决这个问题。
let a = {
age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1
当然我们也可以通过展开运算符(…)来解决
let a = {
age: 1
}
let b = {...a}
a.age = 2
console.log(b.age) // 1
深拷贝
function cloneFn( sourse ){
var o = Object.prototype.toString.call(sourse).toLowerCase().indexOf("array")!==-1 ? [] : {};
for( var attr in sourse ){
if( (typeof sourse[attr] === "object") && sourse[attr] !== null ){
o[attr] = cloneFn( sourse[attr] ) ;
}else{
o[attr] = sourse[attr];
}
}
return o;
}
24. Object.is()与原来的比较操作符"==="、"==” 的区别?
-
==判等,会在比较时进行类型转换;
-
===判等(判断严格),比较时不进行隐式类型转换,(类型不同则会返回false);
-
Object.is 在===判等的基础上特别处理了NaN、-0和+0,保证-0和+0不再相同,但Object.is(NaN, NaN)会返回true。Object.is应被认为有其特殊的用途,而不能用它认为它比其它的相等对比更宽松或严格。
Object.is() //它用来比较两个值是否严格相等,与严格相等运算符(===)的行为基本一致。
Object.is('foo','foo') //true
Object.is({},{}) //false
// 与等号不同的是
+0 === -0 //true
NaN === NaN //false
Object.js(+0,-0); //false
Object.is(NaN,NaN); //true
25. 数组常用的方法
26. 用js递归的方式写1到100求和
方法一:
function add(num1,num2) {
var num = num1+num2;
if(num2+1>100) {
return num
} else {
return add(num,num2+1)
}
}
add(1,2);
方法二:
function add(num) {
if(num ==1) {
return num
} else {
return num + add(num -1)
}
}
add(100)
27. JS延迟加载的几种方式
- defer属性
- async属性
- 动态创建DOM方式
- 使用jQery的getScript方法
- 使用setTimeout延迟方法
- 让js最后加载 收录干货,戳戳戳
28. 希望获取页面中所有的checkbox怎么做?(不使用第三方框架)
let inputList = document.getElementsByTagName("input")
let len = inputList.length
let checkBoxList = []
while(len --){
if(inputList[len].type == "checkbox"){
checkBoxList.push(inputList(len))
}
}
29. Object.create 做了什么?
Object._create = function(obj) {
function F(){}; //创建了一个新的构造函数F
F.prototype = obj; //然后将构造函数F的原型指向了参数对象obj
return new F(); //返回构造函数F的实例对象,从而实现了该实例继承obj的属性
}
30. 浏览器禁用cookie该如何处理
一般会用到url重写的技术来进行会话跟踪,每一次你的交互,都会在url后面加上sid=xxx类似的参数。服务端会根据这种方式来识别用户。
31. 如何中断ajax请求?
种是设置超时时间让ajax自动断开,另一种是手动停止ajax请求,其核心是调用XML对象的abort方法,ajax.abort()