文章涉及的内容可能不全面,但量不少,须要慢慢看。我花了很长的时间整理,用心分享心得,但愿对你们有所帮助。可是不免会有打字的错误或理解的错误点,但愿发现的能够邮箱告诉我ghui_master@163.com,我会及时的进行修改,只但愿对你有所帮助,谢谢。javascript
基本数据类型:html
number、前端
string、java
boolean、git
null、github
undefined 引用数据类型: object(普通对象、数组对象、正则对象、日期对象、Math、实例、 prototype等)web
function(普通函数和类) 特殊数据类型:Symbol面试
基本数据类型按值操做,引用数据类型按照堆内存的引用地址来操做编程
数据类型检测四种方式: typeofjson
instanceof
constructor
Object.prototype.toString.call()
webkit、
Gecko、
Trident、
Presto等
函数执行会造成一个私有的做用域(私有栈内存),这就是闭包,在真实项目 中主要应用闭包的两大做用 保护
保存 以前研究过像JQUERY等类库的源码,为了防止全局变量污染,基本上全部代码 都是放到闭包中保护起来的 项目中遇到循环事件绑定,也会基于闭包保存的做用,去存储对应的索引 以前研究过JS高阶编程技巧:柯理化函数编程思想,这个就是闭包的应用,重 写过debounce、throttle函数节流和防抖的方法 ...... 由于闭包会产生不释放的栈内存,因此尽量在项目中少使用
面向对象是一种编程思想,js自己就是基于面向对象构建出来的(例如:js中有不少内置类,像Promise就是ES6中新增的一个内置类,咱们能够基于new Promise来建立一个实例,来管理异步编程,咱们在项目中Promise也常常用,本身也研究过他的源码。。。)咱们平时用的VUE/REACT/JQUERY也是基于面向对象构建出来的,他们都是类,平时开发的时候都是建立他们的额实例来操做的;固然我本身在真实项目中,也封装过一些组件插件,(例如:DIALOG、拖拽、、、)也是基于面向对象开发的,这样能够创造不一样的实例,来管理私有的属性和公有的方法,很方便。。。。
JS中的面向对对象,和其余编程语言还略有不一样,JS中类和实例都是基于原型和原型链机制来处理的; 并且js中关于类的重载、重写、继承也和其余语言不太同样
// 这个题我知道,我以前看过部分JQ源码
// 1.$(document).ready() 采用的是DOM2事件绑定,监听的是DOMContentLoaded这个事件,因此只要DOM结构加载完成就会被触发执行,并且同一个页面中可使用屡次(绑定不一样的方法,由于基于DOM2事件池绑定机制完成的) // 2.window.onload必须等待全部资源都加载完成才会被触发执行,采用DOM0事件绑定,同一个页面只能绑定一次(一个方法),想绑定多个也须要改成window.addEventListener('load', function () {})DOM2绑定方式
let 和 var 的区别
- 不存在变量提高
- 不容许重复声明
- 在全局做用域下设置变量不会给window设置属性
- 存在块级做用域
- 解决了一些暂时性死区问题
let 和 const 的区别 const 建立的是常量,存储的值不能被修改(准确说是不能修改变量的指 向)
call 和 apply 的区别 给方法传参的时候,call是按顺序,一个个传递;apply是把传递的参数放 到一个数组中传递;
在传递参数较多的状况下, call的性能要高于apply; call 和 bind 的区别 call在改变函数this指向的时候,会把函数当即执行,而bind不会把函数立 即执行,只是预先处理了this和实参信息;
真实项目中,咱们须要改变this指向的时候,会应用这三个方法,例如: 给元素进行事件绑定,咱们须要把事件触发,所执行的函数中this和参数进 行预先处理,此时可使用bind进行处理;
咱们能够基于call方法,让类数组借用数组原型上的方法,例如:把类数组 转换为数组
能够基于apply传参是一个数组,借用Math.max获取数组中的最大值 ......
forEach、
map、
find、
some、
filter、
reduce、
every、
sort等
// 开发者A let AModule = (function () { let n = 10; let query = function () { //... }; let fn = function () { //... //调取开发者B编写的QUERY方法 BModule.query(); }; return { query: query, init: function () { query(); fn(); } } })(); // 开发者B let BModule = (function () { let n = 20; let query = function () { //... }; let sum = function () { //... //调取开发者A编写的QUERY方法 AModule.query(); }; return { query: query, init: function () { query(); sum(); } } })(); AModule.init(); BModule.init(); 复制代码
var r2 = typeof typeof typeof sum; // "string"
执行顺序:先执行最后一个 typeof sum -> "function" -> typeof typeof "function" -> typeof "string" -> "string"
只要是两个及以上的typeof 最后返回结果就是 "string"
第一次握手:创建链接。客户端发送链接请求报文段,将SYN位置为1,Sequence Number为x;而后,客户端进入SYN_SEND状态,等待服务器的确认;
第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,须要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);同时,本身本身还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述全部信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK报文段。而后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕之后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。
完成了三次握手,客户端和服务器端就能够开始传送数据。
ACK:此标志表示应答域有效,就是说前面所说的TCP应答号将会包含在TCP数据包中;有两个取值:0和1,为1的时候表示应答域有效,反之为0。
TCP协议规定,只有ACK=1时有效,也规定链接创建后全部发送的报文的ACK必须为1。
SYN(SYNchronization) : 在链接创建时用来同步序号。当SYN=1而ACK=0时,代表这是一个链接请求报文。对方若赞成创建链接,则应在响应报文中使SYN=1和ACK=1. 所以, SYN置1就表示这是一个链接请求或链接接受报文。 FIN (finis)即完,终结的意思, 用来释放一个链接。当 FIN = 1 时,代表此报文段的发送方的数据已经发送完毕,并要求释放链接。
发送HTTP请求,服务器处理请求,返回响应结果 TCP链接创建后,浏览器就能够利用HTTP/HTTPS协议向服务器发送请求了。服务器接受到请求,就解析请求头,若是头部有缓存相关信息如if-none-match与if-modified-since,则验证缓存是否有效,如有效则返回状态码为304,若无效则从新返回资源,状态码为200. 关闭TCP链接
第一次分手:主机1(可使客户端,也能够是服务器端),设置Sequence Number和Acknowledgment Number,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;
第二次分手:主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknowledgment Number为Sequence Number加1;主机1进入FIN_WAIT_2状态;主机2告诉主机1,我“赞成”你的关闭请求;
第三次分手:主机2向主机1发送FIN报文段,请求关闭链接,同时主机2进入LAST_ACK状态;
第四次分手:主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,而后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段之后,就关闭链接;此时,主机1等待2MSL后依然没有收到回复,则证实Server端已正常关闭,那好,主机1也能够关闭链接了。
小提示: 若是日常自身有使用场景可结合使用场景进行讲解,好比我在这里使用过的场景是CORS和Nginx反向代理。
小提示:若是你提到JSONP,面试官确定会问你整个详细的实现过程,因此必定要搞懂JSONP的实现原理,若是不是很理解能够本身起一个Express服务实践一下。
Web前端事先定义一个用于获取跨域响应数据的回调函数,并经过没有同源策略限制的script标签发起一个请求(将回调函数的名称放到这个请求的query参数里),而后服务端返回这个回调函数的执行,并将须要响应的数据放到回调函数的参数里,前端的script标签请求到这个执行的回调函数后会立马执行,因而就拿到了执行的响应数据。
缺点: JSONP只能发起GET请求
这里给出几个连接:
segmentfault.com/a/119000001… zhangguixu.github.io/2016/12/02/… www.cnblogs.com/iovec/p/531…
前端构造一个恶意页面,请求JSONP接口,收集服务端的敏感信息。若是JSONP接口还涉及一些敏感操做或信息(好比登陆、删除等操做),那就更不安全了。
解决方法:验证JSONP的调用来源(Referer),服务端判断Referer是不是白名单,或者部署随机Token来防护。
不严谨的 content-type致使的 XSS 漏洞,想象一下 JSONP 就是你请求 http://youdomain.com?callback=douniwan
, 而后返回 douniwan({ data })
,那假如请求 http://youdomain.com?callback=<script>alert(1)</script>
不就返回 <script>alert(1)</script>({ data })
了吗,若是没有严格定义好 Content-Type( Content-Type: application/json ),再加上没有过滤 callback
参数,直接当 html 解析了,就是一个赤裸裸的 XSS 了。
解决方法:严格定义 Content-Type: application/json,而后严格过滤 callback
后的参数而且限制长度(进行字符转义,例如<换成<,>换成>)等,这样返回的脚本内容会变成文本格式,脚本将不会执行。
能够将执行的代码转发到服务端进行校验JSONP内容校验,再返回校验结果。
小提示:若是你回答跨域解决方案CORS,那么面试官必定会问你实现CORS的响应头信息Access-Control-Allow-Origin。
CORS(跨域资源共享 Cross-origin resource sharing)容许浏览器向跨域服务器发出XMLHttpRequest请求,从而克服跨域问题,它须要浏览器和服务器的同时支持。
请求方法是如下三种方法之一:
HTTP的请求头信息不超出如下几种字段:
后端的响应头信息:
非简单请求是那种对服务器有特殊要求的请求,好比请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。非简单请求的CORS请求,会在正式通讯以前,增长一次HTTP查询请求,称为"预检"请求(preflight)。
若是浏览器否认了"预检"请求,会返回一个正常的HTTP回应,可是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不一样意预检请求,所以触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。
Nginx反向代理
postMessage
document.domain
function Dog(name) { this.name = name; } Dog.prototype={ bark(){ console.log('wangwang'); }, sayName(){ console.log('my name is ' + this.name); } }; function _new() { //=>完成你的代码 } let sanmao = _new(Dog, '三毛'); sanmao.bark(); //=>"wangwang" sanmao.sayName(); //=>"my name is 三毛" console.log(sanmao instanceof Dog); //=>true ================================================ //——> 重写 _new function _new(Fn, ...arg) { let obj = {}; obj.__proto__ = Fn.prototype; Fn.call(obj, ...arg); return obj; } 复制代码
/* 实现一个$attr(name,value)遍历 * 属性为name * 值为value的元素集合 * 例以下面示例: */ let ary = $attr('class','box'); //=>获取页面中全部class为box的元素 ===================================== function $attr(property, value) { let elements = document.getElementsByTagName('*'), arr = []; elements = Array.from(elements); elements.forEach(item => { let itemValue = item.getAttribute(property); if (property==='class') { new RegExp("\\b" + value + "\\b").test(itemValue)?arr.push(item):null; return; } if (itemValue === value) { arr.push(item); } }); return arr; } console.log($attr('class', 'box')); 复制代码
~function(){ //=>bind方法在IE6~8中不兼容,接下来咱们本身基于原生JS实现这个方法 function bind(){ }; Function.prototype.bind=bind; }(); var obj = {name:'zhufeng'}; function func(){ console.log(this,arguments); //=>当点击BODY的时候,执行func方法,输出:obj [100,200,MouseEvent事件对象] } document.body.onclick = func.bind(obj,100,200); ============================================= ~function(){ //=>bind方法在IE6~8中不兼容,接下来咱们本身基于原生JS实现这个方法 function bind(context){ context=context||window; var _this = this, outerArg=[].slice.call(arguments,1); return function anonymous() { var innerArg=[].slice.call(arguments,0); _this.apply(context, outerArg.concat(innerArg)); } }; Function.prototype.bind=bind; }(); 复制代码
function Modal(x,y){ this.x=x; this.y=y; } Modal.prototype.z=10; Modal.prototype.getX=function(){ console.log(this.x); } Modal.prototype.getY=function(){ console.log(this.y); } Modal.n=200; Modal.setNumber=function(n){ this.n=n; }; let m = new Model(10,20); =============================================== class Modal{ constructor(x,y){ this.x=x; this.y=y; } getX(){ console.log(this.x); } getY(){ console.log(this.y); } static setNumber(n){ this.n=n; } } Modal.n=200; Modal.prototype.z=10; 复制代码
~function(){ function changeThis(context){ context=context||window; //let arg=[].slice.call(arguments,1); let arg=[], _this=this, result=null; for(let i=1;i<arguments.length;i++){ arg.push(arguments[i]); } context.$fn=_this; result=context.$fn(...arg); delete context.$fn; return result; }; Function.prototype.changeThis=changeThis; }(); let obj = {name:'Alibaba',$fn:100}; function fn(x,y){ this.total=x+y; return this; } let res = fn.changeThis(obj,100,200); //res => {name:'Alibaba',total:300} 复制代码
~function(){ /*生成随机函数名:时间戳的方式*/ function queryRandomName(){ let time=new Date().getTime(); return '$zhufeng'+time; } /*模拟CALL方法改变函数中的THIS*/ function changeThis(context=window,arg=[]){ let _this=this, result=null, ran=queryRandomName(); context[ran]=_this; result=context[ran](...arg); delete context[ran]; return result; }; Function.prototype.changeThis=changeThis; }(); let res = fn.changeThis(obj,[100,200]); 复制代码
/* 已知宽高 */ .box { position: absolute; top: 50%; left: 50%; margin-top: -50px; margin-left: -50px; width: 100px; height: 100px; } ======================== /* 未知宽高 */ .box { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } ========================== .box { position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: auto; } =============================== .container { display: flex; justify-content: center; align-items: center; } .container .box {} 复制代码
/*
* 1.编写一个方法“flatten”,将数组扁平化 (至少两种办法)
* 2.而后实现“unique”数组去重方法,把数组进行去重 (至少两种办法)
*/
let arr = [[1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9,[11, 12, [12,
13, [14]]]], 10];
ary.flatten().unique().sort((a,b)=>a-b); //=>[1, 2, 3, 4, 5,
6, 7, 8, 9....]
============================================
~function(){
function flatten(){
/*第一种*/
return JSON.stringify(this).replace(/(\
[|\])/g,'').split(',').map(item=>{
return Number(item);
});
/*第二种*/
return this.flat(Infinity);
/*第三种*/
return this.toString().split(',').map(item=>{
return Number(item);
});
/*第四种*/
let arr=this.slice(0);
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
/*第五种*/
let result = [];
let fn = function (ary) {
for (let i = 0; i < ary.length; i++) {
let item = ary[i];
if (Array.isArray(ary[i])) {
fn(item);
} else {
result.push(item);
}
}
}
fn(this);
return result;
}
function unique(){
/*第一种*/
return Array.from(new Set(this));
/*第二种*/
return [...new Set(this)];
/*第三种*/
let obj={};
for(let i=0;i<this.length;i++){
let item=this[i];
if(typeof obj[item]!=='undefined'){
this[i]=this[this.length-1];
this.length--;
i--;
continue;
}
obj[item]=item;
}
return this;
}
Array.prototype.flatten=flatten;
Array.prototype.unique=unique;
}();
let arr = [[1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9,[11, 12, [12,
13, [14]]]], 10];
ary.flatten().unique().sort((a,b)=>a-b); //=>[1, 2, 3, 4, 5,
6, 7, 8, 9....]
复制代码