当前位置: 首页 > news >正文

用lnmp做网站重庆亮哥做网站

用lnmp做网站,重庆亮哥做网站,学做网站要什么基础,有内涵的广告公司名字DOM DOM#xff1a;文本对象模型#xff0c;是HTML和XML文档的编程接口。提供了对文档的结构化的表述#xff0c;并定义可一种方式可以使从程序中对该结构进行访问#xff0c;从而改变文档的结构、样式和内容。 DOM操作 创建节点#xff1a;document.createElement()、do…DOM DOM文本对象模型是HTML和XML文档的编程接口。提供了对文档的结构化的表述并定义可一种方式可以使从程序中对该结构进行访问从而改变文档的结构、样式和内容。 DOM操作 创建节点document.createElement()、document.createTextNode()、document.createDocumentFragment()创建文档碎片表示一种轻量级的文档主要用来存储临时节点然后把文档碎片的内容一次性添加到DOM中、document.createAttribute()查询节点querySelector()、querySelectorAll()、更新节点innerHTML、innerText、textContent添加节点innerHTML、appendChild()、insertBefore()删除节点removeChild() 如何判断一个元素是否在可视区域内 offsetTop、scrollTopgetBoundingClientRectIntersection Observe offsetTop、scrollTop实现 function isInViewPortOne(el) {const viewPortHeight window.innerHeight || document.documentElement.clienHeight || document.body.clientHeightconst offsetTop el.offsetTopconst scrollTop document.documentElement.scrollTopconst top offsetTop - scrollTopreturn top viewPortHeight }getBoundingClientRect()实现 function isInViewPortOne(el) {const viewHeight window.innerHeight || document.documentElement.clienHeight || document.body.clientHeightconst viewWidth window.innerWidth || document.documentElement.clienWidth || document.body.clientWidthconst {top,right,bottom,left} el.getBoundingClientRect()return (top 0 left 0 bottom 0 left 0) }BOM BOM浏览器对象模型顶级对象是window表示浏览器的一个实例。 window对象 window.open(url, target)window.close()仅用于关闭window.open()打开的窗口窗口操作方法 moveBy(x, y)moveTo(x, y)移动窗体左上角到相对于屏幕左上角的(x,y)点resizeTo(x, y)resizeBy(x, y)scrollTo(x, y)scrollBy(x, y) location对象 location.hash#后面的字符location.host服务器名称端口号location.hostname域名location.href完整urllocation.portlocation.pathname服务器下文件路径location.protocol使用协议location.searchurl查询字符串?后的内容 navigator对象 navigator.appNamenavigator.geolocationnavigator.getUserMedia()可用媒体设备硬件关联的流navigator.mediaDevices可用的媒体设备… screen对象 screen.heightscreen.widthscreen.pixelDepth… history对象 history.go()history.back()history.forward()history.length JS的数据类型 类型分类 基本类型包含Number、String、Boolean、Null空对象指针typeof判断时候会返回object、Undefined、Symbol引用类型包含Object、Array、Function还有Date、RegExp、Map、Set等。 存储方式 基本数据类型存储在栈中读取栈中数据引用数据类型存储在堆中索引栈地址读取堆中数据。 常见问题 声明变量时不同的地址分配 基本数据类型的值存放在栈中在栈中存放的是对应的值引用数据类型的值存放在堆中在栈中存放的是指向堆内存的地址 不同的类型数据导致赋值变量时的不同 基本数据类型赋值是生成相同的值两个数据对应不同的地址引用数据类型赋值是将保存对象的内存地址复制给另一个变量两个数据对应指向同一个堆内存中的地址 var、let、const的区别 变量提升var声明的变量存在变量提升声明之前调用值为undefined暂时性死区let和const块级作用域let和const重复声明let和const不允许重复声明修改声明的变量const是制度常量。使用 类型转换机制 类型转换分类 显式转换Number()、String()、parseInt()、Boolean()隐式转换 隐式转换注意点 对象与基本类型数据比较对象会先调用valueOf方法如果valueOf方法继续返回对象则调用toString方法尝试得到一个原始值来进行比较null与undifined比较或者!时是相等的其它情况下不等NaN的比较与任何值都不等。要检查一个值是否是NaN应使用Number.isNaN()函数布尔值与数字或字符串比较布尔值会先转换为数字然后按照数字与数字或者字符串比较规则比较。两个值都为引用类型则比较他们是否指向同一个对象 常见问题 Number(undefined) // NaNparseInt(234sdf2) // 234null undefined // true[] ![] // truetypeof null // objectundefined和null与自身严格相等 数据类型检测typeof和instanceof typeof操作符返回一个字符串表示未经计算的操作数的类型。使用方法typeof val typeof判断引用类型数据只能识别出function其它均为object。 instanceof用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。使用方法object instanceof constructor。 构造函数通过new可以实例对象instanceof能判断这个对象是否是之前那个构造函数生成的对象。 typeof和instanceof用于判断数据类型均存在弊端。因此通用的数据类型检测方法为Object.prototype.toString()该方法统一返回[object Xxx]字符串。 数据类型检测方法封装 const getValType val {let type typeof val;if(type ! object) return type;return Object.prototype.toString.call(val).replace(/^\[object (\S)\]$/, $1); }常用的字符串操作方法 增、${}拼接以及concat()等删创建新的副本slice(start, end)、substr(start, end)、substring(start, num)改创建新的副本trim()、toLowerCase()、repeat()等查chatAt()、indexOf()、includes()、strartWith()等转换方法split()模板匹配match()、search()、replace() 数组的常用操作方法 增push()、unshift()、splice()、concat()等删pop()、shift()、splice()、slice()等改splice()查indexOf()、includes()、find()等排序sort()、reverse()等转换join()迭代some()、map()、filter()、forEach、every()等 浅拷贝和深拷贝 浅拷贝和深拷贝的主要区别是在复制对象或数据结构时拷贝的深度以及对原始数据内部结构的影响。 基本类型传递的是值数据存储在栈中引用类型传递的是地址数据存储在堆中 浅拷贝基本类型拷贝的是基本类型的值引用类型拷贝创建一个新对象只复制原始对象的基本数据类型的字段或引用地址不复制引用指向的对象即新对象和原始对象数据均指向同一个引用对象数据修改会相互影响 Object.assigin()slice()/concat拓展运算符 深拷贝创建一个新对象递归复制原始对象的所有字段和引用对象即新对象和原始对象之间的数据相互独立复制后无直接影响关系。 JSON.stringfly()存在弊端会忽略undefined、symbol和函数手写循环递归 常见问题 手写一个浅拷贝 const shallowCopyFn obj {let result null;const type Object.prototype.toSting.call(obj)// 创建一个新对象if(type [Object Object]) {result {}} else if(Object [Object Array]){result []} else {result obj}// 对象数据 基本类型和字段赋值for(let prop in obj) {if(obj.hasOwnProperty(prop)) {result[prop] obj[prop]}}return result }浅拷贝或者可以使用Object.assign()、ES6的展开运算符、concat()等实现。 手写一个深拷贝 function deepClone(obj, hash new WeakMap()) { if (obj null) return null; // null 的情况 if (obj instanceof Date) return new Date(obj); // 日期对象直接返回一个新的日期对象 if (obj instanceof RegExp) return new RegExp(obj); // 正则对象直接返回一个新的正则对象 if(typeof obj ! object) return obj;// 如果循环引用了就用 weakMap 解决 if (hash.has(obj)) return hash.get(obj); let cloneObj new obj.constructor; // 找到所属类型原型上的constructorhash.set(obj, cloneObj); for (let key of obj) { if(obj.hasOwnProperty(key))cloneObj[key] deepClone(obj[key], hash)} return cloneObj; } // 示例 const original { a: 1, b: { c: 2 }, d: [3, 4], e: new Date(), f: /abc/g, g: function() {} }; const cloned deepClone(original); console.log(cloned); console.log(cloned original); // false console.log(cloned.b original.b); // falseJS的数据结构 数据结构计算机存储、组织数据的方式。 分类 数组连续的内存空间保存数据保存的数据个数在内存分配的时候是确认的栈Stack先进后出LIFO的有序集合队列Queue先进先出FIFO的有序集合堆Heap链表以键-值对存储的数据结构字典树图散列表也称为哈希表特点是操作很快 原型和原型链 原型 由于JS中只有对象没有类ES6之前因此为了解决数据共享引入了原型的概念。 原型其实就是一个普通对象prototype 也称为显式原型主要作用是为其它对象提供共享属性。 只有构造函数才有原型公有属性可操作几乎所有对象在创建的时候都会被赋予一个非空的值作为原型对象的引用 隐式原型__proto__ 只有对象普通对象、函数具备私有的对象属性不可操作 显示原型prototype是构造函数才具备的普通对象要调用构造函数的方法就只能通过__proto__ 。隐式原型全等于显示原型即__proto__ prototype。 常见问题 Google中隐式原型的写法[[prototype]]函数的原型是放在prototype上对象、数组的原型是放在__proto__上Object.getPrototypeof(obj)获取val的原型对象 constructor、原型对象和函数实例三者间的关系 默认情况下所有的函数的原型对象都会自动获得一个名为 constructor的属性指向与之关联的构造函数。 function Person() {}let per new Person()console.log(Person.prototype per.__proto__) // true console.log(Person.prototype.constructor Person) // true构造函数的原型和函数实例对象的原型是同一个对象。 常见问题 constructor用于判断类型arr.constructor Array // true 原型链 原型链其实就是一条访问链路通过对象特有的原型构成的一种链式结构用来继承多个引用类型的属性和方法。当试图访问一个对象的属性时就会在原型链上进行查找默认情况下终点就是最初原型对象的原型null。 字符串。数组、构造函数的原型最终都会指向Object而Object的原型指向是null。 常见问题 __proto__ prototype prototype {} {}.__proto__ Object.prototype[].__proto__ Array.prototype {}.__proto__ [].__proto__.__proto__Person.prototype.__proto__ Object.prototype Object.prototype.__proto__ null总结 一切对象都是继承自ObjectObject对象直接继承根源对象null一切的函数对象都是继承自Function对象Object对象直接继承自Function对象Function对象的__proto__会指向自己的原型对象最终还是继承自Object。 继承 在JS中所有引用类型都继承了Object而继承也是通过原型链实现的常见继承方法有8种。 原型链继承把子类的原型指向父类构造函数实例来覆盖子类原型对象。一般用于一个子类继承的情况避免属性篡改影响。 function Parent(name) {this.name namethis.hobby [吃饭,睡觉] } Parent.prototype.getInfo _ {console.log(this.name)console.log(this.hobby) } function Child() {} Child.prototype new Parent()const children1 new Child() children1.name 222 children1.hobby.push(唱歌) children1.getInfo() // 输出 222 [吃饭,睡觉, 唱歌]const children2 new Child() children2.name 333 children2.getInfo() // 输出 333[吃饭,睡觉, 唱歌]构造函数继承在子类构造函数中调用父类构造函数把this指向改变为子类对象借助call。 注父类的引用属性不会被共享即构造函数继承只能继承父类的实例属性和方法不能继承原型属性和方法。 function Parent(name) {this.name name;this.hobby [吃饭, 睡觉] } Parent.prototype.getName function() {return this.name } function Child(name) {Parent.call(this, name) } const children1 new Child(小明) children1.hobby.push(唱歌) console.log(children1.name , children1.hobby) // 输出小明 [吃饭,睡觉, 唱歌]const children2 new Child() children2.name 小红 console.log(children2.name , children2.hobby) // 输出小红 [吃饭,睡觉] children2.getName() // 报错组合继承将原型链继承和构造函数继承结合。主要是使用原型链实现对原型属性和方法的继承又通过借用构造函数实现对实例属性的继承。因此组合式继承一般情况下回调用两次父类的构造函数。 function Parent(name) {this.name name;this.hobby [吃饭, 睡觉] } Parent.prototype.getInfo _ {console.log(this.name)console.log(this.hobby) } function Child(name, age) {Parent.call(this. name) // 第二次调用 this.age age } // 继承Parent的原型 第一次调用 继承父类的属性和方法 Child.prototype new Parent() // 修复构造函数的指向 Child.prototype.constructor Child // 添加自定义方法 Child.prototype.getAge _{console.log(this.age) }注在上述示例中Child.prototype new Parent()即第一次调用实际上是不必要的因为它会导致父类的构造函数被不必要的调用从而继承父类实例的所有属性的方法数据共享。更推荐的做法是使用Object.create(Parent.prototype)来创建子类的原型对象即寄生组合式继承。 原型式继承 ES5中新增了Object.create()方法规范了原型式继承。即实现一个对象的继承不比创建构造函数。 let Parent {name: 132,hobby: [吃饭, 睡觉],getInfo() {console.log(this.name)console.log(this.hobby)} } const children1 Object.create(Parent) children1.name 232 children1.hobby.push(打游戏) children1.getInfo() // 232 [吃饭, 睡觉, 打游戏]const children2 Object.create(Parent) children2.getInfo() // 132 [吃饭, 睡觉, 打游戏]ES6 extend class 关键字继承 ES6继承是一种语法糖先将父类实例对象的属性和方法驾到this上super使用然后再用子类的构造函数修改this。 class Parent() {constructor(name) {this.name name}sayHello() {console.log(hello, ${this.name})} } class Child extend Parent {constructor(name) {super(name);} }作用域和作用域链 作用域 作用域即变量和函数有效的区域集合变量作用域又称为上下文。换句话说就是代码中国变量和其它资源的可见性。 分类 全局作用域局部作用域函数作用域块级作用域ES6中国引入了let和const关键字局部访问。 作用域链 当使用一个变量时js引擎会在当前作用域下寻找该变量如果没有找到则向上查找知道找到全局作用域下结束。 执行上下文与执行栈 this对象 this关键字是函数运行时自动生成的一个内部对象只能在函数内部使用总指向调用它的对象。 this在函数执行过程中一旦确定就不可再更改。 绑定规则 默认绑定严格模式下不能讲全局对象用于默认绑定this会绑定到undefined隐式绑定this永远指向最后调用它的对象new绑定通过构建函数new关键字生成一个实例对象此时this指向这个实例对象new过程中如果返回一个对象this则指向返回的对象如果返回一个简单类型数据时this依旧指向实例对象显式修改apply(obj)、call(obj)、bind(obj)是改变函数调用对象的方法。 绑定规则优先级 new绑定 显式绑定 隐式绑定 默认绑定 apply、call、bind的区别 apply、call、bind的作用都是改变函数执行时的上下文即this指向。 const name Li const obj {name: Bo,sayHello() {console.log(this.name)} } obj.sayHello() // 输出Bo setTimeout(obj.sayHello, 0) // 输出Li上述示例中由于使用了setTimeout在回调中执行obj.sayHello()因此在指向环境回到主栈执行时实在全局执行上下文中的环境执行的此时this指向window因此输出 Li因此需要调整绑定this指向 setTimeout(obj.sayHello.call(obj), 0)三者区别 apply(obj, arrayArgs)参数以数组形式传入改变this指向后原函数会立即执行且此方法只是临时改变一次。call(obj, listArgs)参数以列表形式传入改变this指向后原函数会立即执行且此方法只是临时改变一次。bind(obj, listArgs)参数以列表形式传入可多次传入。改变this指向后不会立即执行而是返回一个永久改变this指向的函数。 三者相同点 三者第一个参数都是this要指向的对象如果是null、undefined时默认指向window 手动实现bind Function.prototype.myBind function (context) {// 判断是否是函数if(typeof this ! function) {throw new TypeError(error)}// 获取参数const args [...arguments].slice(1), fn this;return function Fn () {// 根据调用方式 传入不同的绑定值return fn.apply(this instanceof Fn ? new fn(...arguments) : context, args.concat(...arguments))} }箭头函数 ES6中提供了箭头函数语法在书写时候就能确定this指向。 箭头函数不能作为构建函数。 闭包 在JS中闭包是指一个函数能够访问并操作它外部的变量。闭包的创建主要是在嵌套函数中发生的。及时外部函数执行完毕并返回之后内部函数依旧可访问和修改这些变量只是因为内部函数保持了对外部作用域的引用。 一般函数的词法环境在函数返回后就被销毁。但由于闭包保留了对所在词法环境的数据引用因此创建时所在执行上下文被销毁但创建所在词法环境依然存在延长了变量的生命周期。 示例 const sumFn _ {let count 0return function () {return count 1} } // 创建两个独立的计数器 const sum1 sumFun() const sum2 sumFn() console.log(sum1()) // 1 console.log(sum1()) // 2 console.log(sum2()) // 1闭包的特性 保持变量私有模拟素有方法实现封装和抽象使得代码模块化实现回调和异步操作 闭包的用途 创建私有变量数据封装和隐私模拟类的私有方法和属性实现函数工程 闭包的缺点 内存消耗由于闭包保持了对外部变量的引用因此可能会造成内存消耗增加甚至内存泄漏性能考虑闭包可能会比普通函数的调用要稍慢一些。 其它 在创建新的对象或者类时方法通常应该关联于对象的原型而不是定义在对象的构造器中原因每个对象的创建方法都会被重新赋值。 function Obj(name, age) {this.name namethis.age age } Obj.prototype.getName function() {return this.name } Obj.prototype.getAge function() {return this.age }执行上下文 执行上下文就是代码的执行环境。分为 全局执行上下文 window函数执行上下文只有在函数被调用的时候才会被创建Eval函数执行上下文Eval函数中的代码 生命周期 函数执行上下文的生命周期包括3个阶段 创建节点确定this指向执行阶段执行变量赋值、代码执行找不到值则分配undefined回收阶段执行上下文出栈等待虚拟机回收执行上下文 变量提升 变量提升由执行上下文和作用域的工作原理决定的。在JS代码执行前解析器会首先解析代码找出所有的变量声明var关键字声明然后在执行之前讲这些变量提升在其所在作用域的最顶端这个过程就是变量提升。 变量提升的实际原因 编译阶段与执行阶段分离编译阶段代码解析变量和函数声明被提升到作用域顶部执行阶段代码按照编写顺序执行作用域决定在JS中作用域由函数决定 注意 只有声明本身会被提升赋值或者其它逻辑操作依旧在原处执行使用let和const关键字声明的变量不会被提升ES6处理 执行栈调用栈 - 先进后出结构 执行栈用于存储代码执行阶段创建的所有执行上下文。先进后出从上到下创建对应的函数执行上下文冰牙人员栈执行完成被推出直至结束。 new操作符具体实现 在JS中new操作符用于创建一个给定构造函数的实例对象。 流程实现 创建一个新的object将对象与构造函数通过原型链连接起来将构造函数中的this绑定道新建的对象object上根据构建函数返回类型做判断原始值责备忽略对象则需要正常处理使用。 function Person(name, age) {this.name namethis.age age } const per new Person(haa, 33) // 构造函数没有return语句 则将新创建的对象返回 console.log(per) //Person {name: haa, age: 33} 手写new操作符 function NNew(Func, ...args) {const obj {}// 将新对象原型指向构造函数原型对象obj.__proto__ Func.prototypelet res Func.apply(obj, args)returm res instanceof Object ? res : obj }ES6新增扩展 扩展运算符的应用...构造函数新增的方法Array.from()对象转数组、Array.of()一组值转换为数组 const arr Array.form({0:a,1:b,length: 2 }) // [a, b]Array.from([1, 2, 4], xx1) // [1, 3, 5]Array.of(3) // [,,,] Array.of(1,2,4,5) [1, 2, 4, 5]实例对象新增的方法copyWithin()、find()、keys()、flatMap()等空值处理sort()排序算法的稳定性 JS的事件模型 事件HTML文档或浏览器中发生的一种交互操作 事件流父子节点事件绑定触发顺序 事件流 事件流的三个阶段 事件捕获阶段从上到下依次触发处于目标阶段事件冒泡阶段**从下触发节点往上DOM的最高层父节点**的传播方式。 事件模型 分类 原始事件模型DOM0级 绑定速度快只支持冒泡不支持捕获同一个事件类型只能绑定一次后绑定会覆盖之前的删除事件处理赋值为null即可 标准事件模型DOM2级 标准事件模型中一次事件共有三个过程 事件捕获从document一直向下传播到目标元素事件处理触发目标元素的监听元素事件冒泡从目标元素冒泡到document依次检查和执行相关的监听函数 添加事件监听addEventListener(evt, handler, userCapture) 移除事件监听removeEventListener(evt, handler, userCapture) useCapture默认为false表示在冒泡过程中执行设置为true表示在捕获过程中执行。 IE事件模型 IE事件模型共有两个过程 事件处理阶段事件到达目标元素触发监听函数事件冒泡阶段冒泡到document过程中检查和执行相关监听函数 添加事件监听attachEvent(evt, handler) 移除事件监听detachEvent(evt, handler) 事件代理事件委托 事件代理就是把一个或一组元素的响应事件的函数委托给外层的元素完成其在冒泡阶段完成。 应用场景 通常用于动态绑定减少重复工作。列表项操作增、删、改、查示例 const ulDom document.getElementById(ulDom) ulDom.onclick function (evt) {evt evt || window.eventconst target evt.target || evt.srcElemnentif(target.nodeName.toLowerCase() li) {console.log(target.innerText)} }事件委托的局限性 focus、bour等没有冒泡机制的事件无法使用mousemove、mouseout这些只能不断通过位置计算定位的对性能消耗高不适合事件委托 事件循环 JS是一门单线程语言实现单线程非阻塞的方法就是事件循环。主要实现同步任务进入主线程主执行栈异步任务进入任务队列先进先出。主线程内的任务执行完毕为空则会去任务队列读取对应的任务推入主线程执行不断重复。 在JS中所有的任务都可以分为 同步任务一般会直接进入主线程执行异步任务比如ajax请求、定时器函数等。 宏任务与微任务 微任务 微任务一个需要异步执行的函数执行时机主函数执行结束之后、当前宏任务执行结束之前。 常见微任务 Promise.then()MutationOberserveProxynextTick() 宏任务 宏任务的时间粒度比较大执行事件间隔是不能精确控制的。 常见宏任务 scriptsetTimeout、setIntervalUI事件postMessage、MessageChanelsetImmediate、I/O等 关系图 按照关系图执行机制 执行一个宏任务如果遇到微任务则先将它推入微任务的事件队列中当前宏任务执行完查看微任务的事件队列将里面的任务依次执行再继续执行下一个宏任务。 示例 console.log(1)setTimeout(_{console,log(2) }, 0)new Promise((res, rej) {console.log(Promise)resolve() }).then(_{console.log(then) }) console.log(3)// 执行后 输出 1 Promise 3 then 2 // setTimeout术语新的宏任务所以要等上一个微任务列表执行完后再执行async 和 await async异步的意思await可以理解为async await即等待异步方法执行阻塞后面的代码。 async async函数返回一个Promise对象。以下示例两种实现是等效的 function fnc() {return Promise.resolve(123) }async function() {return 123 }await 正常情况下await后是一个Promise对象如果不是则直接返回对应的值。函数运行遇到await则会阻塞下面的代码加入微任务列表跳出去执行同步代码。 async function func() {return await 123 } func().then(val console.log(val)) // 123函数缓存 函数缓存就是将函数运算过的结果进行缓存。 实现函数缓存主要依靠闭包、科利华、高阶函数等。 柯里化把接受多个参数的函数转换为接受一个单一参数的函数 const add (x) {return function (y) {return x y} } // 使用 add(2)(3) // 5JS本地存储 JS的本地存储方式主要有 cookiesessionStoragelocalStorageindexedDB Cookie cookie类型为小型文本文件指某些网站为了辨别用户身份而存储在用户本地终端上的数据。是为了解决HTTP无状态导致的问题。 cookie一般大小不超过4KB由key-value形式存储还包含一些有效期、安全性、适用范围的可选属性。 Cookie每次请求都会被发送。修改Cookie必须保证Domain和Path的值相同。删除Cookie一般通过设置一个过期时间使其从浏览器上删除。 Expires过期时间Domain主机名Path要求请求的资源路径必须带上这个URL路径才可以发送Cookie受不标记为Secure的cookie只通过HTTPS协议加密的请求发送给服务端。 localStorage 特点 持久化存储除非主动删除否则不会过期存储信息在同一域下是共享的当前页进行 localStorage的增删改的时候本页不会触发storage事件只会在其它页面触发大小5M;本质上就是字符串的读取内容过多会消耗内存空间导致页面卡顿受同源策略的限制 使用 localStorage.setItem(key, value)localStorage.getItem(key)localStorage.key(num)获取第num个键名localStorage.removeItem(key)localStorage.clear() sessionStorage 特点 会话级别存储关闭页面则自动清除数据存储信息在同一域下是共享的当前页进行 sessionStorage的增删改的时候本页不会触发storage事件只会在其它页面触发大小5M;本质上就是字符串的读取内容过多会消耗内存空间导致页面卡顿受同源策略的限制 使用 sessionStorage.setItem(key, value)sessionStorage.getItem(key)sessionStorage.key(num)获取第num个键名sessionStorage.removeItem(key)sessionStorage.clear() 应用场景 标记用户与跟踪用户行为使用cookie适合长期保存在本地的数据令牌使用localStorage敏感账号一次性登录使用sessionStorage存储大量数据、在线文档保存编辑历史的情况使用indexDB 大文件的断点续传 分片上传 分片上传就是将上传的文件按照一定的大小等分割规则将整个文件分割成多个数据块chunk来进行分片上传上传完成后再由服务端对所有分片进行汇总整合拼接生成原始的文件。 断点续传 断点续传就是在上传或下载时将上传或下载任务人为的划分为几个部分。每一个部分采用一个线程来进行。如果遇到网络故障可以从已经完成的部分处开始继续上传或下载未完成的部分。节省时间提高速度。 实现的两种方式 服务端返回告诉从哪开始浏览器端自行处理。 上传或下载过程中在服务器谢伟临时文件处理完成后再将此文件重命名为正式文件即可。 实现思路 拿到文件保存文件唯一标识切割分段上传。每次上传一段根据唯一标识判断此次上传进度直到全部文件上传完毕。对于上传失败、上传过程中刷星页面等情况处理的一种常见方法是使用浏览器的存储机制如localStorage、sessionStorage、IndexedDB或Cookies来保存上传进度和已上传的文件块信息。 function uploadFile(file, chunkSize 1024 * 1024) { const totalChunks Math.ceil(file.size / chunkSize); for (let index 0; index totalChunks; index) { const chunk file.slice(index * chunkSize, (index 1) * chunkSize); const formData new FormData(); formData.append(file, chunk); formData.append(index, index); formData.append(totalChunks, totalChunks); fetch(/upload, { method: POST, body: formData }) .then(response response.json()) .then(data { console.log(Chunk uploaded, data); }) .catch(error { console.error(Error uploading chunk:, error); // 保存已上传的块信息 }); } }使用场景 大文件加速上传流式文件上传网络环境不太行 使用Web worker处理大文件上传 新建 fileUploader.js文件web worker self.onmessage function(e) { const { file, chunkSize } e.data; const totalChunks Math.ceil(file.size / chunkSize); for (let index 0; index totalChunks; index) { const chunk file.slice(index * chunkSize, (index 1) * chunkSize); const formData new FormData(); formData.append(file, chunk); formData.append(index, index); formData.append(totalChunks, totalChunks); // 假设你有一个上传函数 uploadChunk(formData, index).then(() { // 通知主线程该块已上传 self.postMessage({ index: index, status: success }); }).catch(error { // 通知主线程上传失败 self.postMessage({ index: index, status: error, error: error.message }); }); } // 假设的上传函数需要替换为实际的API调用 function uploadChunk(formData, index) { return new Promise((resolve, reject) { // 使用fetch或其他HTTP客户端发送formData // 这里只是模拟 setTimeout(() { if (Math.random() 0.5) { resolve(); } else { reject(new Error(Upload failed for chunk index)); } }, 1000); }); } };主文件index.js中创建Worker并将文件数据和其它必要数据发送给Worker if (window.Worker) { const worker new Worker(fileUploader.js); // 假设你有一个文件输入元素 const fileInput document.querySelector(input[typefile]); fileInput.addEventListener(change, function(e) { const file e.target.files[0]; const chunkSize 1024 * 1024; // 1MB // 发送文件和块大小到Worker worker.postMessage({ file: file, chunkSize: chunkSize }); // 监听来自Worker的消息 worker.onmessage function(e) { console.log(Chunk e.data.index uploaded with status: e.data.status); if (e.data.status error) { console.error(Error:, e.data.error); } }; // 监听Worker的错误 worker.onerror function(error) { console.error(Worker error:, error); }; }); } else { console.log(Your browser doesn\t support web workers.); }ajax Ajax即异步的JS和XML可以在不重新加载整个网页的情况下与服务器交换数据并且更新部分网页。 Ajax的原理通过XMLHttpRequest对象向服务器发送异步请求从服务器获取数据然后用JS来操作DOM而更新页面。 创建Ajax异步交互需要服务器逻辑进行配合完成如下步骤 创建 Ajax 的核心对象XMLHttpRequest;通过XMLHttpRequest对象的open()方法与服务器建立连接构建请求所需的数据内容并通过XMLHttpRequest对象的send方法发送给服务器端通过XMLHttpRequest对象提供的onreadystatechange事件监听服务器端的通信状态XMLHttpRequest.readyState接受并处理服务器向客户端响应的数据结果将处理结果更新到HTML中 封装 function ajaxReq (options) {options options || {}options.type (options.type || GET).toUpperCase()options.dataType options.dataType || jsonconst datas options.dataconst xhr new XMLHttpRequest()if(options.type GET) {xhr.open(GET, ${options.url}?${params}, true)xhr.send()} else if(options.type POST){xhr.open(POST, options.url, true)xhr.send(params)}// 监听服务器的通信状态xhr.onreadychange function(e) {if(xhr.readyState 4) { // 请求完成if(xhr.status 200 xhr.status 300) {options.success options.success(xhr.responseText, xhr.responseXML)} else {options.fail options.fail(xhr.status)}}} } // 使用 ajaxReq({type: get,datas: {id: 1},url:https:xxx,success: (text, xml) {console.log(text)},fail: status {console.log(status)} }) 防抖和节流 防抖和节流本质上就是优化高频率执行代码的一种手段减少调用频率优化体验。 防抖debouncen秒后再执行该事件如在n秒内被重复触发则重新计时示例电梯关门计时关门。确保事件处理函数在最后一次事件触发后的一段时间内才执行通常用于用户输入、验证码输入验证等场景节流throttlen秒内只运行一次如在n秒内重复触发只有一次生效示例火车发车要准点。确保事件处理函数在固定时间间隔内只执行一次通常应用于滚动、搜索联想等 代码实现 防抖n秒后执行 function debounce(func, wait, immediate) {let timeout;return function (...args) {let context thisif(timeout) clearTimeout(timeout)if(immediate) {let callNow !timeout // 第一次会立即执行后续触发才执行timeout setTimeout(function() {timeout null}, wait)if(callNow) {func.apply(context, args)}} else {timeout setTimeout(function () {func.apply(context, args)}, wait)}} }节流n秒内仅执行一次 function throttled(fn, delay 500) {let timer nullreturn function(...args) {if(!timer) {timer setTimeout(_ {fn.apply(this, args)timer null}, delay)}} }单点登录 单点登录是目前比较流行的企业业务整合的解决方案之一。 SSO的定义是在多个应用系统中用户只需要登录一次就可以访问所有相互信任的应用系统。 SSO一般需要一个独立的认证中心子系统的登录均需要通过认证中心本身不参与登录操作。 当一个系统成功登录以后认证中心会颁发一个令牌给各个子系统子系统拿着令牌去获取各自受保护的资源。为了减少频繁验证一般在授权以后一定时间内无需再发起认证。 实现方式 同域名下的单点登录使用Cookie即将Cookie的domain设置为当前域的父域并且服务的Cookie会被子域共享。path默认为web应用的上下文路径。不同域名下的单点登录两种方法均支持跨域 方法一认证中心进行登录登录成功将token写入Cookie。应用系统检查当前请求是否有token没有则跳转登录有则将当前token写入当前应用系统的Cookie访问放行。方法二将认证中心的token保存在localStorage中前端每次请求都主动将localStorage的数据传给服务端。前端拿到token后除了写入自己的localStorage中还可以通过特殊手段写入其他域的localStorage中iframe postMessage。 上拉加载、下拉刷新 上拉加载的本质就是页面触底时机自动触发加载请求。 页面触底公式 const scrollTop document.documentElement.scrollTop const scrollHeight document.body.scrollHeight const clientHeight document.documentElement.clientHeight // 浏览器高度// 距离底部还有50的时候就可以开始触发 const isPut (scrollTop clientHeight) (scrollHeight - 50)下拉刷新的本质就是页面本身置于顶部时用户下拉触发操作。 正则表达式 遇到特殊字符需要使用\转义哦~ 构建正则表达式的方式 字面量创建其包含在斜杠之间/\d/g调用RegExp对象的构造函数new RegExp(\\d, g) 匹配规则 ^匹配输入开始$匹配输入结束*匹配前一个表达式0次或毒刺匹配前一个表达式1次或多次等价于{1}匹配前一个表达式0次或1次等价于${0, 1}.匹配除换行符意外的任何单个字符… 标记 g全局搜索i不区分大小写搜索m多行搜索… 匹配方法 字符串方法match()、matchAll()、search()、replace()、split()正则对象方法test()、exec() 常用正则 5-20个字符以字母开头可带数字以及_、.的字符串/^[a-zA-Z]{1}([a-zA-Z0-9]|[._]){4, 19}$/ 函数式编程 纯函数 纯函数就是对给定的输入返回相同输出的函数并要求所有的数据都是不可变的即纯函数无状态数据不可变 高阶函数 高阶函数就是以函数作为输入或者输出的函数。 高阶函数存在缓存的特性主要是利用了闭包作用。 const doOnce fn {let done falsereturn function() {if(!done) fn.apply(this. fn)else console.log(已处理)done true} }柯里化 柯里化就是把一个多参数函数转换为一个嵌套的一元函数的过程惰性执行。 web攻击方式 常见攻击方式 SQL注入在表单的输入框中输入恶意SQL代码并通过提交这些字段来执行恶意的SQL语句从而影响网站的数据库安全。 SQL注入主要是通过将恶意的Sql查询或添加语句插入到应用的输入参数中再在后台Sql服务器上解析执行进行的攻击。 SQL注入预防 严格检查输入变量的类型和格式过滤和转义特殊字符对访问数据库的Web应用采用防火墙等。 跨站脚本攻击XSS在Web应用中输入恶意指令代码到网页使用户加载并执行攻击者恶意制造的网页程序。 分类 存储型恶意数据提交读取返回解析执行反射型包含恶意代码的URL读取、拼接返回给HTML解析执行DOM型包含恶意代码的URL前端读取打开前端自身漏洞 解决办法 在使用innerHTML、outerHTML、document.write()等小心不要把不可信的HTML插入到页面上。如果使用Vue/react等技术栈应在render阶段避免 innerHTML 的xss攻击隐患DOM中的内联事件监听器如onclick、onload、onmousemove等a标签的href属性setTimeout()等都能把字符串作为代码运行。如果吧不可信的数据拼接到字符串中传递给这些API很容易产生隐患 跨站请求伪造CSRF攻击者优导受害者进入第三方网站在第三方网站中向被攻击网站发起跨站请求。 跨站请求伪造可以通过 get 请求即通过访问img的页面后浏览器自动访问目标地址发送请求。也可以设置一个自动提交的表单发送POST请求。 CSRF的特点 攻击一般发起在第三方网站攻击利用受害者在被攻击网站的登录凭证冒充受害者提交操作跨站请求可以用各种方式图片URL、超链接、Form表单提交等部分请求方式可以直接嵌入第三方论坛、文章中难以追踪。 CSRF的预防 阻止不明外域的访问提交时要求附加本域才能获取的信息token等 文件上传漏洞攻击者可能会利用文件上传功能将恶意软件或脚本上传到目标服务器上进而执行恶意操作或获取敏感信息。 远程命令执行漏洞攻击者可利用该漏洞在受害机上执行任意命令或程序进一步控制受害机器。 目录遍历攻击攻击者试图访问服务器根目录之外的目录并利用特定的符号如“…/”来尝试访问受限制的目录或文件。 信息泄露攻击攻击者可能试图通过各种方法获取或猜测敏感信息如用户密码、密钥等以便进一步入侵系统。 会话劫持攻击者利用各种技术手段捕获会话信息然后冒充合法用户进行非法操作。 零日攻击黑客利用尚未被公众发现的漏洞信息进行攻击使得目标系统无法防范。 JS内存泄漏 JS的内存泄漏是指计算处理中由于疏忽或者错误造成程序未能释放已经不在使用的内存从而造成内存的浪费。 对于持续运行的服务进程必须及时释放不再用到的内存否则内存占用越来越高影响系统性能甚至导致程序崩溃。 垃圾回收机制 JS具有自动垃圾回收机制执行环境会负责管理代码执行过程中使用的内存。 原理垃圾收集器会定期找出不再继续使用的变量然后释放内存。 实现方式 标记清除变量标记进入和离开执行环境垃圾回收程序会将离开状态且无被引用的变量做清理销毁‘’引用计数如果一个值的引用次数为0就表示这个值不再用了可以将此销毁释放。 常见内存泄漏情况 意外的全局变量使用严格模式可解决定时器闭包监听器addEventListener JS数字精度丢失 0.1 0.3 0.4 // false存储二进制小数点的偏移量最大为52位最多可以表达的位数是2^5390071992547740992对应科学计数位数是9.0071992547740992这也是JS最多能表示的精度。他的长度是16所以可以使用toPrecision(16)来做运算超过的精度会自动做凑整处理。 要想解决大数的问题使用第三方库bignumber.js原理是把所有数字当做字符串重新实现了计算逻辑缺点就是性能差。 因此0.1 0.3 0.4为false主要是因为计算机存储双精度浮点数需要先把十进制数转换为二进制的科学计数法的形式然后计算机以自己的规则存储二进制的科学计数法。 由于存储时有位数限制64位并且某些十进制浮点数在转换为二进制数时会出现无线循环造成二进制的舍入操作当再转换为十进制就造成了计算误差。 解决方案 使用toPrecision()凑整并parseFloat()转换为数字后显示 function strip(num, precision 12) {return parseFloat(num.toPrecision(precision)) }或者直接使用第三方库Math.js、BigDecimal.js等 尾递归 数组求和 const sum (arr, total) {if(arr.lengh 1) return totalreturn sum(arr, total arr.pop()) }数组扁平化 const flatArr (arr[], result[]) {arr.forEach(val {if(Arrar.isArray(val)) {result result.concat(flat(val, []))} else result.push(val)}) }ES6相关
http://www.dnsts.com.cn/news/168946.html

相关文章:

  • 如何查看网站 是哪家做的企业官方网站建设运营方案
  • 网站开发毕业设计自己做海报的网站
  • 免费的asp网站河南如何优化网站
  • 网站开发企业官网建筑钢结构网站
  • 客户网站建设洽谈方案百度如何建网站
  • 广西网站建设介绍网络营销推广主要做什么?
  • 网站建设人力资源人员配置网站建设 锋云科技公司
  • 集团公司网站改版方案网站吸引力
  • 网站域名备案与不备案的区别网站上线后如何换模版
  • 游戏网站策划书山东省建设厅招标网站首页
  • 石家庄企业制作网站网页美工设计的四大原则
  • 在重庆找做网站的技术人员如何建设影视网站首页
  • 网站开发前端跟后端的区别ai智能ppt制作
  • 菏泽网站建设价格国外搜索引擎排名百鸣
  • 超市网站建设费用网站做成软件
  • 会网站开发想找兼职装修公司网站模版
  • 网站设计制作教程网站开发微信小程序需求量大吗
  • 淘宝上做网站行吗做肮脏交义的网站
  • 有没有做公司网站的西安标书制作
  • 眉山网站制作源码交易平台哪个最好
  • 如何登录ftp网站企业网站建设的服务类型有哪些
  • 上海优化网站seo公司怎么加快登录网站速度
  • 厂字型布局网站西安产品设计公司有哪些
  • 邦邻网站建设wordpress 画图插件
  • 货运公司网站源码小游戏网站开发需要什么技术
  • 陕西长城建设工程有限公司网站seo技术培训学校
  • 一个服务器可以建几个网站好用的wordpress企业模版
  • 开发网站平台软件技术安卓软件开发专业
  • 怎么优化网站排名具体怎么做那个网站建设
  • 佛山网站建设公司排名榜做性的网站有哪些内容