js中sort内置多种排序算法,是根据要排序数的乱序程度来决定使用哪种排序方法。V8 引擎 sort 函数只给出了两种排序 InsertionSort 和 QuickSort,长度小于20的使用InsertionSort(插入排序),大于20的数组则使用 QuickSort(快速排序)javascript
快速排序css
function quickSort(arr){ if(arr.length<=1){ //若是数组中只有一位数,返回数组 return arr; } var mNumIndex = Math.floor(arr.length/2); //取基准值的下标 var mNum = arr.splice(mNumIndex,1)[0]; //取基准值 var left = []; //左边数组 var right = []; //右边数组 for(var i=0;i<arr.length;i++){ if(arr[i]<mNum){ //若是数组小于基准值,放在左边数组 left.push(arr[i]); }else{ ///不然 right.push(arr[i]); } } return quickSort(left).concat([mNum],quickSort(right)); //返回左边数组+基准值+右边数组 }
插入排序html
function insertSort(arr) { let length = arr.length; for(let i = 1; i < length; i++) { let temp = arr[i]; for(let j = i; j > 0; j--) { if(arr[j] >= arr[j-1]) { break; // 当前考察的数大于前一个数,证实有序,退出循环 } arr[j] = arr[j-1]; // 将前一个数复制到后一个数上 } arr[j] = temp; // 找到考察的数应处于的位置 } return arr; }
选择排序(实现思路跟冒泡排序差很少, 能够说是冒泡排序的衍生版本)vue
function selectionSort(arr) { var len = arr.length var minIndex, temp for (i = 0; i < len - 1; i++) { minIndex = i for (j = i + 1; j < len; j++) { if (arr[j] < arr[minIndex]) { minIndex = j } } temp = arr[i] arr[i] = arr[minIndex] arr[minIndex] = temp } return arr }
ES6java
function unique(arr) { return Array.from(new Set(arr)) } new Set自己是一个构造函数,用来生成Set数据结构,类数组,成员的值都是惟一的, 没有重复的值。 Array.from()将一个类数组对象或者可遍历对象转换成一个真正的数组。
ES5node
function unique(arr) { var newArr = [] for (var i = 0; i < arr.length; i++) { if (newArr.indexOf(arr[i]) === -1) { newArr.push(arr[i]) } } return newArr } var result = []; var obj = {}; for(var i =0; i<arr.length; i++){ if(!obj[arr[i].key]){ result.push(arr[i]); obj[arr[i].key] = true; } }
ES5webpack
var doms = document.getElementsByTagName('*') var obj = {} var ret = [] for (let i = 0; i < doms.length; i++) { var name = doms[i].nodeName if(!obj[name]){ ret.push(name) obj[name] = true } } console.log(ret.length)
ES6ios
let names = [...document.getElementsByTagName('*')].map(v=>v.nodeName) console.log(new Set(names).size)
function getDom(dom) { var list = [] var domChildren = dom.childNodes for (var i = 0; i < domChildren.length; i++) { // nodeType === 1 是元素节点,2是属性节点。 if (domChildren[i].nodeType === 1) { list.push(domChildren[i]) var retArr = getDom(domChildren[i]) list = list.concat(retArr) } } return list } getDom(document.querySelector('body'))
实现bind方法:web
Function.prototype.bind= function(obj){ var _self = this, args = arguments; return function() { _self.apply(obj, Array.prototype.slice.call(args, 1)); } }
定义:屡次触发事件后,事件处理函数只执行一次,而且是在触发操做结束时执行。 原理:对处理函数进行延时操做,若设定的延时到来以前,再次触发事件,则清除上一次的延时操做定时器,从新定时。 function debounce(fn) { // 四、建立一个标记用来存放定时器的返回值 let timeout = null; return function() { // 五、每次当用户点击/输入的时候,把前一个定时器清除 clearTimeout(timeout); // 六、而后建立一个新的 setTimeout, // 这样就能保证点击按钮后的 interval 间隔内 // 若是用户还点击了的话,就不会执行 fn 函数 var args = arguments; timeout = setTimeout(() => { fn.apply(this, args); }, 1000); }; } sayDebounce(){ console.log("防抖成功!"); } btn.addEventListener("click", debounce(sayDebounce));
定义:触发函数事件后,短期间隔内没法连续调用,只有上一次函数执行后,过了规定的时间间隔,才能进行下一次的函数调用。算法
原理:对处理函数进行延时操做,若设定的延时到来以前,再次触发事件,则清除上一次的延时操做定时器,从新定时。
详细连接: https://juejin.im/post/5afe64...
特色:一个类只能构造出惟一实例 案例:建立菜单对象或者弹出框 const singleton = function(name) { this.name = name this.instance = null } singleton.prototype.getName = function() { console.log(this.name) } singleton.getInstance = function(name) { if (!this.instance) { // 关键语句 this.instance = new singleton(name) } return this.instance } // test const a = singleton.getInstance('a') // 经过 getInstance 来获取实例 const b = singleton.getInstance('b') console.log(a === b)
建立一个对象经常须要复杂的过程,因此不适合在一个复杂的对象中。建立对象可能会致使大量的重复代码,也可能提供不了足够级别的抽象。工厂方法模式经过定义一个单独的建立对象的方法来解决这些问题,由子类实现这个方法来建立具体类型的对象。
function Animal(opts){ var obj = new Object(); obj.name = opts.name; obj.color = opts.color; obj.getInfo = function(){ return '名称:'+obj.name +', 颜色:'+ obj.color; } return obj; } var cat = Animal({name: '波斯猫', color: '白色'}); cat.getInfo();
发布订阅模式,基于一个主题/事件通道,但愿接收通知的对象(称为subscriber)经过自定义事件订阅主题,被激活事件的对象(称为publisher)经过发布主题事件的方式被通知。
就和用户订阅微信公众号道理同样,一个公众号能够被多个用户同时订阅,当公众号有新增内容时候,只要发布就行了,用户就能接收到最新的内容
订阅/发布者模式和观察者模式的区别:
在观察者模式中,观察者须要直接订阅目标事件。在目标发出内容改变的事件后,直接接收事件并做出响应。发布订阅模式相比观察者模式多了个事件通道,订阅者和发布者不是直接关联的。
一、Observer模式要求观察者必须订阅内容改变的事件,定义了一个一对多的依赖关系;
二、Publish/Subscribe模式使用了一个主题/事件通道,这个通道介于订阅着与发布者之间;
三、观察者模式里面观察者「被迫」执行内容改变事件(subject内容事件);发布/订阅模式中,订阅着能够自定义事件处理程序;
四、观察者模式两个对象之间有很强的依赖关系;发布/订阅模式两个对象之间的耦合读底
function Public(){ //存放订阅者信息 this.subscribers = []; // 添加订阅者 this.addSubscriber = function(subscriber) { //保证一个订阅者只能订阅一次 let flag = this.subscribers.some(function(item){ return item == subscriber; }) if(!flag){ this.subscribers.push(subscriber); } return this; } // 发布消息 this.publish = function(data) { let arr = arguments; this.subscribers.forEach(function(fn){ fn(...arr) }) return this; } } let publisher = new Public() //初始化 let fanfan = function(data){ console.log(`订阅者吴亦凡收到订阅信息:${[...arguments]}`) } let luhan = function(data){ console.log(`订阅者鹿晗收到订阅信息:${[...arguments]}`) } publisher.addSubscriber(fanfan).addSubscriber(luhan); // 添加订阅者fanfan publisher.publish('NBA头条快讯', '蔡徐坤签约掘金');
一个或多个观察者对目标的状态感兴趣,经过将本身依附在目标对象上以便注册所感兴趣的内容。目标状态发生改变而且观察者可能对这些改变感兴趣,会发送一个通知消息,调用每一个观察者的更新方法。当观察者再也不对目标状态感兴趣时,他们能够简单将本身从中分离。
首先是目标的构造函数,他有个数组,用于添加观察者。还有个广播方法,遍历观察者数组后调用他们的update方法: class Subject{ constructor(){ this.subs = []; } addSub(sub){ this.subs.push(sub); } notify(){ this.subs.forEach(sub=> { sub.update(); }); } } 那么观察者就得有个update方法: class Observer{ update(){ console.log('update'); } } let subject = new Subject(); let ob = new Observer(); //目标添加观察者了 subject.addSub(ob); //目标发布消息调用观察者的更新方法了 subject.notify(); //update
4. 策略模式
特征:根据不一样参数能够命中不一样的策略;
案例:动画库里的算法函数
5. 代理模式
特征:代理对象和本体对象具备一致的接口;
案例:图片预加载
5. 迭代器模式
特征:能获取聚合对象的顺序和元素;
案例:each([1, 2, 3], cb);
5. 命令模式
特征:不一样对象间约定好相应的接口;
案例:按钮和命令的分离;
6. 组合模式
特征:组合模式在对象间造成一致对待的树形结构;
案例: 扫描文件夹;
7. 组合模式
特征:组合模式在对象间造成一致对待的树形结构;
案例: 扫描文件夹;
6. 组合模式
特征:组合模式在对象间造成一致对
待的树形结构;
案例: 扫描文件夹;
Object.prototype.toString.call(arr) === "[object Array]" ; Array.isArray(arr); arr.constructor === Array;
建立一个函数就会为其建立一个prototype属性,指向这个函数的原型对象,原型对象会自动得到constructor属性,指向prototype属性所在函数。
Function.prototype.a = "a"; Object.prototype.b = "b"; function Person(){} console.log(Person); //function Person() let p = new Person(); console.log(p); //Person {} 对象 console.log(p.a); //undefined console.log(p.b); //b p.__proto__ === Person.prototype;Person.prototype.constructor === Person;
vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,经过Object.defineProperty()来劫持各个属性的setter,getter,在数据变更时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来做为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,可是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
vue的数据双向绑定 将MVVM做为数据绑定的入口,整合Observer,Compile和Watcher三者,经过Observer来监听本身的model的数据变化,经过Compile来解析编译模板指令(vue中是用来解析 {{}}),最终利用watcher搭起observer和Compile之间的通讯桥梁,达到数据变化 —>视图更新;视图交互变化(input)—>数据model变动双向绑定效果。
<body> <div id="app"> <input type="text" id="txt"> <p id="show"></p> </div> </body> <script type="text/javascript"> var obj = {} Object.defineProperty(obj, 'txt', { get: function () { return obj }, set: function (newValue) { document.getElementById('txt').value = newValue document.getElementById('show').innerHTML = newValue } }) document.addEventListener('keyup', function (e) { obj.txt = e.target.value }) </script>
keep-alive是 Vue 内置的一个组件,可使被包含的组件保留状态,或避免从新渲染。
在vue 2.1.0 版本以后,keep-alive新加入了两个属性: include(包含的组件缓存) 与 exclude(排除的组件不缓存,优先级大于include) 。
答:简而言之,就是先转化成AST树,再获得的render函数返回VNode(Vue的虚拟DOM节点)
详情步骤:
首先,经过compile编译器把template编译成AST语法树(abstract syntax tree 即 源代码的抽象语法结构的树状表现形式),compile是createCompiler的返回值,createCompiler是用以建立编译器的。另外compile还负责合并option。
而后,AST会通过generate(将AST语法树转化成render funtion字符串的过程)获得render函数,render的返回值是VNode,VNode是Vue的虚拟DOM节点,里面有(标签名、子节点、文本等等)
在下次 DOM 更新循环结束以后执行延迟回调。在修改数据以后当即使用这个方法,获取更新后的 DOM。
原理:事件循环机制(Event Loop)
如下事件属于宏任务:
setInterval()
setTimeout()
如下事件属于微任务
new Promise()
new MutaionObserver()
1.computed计算属性会依赖于使用它的data属性,只要是依赖的data属性值有变更,则自定义从新调用计算属性执行一次。
2.watch则是在监控的data属性值发生变更时,其会自动调用watch回调函数。
1.执行异步操做,开销较大的操做,避免堵塞主线程,使用watch。
2.简单且串行返回的,使用computed
《JavaScript权威指南》中的概念:有权访问另外一个做用域中变量的函数
闭包特性:可实现函数外访问函数内变量,外层变量能够不被垃圾回收机制回收。
缺点:
function outer() { var a = 2; function inner() { console.log(a); } return inner; } var neal = outer(); neal();//2
基础类型:Undefined, Null, Boolean, Number, String, Symbol(ES6新增,表示独一无二的值))一共6种 引用类型:Object
JS中的基础数据类型,这些值都有固定的大小,每每都保存在栈内存中(闭包除外),由系统自动分配存储空间。咱们能够直接操做保存在栈内存空间的值,所以基础数据类型都是按值访问 数据在栈内存中的存储与使用方式相似于数据结构中的堆栈数据结构,遵循后进先出的原则。
JS的引用数据类型,好比数组Array,它们值的大小是不固定的。引用数据类型的值是保存在堆内存中的对象。JS不容许直接访问堆内存中的位置,所以咱们不能直接操做对象的堆内存空间。在操做对象时,其实是在操做对象的引用而不是实际的对象。所以,引用类型的值都是按引用访问的。这里的引用,咱们能够粗浅地理解为保存在栈内存中的一个地址,该地址与堆内存的实际值相关联。
数据结构就是关系,没错,就是数据元素相互之间存在的一种或多种特定关系的集合。
逻辑结构:是指数据对象中数据元素之间的相互关系,也是咱们从此最须要关注和讨论的问题。
物理结构:是指数据的逻辑结构在计算机中的存储形式。
常见的数据结构:数组,队列(queue),堆(heap),栈(stack),链表(linked list ),树(tree),图(graph)和散列表(hash)
参照:https://www.cnblogs.com/slly/...
一种遵循后进先出(LIFO)原则的有序集合。新添加的或待删除的元素都保存在栈的同一端,称做栈顶,另外一端就叫栈底。在栈里,新元素都接近栈顶,旧元素都接近栈底。
是只容许在一端进行插入操做,而在另外一端进行删除操做的线性表。与栈相反,队列是一种先进先出(First In First Out, FIFO)的线性表。与栈相同的是,队列也是一种重要的线性结构,实现一个队列一样须要顺序表或链表做为基础。
链表存储有序的元素集合,但不一样于数组,链表中的元素在内存中并非连续放置的。每一个元素由一个存储元素本事的节点和一个指向下一个元素的引用组成。相对于传统的数组,链表的一个好处在于,添加或者删除元素的时候不须要移动其余元素。 使用链表结构能够克服数组须要预先知道数据大小的缺点(C语言的数组须要预先定义长度),链表结构能够充分利用计算机内存空间,实现灵活的内存动态管理。 数组和链表的一个不一样在于数组能够直接访问任何位置的元素,而想要访问链表中的一个元素,须要从起点开始迭代列表。
<meta name="viewport" content="width=device-width, user-scalable=no">
检测到touchend事件后,马上出发模拟click事件,而且把浏览器300毫秒以后真正出发的事件给阻断掉
1.IE盒子模型(怪异盒子)box-sizing :border-box;
宽度=margin+width
2.W3C标准盒模型box-sizing : content-box;
宽度=margin+border+padding+width
!important > 行内样式>ID选择器 > 类选择器 > 标签 > 通配符* > 继承 > 浏览器默认属性
1. 父元素 overflow: hidden; 2.浮动元素后面的元素: clear: both; 3.伪元素选择器:.clear::after{ content:’’;display:block; clear:both;}; 4.父元素设置高度; 5.父级元素:display: table;
方案一:已知宽高,设置position: absolute;,而后left和top都设置为50%,再根据margin的负值来调正
方案二:相似方案一,最后一步用transform:translate(-50%,-50%);
方案三:绝对定位,top、bottom、left、right都设置为0,设置好宽高,而后margin: auto;
方案四:display:table-cell; + vertical-align:middle;
方案五:使用flex弹性盒模型
<div class=“box”> <div class=“item”></div> </div> box{ display:flex; justifly-content:center; Align-item:center; } Box{ Position:relative; } Item{ Position:absolute; Top:50%; Transform:translateY(-50%); }
!important > 行内样式>ID选择器 > 类选择器 > 标签 > 通配符* > 继承 > 浏览器默认属性
webpack:把全部依赖打包成一个 bundle.js 文件,经过代码分割成单元片断并按需加载。
AMD 是 RequireJS 在推广过程当中对模块定义的规范化产出(不过 RequireJS 从 2.0 开始,也改为能够延迟执行(根据写法不一样,处理方式不一样))。
CMD 是 SeaJS 在推广过程当中对模块定义的规范化产出。
父子类 function Animal(name) { this.name = name || "Mike";//实例属性 this.love = function () { console.log(this.name + "爱吃骨头")//实例方法 } this.other = [];//实例引用属性 } Animal.prototype.sleep = function (place) { console.log(this.name + "在" + place + "睡觉") }
function Dog() {} Dog.prototype = new Animal(); Dog.prototype.name = "Jack"; var dog1 = new Dog("twoHa"); var dog2 = new Dog("keJi"); console.log(dog1.name);//Jack console.log(dog2.name);//Jack dog1.love();//Jack爱吃骨头 dog2.love();//Jack爱吃骨头 dog1.sleep("床上");//Jack在床上睡觉 dog2.sleep("客厅");//Jack在客厅睡觉 优势: 1. 实例是子类的实例,也是父类的实例 2. 父类新增原型方法/原型属性,子类都能访问到 3. 简单,易于实现 缺点: 1. 要想为子类新增属性和方法,必需要在new Animal()这样的语句以后执行,不能放到构造器中 2. 没法实现多继承 3. 来自原型对象的引用属性是全部实例共享的,改变实例会污染父类 4. 建立子类实例时,没法向父类构造函数传参
XSS跨站脚本攻击:
不须要你作任何的登陆认证,它会经过合法的操做(好比在url中输入、在评论框中输入),向你的页面注入脚本(多是js、hmtl代码块等)。
检测 callback 里面的字符。通常 callback 里面都是字母和数字,别的符号都不能有。
要完成一次CSRF攻击,受害者必须知足两个必要的条件:
舒适提示一下,cookie保证了用户能够处于登陆状态,但网站B其实拿不到 cookie。
预防
(1)服务器发送给客户端一个token;
(2)客户端提交的表单中带着这个token。
(3)若是这个 token 不合法,那么服务器拒绝这个请求。
把 token 隐藏在 http 的 head头中。
方法二和方法一有点像,本质上没有太大区别,只是使用方式上有区别。
HTTP是用于传输如HTML文件,图片文件,查询结果的应用层协议。它被设计于用于服务端和客户端之间的通讯。
当前Web应用中较常见的一种持续通讯方式,一般采起 setInterval 或者 setTimeout 实现。例如若是咱们想要定时获取并刷新页面上的数据,能够结合Ajax写出以下实现:
setInterval(function() { $.get("/path/to/server", function(data, status) { console.log(data); }); }, 10000); 缺陷: 程序在每次请求时都会新建一个HTTP请求,然而并非每次都能返回所需的新数据。 当同时发起的请求达到必定数目时,会对服务器形成较大负担。
客户端发送一个request后,服务器拿到这个链接,若是有消息,才返回response给客户端。没有消息,就一直不返回response。以后客户端再次发送request, 重复上次的动做。
http协议的特色是服务器不能主动联系客户端,只能由客户端发起。它的被动性预示了在完成双向通讯时须要不停的链接或链接一直打开,这就须要服务器快速的处理速度或高并发的能力,是很是消耗资源的。
相同点:
不一样点:
注意:回流必将引发重绘,而重绘不必定会引发回流。
总共分为8个阶段建立前/后,载入前/后,更新前/后,销毁前/后
beforeCreate 建立前执行(vue实例的挂载元素$el和数据对象data都为undefined,还未初始化)