周口住房和城乡建设网站,怎么把视频弄成超链接,wordpress内部邮件插件,网站有收录就会排名吗#x1f308;个人主页#xff1a;前端青山 #x1f525;系列专栏#xff1a;JavaScript篇 #x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来JavaScript篇专栏内容:JavaScript全面指南 目录
61、如何防止XSRF攻击
62、如何判断一个对象是否为数组个人主页前端青山 系列专栏JavaScript篇 人终将被年少不可得之物困其一生 依旧青山,本期给大家带来JavaScript篇专栏内容:JavaScript全面指南 目录
61、如何防止XSRF攻击
62、如何判断一个对象是否为数组函数
63、JavaScript中如何使用事件处理程序
64、解释延迟脚本在JavaScript中的作用
65、实现一个函数clone可以对javascript中的5种主要数据类型进行值复制。
66、decodeURI和encodeURI是什么
67、解释JavaScript中的pop方法
68、解释什么是回调函数并提供一个简单的例子。
69、面向对象编程与面向过程编程的区别
70、eval是做什么的性能怎么样安全如何
71、函数节流、防抖
72、“use strict”的作用是什么
73、了解ES6 的 Proxy吗
74、深拷贝是什么
75、解释 JavaScript 中的 null 和 undefined。
76、解释 JavaScript 中的值和类型。
77、scroll resize 使用函数节流实现不要频繁触发事件的需求
78、解释事件冒泡以及如何阻止它
79、JavaScript 中的 let 关键字有什么用
80、 jQuery 优点和缺点 61、如何防止XSRF攻击
一 CSRF是什么 跨站请求伪造英语Cross-site request forgery也被称为 one-click attack 或者 session riding通常缩写为 CSRF 或者 XSRF 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。
二、CSRF的原理
三、CSRF的防范措施
1、验证 HTTP Referer 字段 HTTP头中的Referer字段记录了该 HTTP 请求的来源地址。在通常情况下访问一个安全受限页面的请求来自于同一个网站而如果黑客要对其实施 CSRF 攻击他一般只能在他自己的网站构造请求。因此可以通过验证Referer值来防御CSRF 攻击。
2、验证码。 验证码 利用验证码将用户收到的信息与后台服务器进行比对每次用户提交都需要用户在表单中填写一个图片上的随机字符串不符则进行拒绝。 3、添加token验证
CSRF攻击之所以能够成功是因为攻击者可以完全伪造用户的请求该请求中所有的用户验证信息都存在cookie中因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的cookie来通过安全验证。要防止CSRF关键在于在请求中放入黑客所不能伪造的信息并且该信息不存在于cookie之中。可以在HTTP请求中以参数的形式加入一个随机产生的token并在服务器建立一个拦截器来验证这个token如果请求中没有token或者token不正确则认为可能是CSRF攻击而拒绝该请求。 现在业界一致的做法就是使用Anti CSRF Token来防御CSRF。 用户访问某个表单页面。
服务端生成一个Token放在用户的Session中或者浏览器的Cookie中。
在页面表单附带上Token参数。
用户提交请求后服务端验证表单中的Token是否与用户Session或Cookies中的Token一致一致为合法请求不是则非法请求。
这个Token值必须是随机的不可预测的。由于Token的存在攻击者无法再构造一个带有合法Token的请求实施CSRF攻击。另外使用Token应注意Token的保密性尽量把敏感操作由GET改成POST以form或者AJAX形式提交避免Token泄露。
4、尽量使用POST限制GET
GET接口能够直接将请求地址暴露给攻击者所以要防止CSRF一定最好不要用GET。当然POST并不是万无一失攻击者只需要构造一个form表单就可以但需要在第三方页面做这样就增加了暴露的可能性。 62、如何判断一个对象是否为数组函数
在js中判断数据类型通常使用typeof但是typeof在判断数组和对象时的结果都是object。
那么怎么才能区分对象和数组呢 判断原型
var obj {};var arr [];console.log(arr);console.log(obj); 数组和对象的原型对象不一样由此可以通过判断原型来判断一个对象是否为数组var obj {};var arr [];console.log(Object.getPrototypeOf(obj) Object.prototype);console.log(Object.getPrototypeOf(obj) Array.prototype); 但是这种方法虽然通过检查原型来判断是否为数组不是特别稳定因为原型可以人为改变的一旦原型改变就可能会失效。var obj {};var arr [];Object.setPrototypeOf(obj, Array.prototype);console.log(Object.getPrototypeOf(obj) Object.prototype);//falseconsole.log(Object.getPrototypeOf(obj) Array.prototype);//true 此时arr的原型不是Array.prototype第一个返回的结果为false如此不能判断是否为数组。判断构造函数创建对象和创建数组的构造函数不同可以通过此种方法判断一个对象是否为数组。var obj {};var arr [];console.log(Object.getPrototypeOf(obj).constructor Object);console.log(Object.getPrototypeOf(obj).constructor Array); 由此可见两个输出结果并不一样并且也符合我们的认知通过此种方法也可以判断一个对象是否为数组。但该种方法与上一种方法的问题一样即当构造函数被修改之后就无法判断真正的数组。var obj {};var arr [];Object.getPrototypeOf(obj).constructor Array;console.log(Object.getPrototypeOf(obj).constructor Object);//falseconsole.log(Object.getPrototypeOf(obj).constructor Array);//trueconsole.log(Object.getPrototypeOf(arr).constructor Array);//true 由此可见该方法的缺点与上一种方法的一样。在判断构造函数方法中除了直接判断外还可以使用 instanceof 判断一个对象是否为一个构造函数的实例var obj {};var arr [];console.log(obj instanceof Array);//falseconsole.log(arr instanceof Array);//true 由此可见该方法也可以判断是否为数组。Array.isArray()通过Array.isArray()可以判断一个对象是否为数组。var obj {};var arr [];console.log(Array.isArray(obj));//falseconsole.log(Array.isArray(arr));//true 由此可见此种方法可行那么当我们把其构造函数改变后还会出现和上面一样的情况吗var obj {};var arr [];Object.getPrototypeOf(obj).constructor Array;//falseconsole.log(Array.isArray(obj));//trueconsole.log(Array.isArray(arr)); 由此可见即便将obj的构造函数改为Array也能判断出真正的数组。用Object.toString()方法判断var obj {};var arr [];console.log(obj.toString());//[object Object]console.log(arr.toString());// 由此可见对象是Object创建的但是数组的toString()返回的是空。这是因为js中每个对象都有toString()方法该方法继承自Object.toString()方法但数组被重写了但是我们可以使用call()来调用数组的toString的原始方法来判断。var obj {};var arr [];console.log(obj.toString());//[object Object]console.log(Object.prototype.toString.call(arr));//[object Array] 由此可见也可以通过此种方法判断一个对象是否为数组。那么如果改变构造函数是否会发生类似之前的情况呢var obj {};var arr [];Object.getPrototypeOf(obj).constructor Array;console.log(obj.toString());//[object Object]console.log(Object.prototype.toString.call(arr));//[object Array] 由此可见此时还能正常判断并不会发生此前出现的情况。
使用场景
判断一个对象是否为数组在什么地方使用呢
在进行克隆时需要判断对象的属性是否为数组根据结果采取不同的操作。
总结 判断原型和判断构造函数的方法的结果会因为原型和构造函数的改变发生改变并不十分稳定。 Array,isArray()和Object.toString()方法较为稳定较为推荐。 通常在进行克隆时会用到判断一个对象是否为数组。
63、JavaScript中如何使用事件处理程序
事件是由用户生成活动例如单击链接或填写表单导致的操作。需要一个事件处理程序来管理所有这些事件的正确执行。事件处理程序是对象的额外属性。此属性包括事件的名称以及事件发生时采取的操作。
64、解释延迟脚本在JavaScript中的作用
默认情况下在页面加载期间HTML代码的解析将暂停直到脚本停止执行。这意味着如果服务器速度较慢或者脚本特别沉重则会导致网页延迟。在使用Deferred时脚本会延迟执行直到HTML解析器运行。这减少了网页加载时间并且它们的显示速度更快。
65、实现一个函数clone可以对javascript中的5种主要数据类型进行值复制。
var clone function (type) {var o;var typeA typeof type;switch (typeA){case string:o typeA;break;case number:o typeA-0;break;case undefined:break;case boolean:o typeA;break;case object:if(typenull){o null;}else {if(Object.prototype.toString.call(type).slice(8,-1)Array){o [];for(var i 0;itype.length;i){o.push(clone(type[i]));}}else {o {};for(var key in type){o[key] clone(type[key]);}}}break;default:break;}return o;
}
66、decodeURI和encodeURI是什么
EncodeURl用于将URL转换为十六进制编码。而DecodeURI用于将编码的URL转换回正常。
67、解释JavaScript中的pop方法
pop方法与shift方法类似但不同之处在于Shift方法在数组的开头工作。此外pop方法将最后一个元素从给定的数组中取出并返回。然后改变被调用的数组。
例var cloths [“Shirt”, “Pant”, “TShirt”];
cloths.pop();
//Now cloth becomes Shirt,Pant
68、解释什么是回调函数并提供一个简单的例子。
回调函数是可以作为参数传递给另一个函数的函数并在某些操作完成后执行。下面是一个简单的回调函数示例这个函数在某些操作完成后打印消息到控制台。
function modifyArray(arr, callback) {// 对 arr 做一些操作arr.push(100);// 执行传进来的 callback 函数callback();
}
var arr [1, 2, 3, 4, 5];
modifyArray(arr, function() {console.log(array has been modified, arr);
});
69、面向对象编程与面向过程编程的区别
面向过程考虑数据变换; 面向过程的世界是以目标问题规定的I/O为中心的
面向对象考虑功能分工; 面向对象的世界是以内部实现的可理解性为中心的
70、eval是做什么的性能怎么样安全如何
eval方法是在运行时对脚bai本进行解du释执行而普通的javascript会有一个zhi预处dao理的过程。所以会有一些性能上zhuan的损失但是通常通过一些手段能将这些性能损失降低到非常少。不至于谈虎色变。 eval通常用在一些需要动态执行字符串或将字符串转为javascript对象的场景比如将json字符串转为javascript对象。 至于eval容易被XSS攻击是属于想当然的说法吧XSS攻击就是在你的页面上嵌入html或javascript代码我觉得与是否使用eval方法没有什么关系。
71、函数节流、防抖
函数防抖(debounce)
概念 在事件被触发n秒后再执行回调如果在这n秒内又被触发则重新计时。 生活中的实例 如果有人进电梯触发事件那电梯将在10秒钟后出发执行事件监听器这时如果又有人进电梯了在10秒内再次触发该事件我们又得等10秒再出发重新计时。
函数节流(throttle)
概念 规定一个单位时间在这个单位时间内只能有一次触发事件的回调函数执行如果在同一个单位时间内某事件被触发多次只有一次能生效。 生活中的实例 我们知道目前的一种说法是当 1 秒内连续播放 24 张以上的图片时在人眼的视觉中就会形成一个连贯的动画所以在电影的播放以前是现在不知道中基本是以每秒 24 张的速度播放的为什么不 100 张或更多是因为 24 张就可以满足人类视觉需求的时候100 张就会显得很浪费资源。
分析图 假设我们观察的总时间为10秒钟规定1秒作为一次事件的最小间隔时间。 如果触发事件的频率是 0.5s/次那么 函数防抖如图 因为始终没法等一秒钟就被再次触发了所以最终没有一次事件是成功的。 函数节流如图 因为控制了最多一秒一次频率为0.5s/次所以每一秒钟就有一次事件作废。最终控制成1s/次 如果触发事件的频率是 2s/次那么 函数防抖如图 因为2s/次已经大于了规定的最小时间所以每计时两秒便触发一次。 函数节流如图
同样2s/次 大于了最小时间规定所以每一次触发都生效。 应用场景 对于函数防抖有以下几种应用场景
给按钮加函数防抖防止表单多次提交。 对于输入框连续输入进行AJAX验证时用函数防抖能有效减少请求次数。 判断scroll是否滑到底部滚动事件函数防抖
总的来说适合多次事件一次响应的情况
对于函数节流有如下几个场景
游戏中的刷新率 DOM元素拖拽 Canvas画笔功能
总的来说适合大量事件按时间做平均分配触发。
函数防抖
function debounce(fn, wait) {var timer null;return function () {var context thisvar args argumentsif (timer) {clearTimeout(timer);timer null;}timer setTimeout(function () {fn.apply(context, args)}, wait)}
}
var fn function () {console.log(boom)
}
setInterval(debounce(fn,500),1000) // 第一次在1500ms后触发之后每1000ms触发一次
setInterval(debounce(fn,2000),1000) // 不会触发一次我把函数防抖看出技能读条如果读条没完成就用技能便会失败而且重新读条
之所以返回一个函数因为防抖本身更像是一个函数修饰所以就做了一次函数柯里化。里面也用到了闭包闭包的变量是timer。
函数节流
function throttle(fn, gapTime) {let _lastTime null;return function () {let _nowTime new Date()if (_nowTime - _lastTime gapTime || !_lastTime) {fn();_lastTime _nowTime}}
}
let fn (){console.log(boom)
}
setInterval(throttle(fn,1000),10)
如图是实现的一个简单的函数节流结果是一秒打出一次boom
小结
函数防抖和函数节流是在时间轴上控制函数的执行次数。防抖可以类比为电梯不断上乘客,节流可以看做幻灯片限制频率播放电影。
72、“use strict”的作用是什么
use strict 出现在 JavaScript 代码的顶部或函数的顶部可以帮助你写出更安全的 JavaScript 代码。如果你错误地创建了全局变量它会通过抛出错误的方式来警告你。例如以下程序将抛出错误
function doSomething(val) {use strict; x val 10;
}
它会抛出一个错误因为 x 没有被定义并使用了全局作用域中的某个值对其进行赋值而 use strict 不允许这样做。下面的小改动修复了这个错误
function doSomething(val) {use strict; var x val 10;
}
73、了解ES6 的 Proxy吗
概述 Proxy用于修改某些操作的默认行为等同于在语言层面上做出修改所以属于一种“元编程”即对编程语言进行编程。 Proxy可以理解成在目标对象前架设一层拦截层外界访问该对象都必须先通过这层拦截因此提供一种机制可以对外界的访问进行拦截或过滤。
实例的方法
1.get() get方法用于拦截某个属性的读取操作。
let person {name : 张三
}
let proxy new Proxy(person,{get : function(target,property){if(property in target){return target[property];}else{throw new Error(property property no found!)}}
})
proxy.name; //张三
proxy.age; //property age no found!
12345678910111213141516
以上的实例当获取对象没有的属性age时就会抛出错误若不通过代理则会返回undefined get方法可以继承
let proto new Proxy({},{get(target,propertykey,receiver){console.log(get propertykey);return target[propertykey];}
});
let obj Object.create(proto);
obj.lalala; //get lalala
123456789 利用Proxy对象可以将读取属性的操作变为执行某个函数从而实现函数的链式操作
let pipe (function(){return function(value){//创建函数执行栈let funcStack [];//创建拦截器let oproxy new Proxy({},{get: function(pipeObj,fnName){//当属性为get返回函数栈一次执行函数后的结果if(fnName get){return funcStack.reduce(function(val,fn){return fn(val);},value)}//否则将函数置入函数执行栈中并返回又一个拦截器else{funcStack.push(window[fnName]);return oproxy;}}});// 将拦截器返回给pipe return oproxy;}
}())
let double nn*2;
let pow nn*n;
pipe(2).double.pow.get; //16
1234567891011121314151617181920212223242526272829 2.set() set方法用户拦截某个属性的赋值操作
let ageLimit {set : function(obj,prop,val){if(prop age){if(!Number.isInteger(val)){throw new TypeError(the age must be a integer)}if(val 150 || val 0){throw new RangeError(the age must be from 0 to 150)}}obj[prop] val;}
}let person new Proxy({},ageLimit);
person.age 200; //the age must be from 0 to 150;
person.age abc //the age must be a integer;
person.age 20; //正常
person.age; // 20;
1234567891011121314151617181920 通过ageLimit拦截器可以及时对用户的数据输入做数据验证以保证数值规范 有时候我们会在对象上设置内部属性属性名的第一个字符为下划线’_’表示该属性不能被外部访问或使用。结合get和set方法就可以做到防止内部属性被外部读写
let handler {get (target , key){invariant(key,get);return target[key];},set (target , key , value){invatiant(key,set);taget[key] value;return true;}
}
function invariant(key,action){if(key[0] _){throw new Error(no allowed to action the property);}
}
let target {_name : 张三,_age : 20
};
let proxy new Proxy(target,handler);
proxy._name; // no allowed to get the property
proxy._age 12 // no allowed to set the property
1234567891011121314151617181920212223242526 3.apply() apply方法拦截函数的调用、call、apply操作 apply方法接收三个参数目标对象、目标对象的上下文的this、目标对象的参数数组
let target function(){console.log(I am the target);
}
let handler {apply : function(){console.log(I am the apply);}
}
let p new Proxy(target,handler);
p(); //I am the apply;
12345678910111213
4.其他方法 has(target,propkey) 拦截hasProperty()、propkey in proxy操作返回一个布尔值 deleteProperty(target,propkey) 拦截delete proxy[propkey]操作返回一个布尔值 ownKeys(target) 拦截Object.getOwnPropertyNarnes(proxy)、Object.getOwnPropertySyrnbols (proxy)、 Object.keys(proxy)返回一个数组。该方法返回目标对象所有自身属性的属 性名而 Object .keys()的返回结果仅包括目标对象自身的可遍历属性 getOwnPropertyDescriptor(target,propkey) 拦截 Object.getOwnPropertyDescriptor(proxy, propKey)返回属性的描述对象; defineProperty(target,propkey) 拦截 Object.defineProperty(proxy, propKey, propDesc)、 Object.define Properties(proxy, propDescs)返回一个布尔值; preventExtensions(target) 拦截 Object . preventExtensions (proxy) 返回一个布尔值; getPrototypeOf(target) 拦截Object.getPrototypeOf(proxy)返回一个对象 isExtensible(target) 拦截Object.isExtensible(proxy),返回一个布尔值 setPrototypeOf(target) 拦截Object.setPrototypeOf(proxy,proto),返回一个布尔值若对象为函数则还有二外两种操作可以拦截apply,construct construct(target,args) 拦截Proxy实例作为构造函数调用的操作比如 new proxy(…args); 74、深拷贝是什么
变量存储类型分两类
①基本类型直接存储在栈中的数据。字符串、布尔值、未定义、数字、null
②引用类型将该对象引用地址存储在栈中然后对象里面的数据存放在堆中。数组、对象、函数
这里解释一下为什么null是基本类型有人说他用type of打印出来不是oject吗
null只是一个空指针对象没有数据。根据引用类型特点可以看一下是否符合。 回到我们的问题上
说说深拷贝和浅拷贝还有赋值的区别这样好理解
浅拷贝也就是拷贝A对象里面的数据但是不拷贝A对象里面的子对象
深拷贝会克隆出一个对象数据相同但是引用地址不同就是拷贝A对象里面的数据而且拷贝它里面的子对象
赋值获得该对象的引用地址 浅拷贝和深拷贝的区别 三者的区别
下面用实例来说明
赋值特点说明 赋值疑惑点来自于下图。 赋值打印图
浅拷贝特点说明 obj还是上面的
深拷贝说明 第一种方法的缺陷在于函数不能拷贝 75、解释 JavaScript 中的 null 和 undefined。
JavaScript 中有两种底层类型null 和 undefined。它们代表了不同的含义 尚未初始化undefined 空值null。
null和undefined是两个不同的对象, 有图为证: 76、解释 JavaScript 中的值和类型。
JavaScript提供两种数据类型: 基本数据类型和引用数据类型 基本数据类型有: String Number Boolean Null Undefined Symbol
引用数据类型有: Object Array Function 77、scroll resize 使用函数节流实现不要频繁触发事件的需求
scriptfunction throttle(fun,delay){let timer null;if(timer){clearTimeout(timer);}return function(){setTimeout(function(){fun();},delay);}} var firstResize true;window.onresize function(){if(firstResize){throttle(function(){alert(1)},30)();}firstResize false;}/script
78、解释事件冒泡以及如何阻止它
事件冒泡是指嵌套最深的元素触发一个事件然后这个事件顺着嵌套顺序在父元素上触发。
防止事件冒泡的一种方法是使用 event.cancelBubble 或 event.stopPropagation()低于 IE 9。
79、JavaScript 中的 let 关键字有什么用
用let声明变量只在块级作用域起作用适合在for循环使用也不会出现变量提升现象。同一个代码块内不可重复声明的相同变量不可重复声明函数内的参数。
80、 jQuery 优点和缺点
具体而言jQuery有如下优势
1提供了用css选择符来选择dom元素的api现在已经被浏览器内置支持 2提供了浏览器的检测api 3提供了兼容的功能性api 4提供了DOM的批处理操作批处理思想永远都不会过时 5提供了dom操作的链式操作 6提供了插件机制代码复用变得容易也不容易过时
缺点 现在已经很少操作DOM了 现代框架VUE中 jquery代码工程化 可维护性差vue很远