同源策略
同源策略可以防止javascript发起跨域请求,此策略可以防止页面上的恶意脚本利用该页面的文档对象模型去访问另一个网页敏感数据
跨域
1 什么原因导致了跨域
浏览器的同源策略导致了跨域
2 跨域如何解决
服务器上设置代理页面
iframe嵌套通讯 window.postmessage
jsonp
反向代理
JSONP
https://blog.csdn.net/hansexploration/article/details/80314948
域名收敛
域名收敛是将静态资源全部放到一个域名下,减少dns解析的消耗
域名发散
域名发散就是将静态资源放到多个子域名下,这样就可以多线程下载,提高并行度 使网页加载速度更快
事件绑定的方式
嵌入dom
<button onclick="a()"></button>
- 直接绑定
btn.onclick = function(){}
事件监听
btn.addEventListener("click",function(){
})
事件委托
事件委托就是利用事件监听时的冒泡机制,只定义一个事件处理程序 让它来管理所有的同类型的事件
事件循环
事件循环是一个单线程循环,它用来监视调用堆栈,并检查是否有任务在队列中完成。若调用堆栈为空,且在队列中发现回调函数,在将其移出队列放到调用堆栈中执行
如何自定义事件
原生js提供了三个方式来自定义事件
1 createEvent 设置事件类型 是html事件还是鼠标事件
2 initEvent 初始化事件
3 dispatchEvent 触发事件
target和currentTarget区别
target是触发事件的元素
currentTarget是绑定事件的元素
prototype和__proto__的关系是什么
每一个对象都有一个__proto__属性 ,它指向的是该对象的构造函数的prototype属性
let obj = {}
obj.__proto__ === Object.prototype // true
function Test(){}
test.__proto__ == Test.prototype // true
每一个函数都同时拥有prototype和__proto__,__proto__指向的是该构造函数的实体,prototype由于是一个对象,所以它也有自己的__proto__属性,指向Object.prototype
function func() {}
func.prototype.__proto__ === Object.prototype // true
Object.prototype.__proto__指向null
原型继承
所有的js对象都有一个prototype属性,它指向该对象的原型,当我们要访问该对象的某个属性时,它便会到其原型上去寻找,若原型上没有则到其原型的原型上去找,直到找到为止,若没有找到则返回null,这一条层层寻找的链条便称为原型链
Ajax
ajax是一种用来开发异步web的技术,可以异步向后台服务器进行数据交互,而不影响原网页内容的呈现,通过将数据交换层和表现层分离,它允许我们动态的改变网页的内容而不用从新加载,它所使用的数据格式通常为json,事实上,现在都将json来替换xml,因为json和js有更好的交互性,它更容易被js语言解析
使用Ajax的优缺点分别是什么
优点
首先ajax可以承担一部分有服务器来承担的压力,它可以减轻服务器的消耗,
它状态可以维护在一个页面上,dom和页面内容不会被重新加载和改变
无刷新操作,这也是最重要的一点,使得它的用户体验性更好
优化了浏览器和服务器之间的数据传输,减少了不必要的数据往返
缺点
它不容易被搜索
如果js被禁用 ajax也会被禁用
它暴露了与服务器交互的细节
破坏了程序的异常机制‘不支持浏览器back按钮
Ajax和Fetch区别
ajax是由xmlhttprequst对象发起的,但是使用起来较为复杂,需要定义大量代码,而fetch是es6新增,使用起来比较简洁方便,
但是也有缺点
1 首先fetch它无法取消一个请求
2 fetch无法原生实时监听一个请求发送的进度,而xmlhttprequst可以
3 fetch只对网络请求报错 像400 500这种状态 都认为是请求成功,所以我们需要自己对其进行封装处理
4 fetch默认不接受会发送cookie
5 fetch兼容性没有ajax好,因为它是es6新增,注定无法适应于所有浏览器
变量提升
使用var声明的变量可以触发变量提升,也就是说它可以在变量声明之前输出,虽然这会输出undefined,但是不会报错,若对声明变量进行了赋值,还是一样,在声明赋值前调用还是输出undefined 因为预编译阶段只对声明变量提升,而不执行,赋值需要在执行阶段才会赋值
使用let、var和const创建变量有什么区别
使用var声明的变量会进行声明提升,被提升到当前作用域的顶部,可以在声明之前调用,不会报错,但是若用let和const在声明之前调用则会报错,var声明的变量可以进行多次重复声明,但let和const只能声明一次,重复声明将会报错,另外,let和const是块级作用域,这意味着它只能在最近一组花括号中使用例如if else等,而var声明的变量作用域是当前执行的上下文,它可以是嵌套的函数内部,也可以是任何函数外的变量
var a;
var a = 10;
console.log(a)//10
let b;
let b;//报错
const c;
const c;//报错
console.log(a)//报错
let a = 10
console.log(a)//报错
const a = 10
if(true){
var a = 10;
let b = 10;
const c = 10;
}
console.log(a)//10;
console.log(b)//报错
console.log(c)//报错
另外 let可以允许多次赋值 而const只允许赋值一次
let a = 10;
a = 20;
a = 30;
console.log(a)//30
const a = 10;
a = 20//报错
对象浅拷贝和深拷贝有什么区别
js中的数据类型分为两种 一种是基本数据类型 一种是引用数据类型,基本数据类型我们对齐进行拷贝时,拷贝的是它的值,
而引用数据类型我们对齐拷贝时,拷贝的是它的引用地址,也就是说会出现下面这种情况
var a = b = {
name:"zhangsan"
}
console.log(a.name,b.name)//输出两次张三
a.name = "lisi"
console.log(a.name,b.name)//输出两次lisi
可以看多,我们只改变了a的值,但是b的值也会跟着改变,这是因为拷贝引用数据类型拷贝的是它们的引用地址,所以当我们改变a和b中任意一个时,另外一个也会跟着改变,因为它们都指向同一个地址
浅拷贝和深拷贝就是在种情况下区分开来
当我们拷贝引用数据类型时,只拷贝它的引用地址,而不创建一个新的对象,那么我们便认为它是浅拷贝
若我们创建了一个新的对象,并且将被拷贝对象的成员全都复制到新对象上,那么便认为他是深拷贝
常见的深拷贝方式有下面两种
var a = {
name:"zhangsan"
}
var b = JSON.parse(JSON.stringify(a));
b.name = "lisi";
console.log(a.name)//zhangsan
console.log(b.name)//lisi
var a = {
name:"zhangsan"
}
function deepCopy(s){
const b = {};
for(let k in s){
if(typeof s[k]=="object"){
b[k] = deepCopy(s[k]);
}else{
b[k] = s[k]
}
}
return b
}
var b = deepCopy(a);
b.name="lisi"
console.log(a,b);//zhangsan lisi
数组去重
var a = [1,2,2,2,3,4,5,6,6,6,7,8,9]
function unique(array){
var temp = [];
array.forEach(e => {
if(temp.indexOf(e)==-1){
temp.push(e);
}
});
return temp;
}
console.log(unique(a));
//[1, 2, 3, 4, 5, 6, 7, 8, 9]
数据类型
Number
Object
String
Boolean
Undefined
null
symbol
内置函数(原生函数)
Number
Object
String
Boolean
symbol
Data
Function
Array
Regexp
error
如何判断数组与对象
var a = [];
var b = {};
console.log(Array.isArray(a));//true
console.log(Array.isArray(b));//false
console.log(Array.prototype == [].__proto__);//true
console.log(Object.prototype == {}.__proto__);//true
这里需要注意 不能使用typeof来判断 typeof判断不准确
console.log(typeof [])//object
console.log(typeof {})//object
自动分号
js会自动为代码补上缺失的分号,即ASI (自动插入分号),
因为缺失必要的分号会使代码不能正常执行
但需要注意,它只在代码换行出或代码结尾处补上缺失的分号,前提是结尾处理空格和注释外不能有其他内容
cookie、localStorage、sessionStorage区别
cookie长度只有4kb,存储在客户端,一般由服务端生成,若由服务端生成可以设置有效期,若由客户端生成则默认在浏览器关闭后清除
并且cookie每次都会携带在http请求头中,若我们在cookie中存放了大量的数据,那么页面重新加载时,cookie也会被重新发送,则就无形中浪费了带宽,这就会带来性能问题。
localStorage存储在客户端 长度5m,并且永久有效,除非我们手动删除它,并且它有自带的set或get等方法,而cookie需要我们开发者自己去封装,当然也并不是说cookie就毫无用处,它的主要作用是与服务器进行交互,作为http规范的一部分而存在,而localStorage仅仅是为了存储本地数据而已
sessionStorage和localStorage相似,只不过它存储的是session会话级别的数据,只在同一会话页面才能访问,会话结束后就会删除
自执行函数?用于什么场景?好处?
自执行函数的作用在于可以创建一个新的作用
它的好处是可以防止变量扩散到全局,并且可以避免各种js库互相冲突,并且可以隔离作用域链。还能避免闭包所导致的引用变量无法被释放的问题。
多个页面之间如何进行通信
cookie
localStorage
css动画和js动画的差异
js动画的可控性好,我们可以对它进行取消,暂停,继续等操作,而css动画无法添加事件
就性能上,css动画比js动画性能要好得多,因为js动画还需要解析后再执行
new一个对象经历了什么
1 创建一个新的对象
2 将新对象的构造器属性改为构造函数名,并将它的proto指向构造函数prototype属性
3 将this指向为新对象
4 将初始化的新对象的地址保存到等号左边的变量中
新创建的对象由this所引用,最后在隐式的返回this
bind、call、apply的区别
call和apply的作用相同,都是改变一个函数或对象的运行环境,也就是改变this指向,唯一不同的就是call传递参数是按顺序一个个传递,而apply则是以数组的形式传递
bind的作用也是改变this指向,但bind不是在调用时生效,而是返回一个新的函数
请简述JavaScript
中的this
1 若是用new关键字调用的,那么this将指向一个全新的对象
2 如果是使用call或apply方法来调用或创建的函数,那么它内部的对象将指向该方法传入的参数
3 若函数是作为某个对象的方法而存在,那么该函数的this就指向调用它的对象列如 obj.fristName()
4 若不符合上述任何规则 则this指向全局,在严格模式下,this指向undefined
5 若使用箭头函数,则上述所以规则作废,this指向创建时的上下文 而非调用时的上下文
如何确定this指向
1 若有new关键字调用 this指向新创建的对象
2 若有call或apply来调用 this指向所以指定的对象
3 若由上下文调用,则绑定到上下文对象
4 若有箭头函数创建 则指向创建时的上下文,而非调用时的上下文