zoukankan      html  css  js  c++  java
  • 2020-11-09

    javascript

    1. 原型/构造函数/实例
    原型(prototype):一个简单的对象,用于实现对象的 属性继承。可以简单的理解成对象的爹。
    每个JavaScript对象中都包含一个 __proto__的属性指向它爹(该对象的原型),可用 obj.__proto__访问。

    构造函数:可以通过new来新建一个对象的函数。

    实例:通过构造函数和new创建出来的对象,便是实例。实例通过__proto__指向原型,通过constructor指向构造函数。
    例如:
    //实例
    const instance = new Object();
    //原型
    const prototype = Object.prototype;
    三者关系:
    实例.__proto__ === 原型
    原型.constructor === 构造函数
    构造函数.prototype === 原型

    2、原型链
    原型链是由原型对象组成,每个对象都有 __proto__属性,指向了创建该对象的构造函数的原型,__proto__将对象连接起来组成了原型
    链。

    2.1、属性查找机制:当查找对象的属性时,如果实例对象自身不存在该属性,则沿着原型链往上一级查找,找到时则输出,不存在时,则继续
    沿着原型链往上一级查找,直至最顶级的原型对象 Object.prototype,如还是没找到,则输出 undefined 。
    2.2、属性修改机制:只会修改实例对象本身的属性,如果不存在,则进行添加该属性,如果需要修改原型的属性时,则可以用:
    b.prototype.x = 2;但是这样会造成所有继承该对象的实例的属性发生改变。

    3、执行上下文(EC)
    执行上下文可以理解为一个对象:
    它包含三个部分:变量对象(VO) , 作用域链(词法作用域) , this指向 。
    它的类型:全局执行上下文 , 函数执行上下文 , eval执行上下文 。
    代码执行过程:
    创建全局上下文(global EC) , 全局执行上下文(caller)逐行 自上而下 执行。遇到函数时,函数执行上下文被 push 到执行栈顶层。
    函数执行上下文被激活,成为 active EC,开始执行函数中的代码,caller被挂起。
    函数执行完后,callee 被 pop移除出执行栈,控制权交还全局上下文(caller),继续执行。

    变量对象:它是执行上下文中的一部分,可以抽象为一种 数据作用域,其实也可以理解为就是 一个简单的对象,它存储着该执行上下文中的所有变量
    和函数声明(不包含函数表达式)。
    活动对象(AO):当变量对象所处的上下文为 active EC 时,称为 活动对象。
    作用域:执行上下文中还包含作用域链。作用域可以理解为该上下文中声明的 变量和声明的作用范围。可分为块级作用域和函数作用域。
    特性:
    声明提前:一个声明在函数体内都是可见的,函数优于变量。
    非匿名自执行函数,函数变量为 只读 状态,无法修改。
    作用域链:可以理解为一组对象列表,包含父级和自身的变量对象。因此我们可以通过作用域链访问到父级里声明的变量或者函数。
    由两部分组成:[[scope]]属性:指向父级变量对象和作用域链,也就是包含了父级的[[scope]]和AO。
    AO:自身活动对象。

    5、闭包
    它属于一种特殊的作用域,称为 静态作用域。他的定义理解为:父函数被销毁的情况下,返回出的子函数的[[scope]]中仍然保留着父级的单变量
    对象和作用域链,因此可以继续访问到父级的变量对象,这样的函数称为闭包。
    闭包会产生一个很经典的问题:
    多个子函数[[scope]]都是同时指向父级,是完全共享的。因此当父级的变量对象被修改时,所有子函数都受到影响。
    解决:
    变量可以通过函数参数的形式传入,避免使用默认的[[scope]]向上查找。
    使用setTimeout包裹,通过第三个参数传入。
    使用 块级作用域 ,让变量成为自己上下文的属性,避免共享。

    6、script引入方式
    html静态<script>引入。
    js动态插入<script>
    <script defer>:异步加载,元素解析完成后执行
    <script async>:异步加载,但执行时会阻塞元素渲染

    7、对象的拷贝
    浅拷贝:以赋值的形式拷贝对象,仍指向同一个地址,修改时原对象也会受到影响。
    Object.assign , 展开运算符(...)
    深拷贝:完全拷贝一个新对象,修改时原对象不再收到任何影响。
    JSON.parse(JSON.stringify()):性能最快,具有循环引用的对象时,报错。 当值为函数,undefined,symbol时,无法拷贝。
    递归进行逐一赋值。

    8、new运算符的执行过程
    新生成一个对象
    链接到原型: obj.__proto__ = Con.prototype
    绑定 this: apply
    返回新对象(如果构造函数有自己 return时,则返回该值)

    9、instanceof 原理
    能在实例的 原型对象链中找到该构造函数的prototype属性所指向的原型对象,就返回true。
    //__proto__:代表原型对象链
    instance.[__proto__...] === instance.constructor.prototype
    //return ture

    10、代码的复用(再次提醒自己,任何代码开始写第二遍时,就要开始考虑如何复用)
    函数封装
    继承
    复制extend
    混入 mixin
    借用 apply/call

    11、继承
    继承通常指的是:原型链继承,通过指定原型,并可以通过原型链继承原型上的属性或者方法。
    最优化:圣杯模式
    var inherit = (function(c,p){
    var F = function(){};
    return function(c,p){
    F.prototype = p.prototype;
    c.prototype = new F();
    c.uber = p.prototype;
    c.prototype.constructor = c;
    }
    })()
    ES6语法糖 class/extends

    12、类型转换
    - , * , / ,% :一律转换成数值后计算
    +:
    数字 + 字符串 = 字符串,运算顺序是从左到右。
    数字 + 对象 ,优先调用对象的 valueOf > toString
    数字 + boolean/null : 数字
    数字 + undefined : NaN
    [1].toString() === '1'
    {}.toString() === '[object object]'
    NaN !== NaN , +undefined 为 NaN

    13.模块化
    分类:
    es6: import / export
    commonjs: require / module.exports / exports
    amd:require / defined
    require 与 import 的区别:
    require支持动态导入,import不支持。
    require 是 同步 导入,import 属于 异步 导入。
    require 是 值拷贝,导出值变化不会影响导入值,import 指向 内存地址,导入值会随着导出值而变化。

    14、防抖与节流
    它们是一种常用的 高频触发优化方式,能对性能有较大的帮助。
    防抖(debounce):将多次高频操作优化为只在最后一次执行,通常使用的场景是:用户输入,只需再输入完成后做一次输入校验即可。
    function debounce(fn,wait,immediate){
    let timer = null;
    return function(){
    let args = arguments;
    let context = this;
    if(immediate && !timer){
    fn.apply(context,args);
    }
    if(timer) clearTimeout(timer);
    timer = setTimeout(()=>{
    fn.apply(context,args);
    },wait)
    }
    }

    节流(throttle):每隔一段时间后执行一次,也就是降低频率,将高频操作优化成低频操作,通常使用场景:滚动条事件或者resize事件,
    每隔100-500ms执行一次即可。
    function throttle(fn,wait,immediate){
    let timer = null;
    let callNow = immediate;
    return function(){
    let context = this,args = arguments;
    if(callNow){
    fn.apply(context,args);
    callNow = false;
    }
    if(!timer){
    timer = setTimeout(()=>{
    fn.apply(context,args)
    timer = null;
    },wait)
    }
    }
    }

    15、函数执行改变this
    三种方式手动修改this指向:
    call:fn.call(target,1,2)
    apply:fn.apply(target,[1,2]);
    bind:fn.bind(target)(1,2)

    16、ES6/ES7
    声明:
    let/const: 块级作用域,不存在变量提升,暂时性死区,不允许重复声明
    const:声明常量,无法修改
    解构赋值
    class/extend:类声明与继承
    Set/Map:新的数据解构
    异步解决方案:
    promise的使用与实现
    generator:
    yield:暂停代码
    next():继续执行代码
    await/async 是 generator 的语法糖,babel是基于 promise 实现。

     浏览器:

    1、跨标签页通讯
    不同标签页间的通讯,本质原理就是去运用一些可以 共享的中间介质,如下面方法:
    1.1、通过父页面 window.open() 和子页面 postMessage
    异步下,通过 window.open('about:blank') 和 tab.location.href='*'
    1.2、设置同域下共享的 localStorage 与 监听 window.onstorage
    重复写入相同的值无法触发。
    会受到浏览器隐身模式等的限制
    1.3、设置共享 cookie 与不断轮询脏检查(setInterval)
    1.4、借助服务端或者中间层实现

    2、浏览器架构
    用户界面
    主进程
    内核:
    渲染引擎
    JS引擎:
    执行栈
    事件触发线程:
    消息队列:
    微任务
    宏任务
    网络异步线程
    定时器线程

    3、浏览器下事件循环(Event Loop)
    事件循环是指:执行一个宏任务,然后执行清空微任务列表,循环再执行宏任务,再清微任务列表。
    微任务 microtask(jobs): promise / ajax / Object.observe(已废弃)
    宏任务 macrotask(jobs): setTimeout / script / IO / UI Rendering

    4、从输入url 到展示的过程
    DNS解析
    TCP三次握手
    发送请求,分析url,设置请求报文(头,主体)
    服务器返回请求的文件(html)
    浏览器渲染
    HTML parser -->DOM Tree
    标记化算法,进行元素状态的标记
    dom树构建
    CSS parser -->Style Tree
    解析css代码,生成样式树
    attachment -->Render Tree
    结合dom树与style树,生成渲染树
    layout:布局
    GPU painting:像素绘制页面

    5、重绘与回流
    当元素的样式发生变化时,浏览器需要触发更新,重新绘制元素。这个过程中,有两种类型的操作,即重绘与回流。
    重绘(repaint):当元素样式的改变不影响布局时,浏览器将使用重绘对元素进行更新,此时由于只需要UI层面的重新像素绘制,因此 损耗较少。
    回流(reflow):当元素的尺寸,结构或触发某些属性时,浏览器会重新渲染页面,称为回流。此时,浏览器需要重新经过计算,计算后还需要重新页面布局,因此
    是较重的操作。会触发回流的操作:
    页面初次渲染
    浏览器窗口大小改变
    元素尺寸,位置,内容发生改变
    元素字体大小变化
    添加或者删除可见的dom元素
    激活css伪类(例如: :hover)
    查询某些属性或调用某些方法:
    clientWidth,clientHieght,clientTop,clientLeft
    offsetWidth,offsetHeight,offsetTop,offsetLeft
    scrollWidth,scrollHeight,scrollTop,scrollLeft
    getComputedStyle()
    getBoundingClientRect()
    scrollTo()

    回流必定触发重绘,重绘不一定触发回流。重绘的开销较小,回流的代价较高。
    最佳实践:
    css:
    避免使用table布局
    将动画效果应用到position属性为absolute 或 fixed的元素上
    js:
    避免频繁操作样式,可汇总后统一 一次修改。
    尽量使用class进行样式修改
    减少dom的增删次数,可使用字符串或者 documentFragment 一次性插入。
    极限优化时,修改样式可将其 display:none 后修改
    避免多次触发上面提到的那些会触发回流的方法,可以的话尽量用变量存住。

    6、存储(可分为:短暂性存储和持久性存储)
    短暂性的时候,我们只需要将数据存在内存,只在运行时可用。
    持久性存储,可以分为 浏览器端 与 服务器端。
    浏览器:
    cookie:通常用于存储用户身份,登录状态等。
    http中自动携带,体积上限为4k,可自行设置过期时间。
    locaLStorage/sessionStorage:长久储存/窗口关闭删除,体积限制为4-5M
    indexDB
    服务器:
    分布式缓存 redis
    数据库

    7、Web Worker
    现代浏览器为 JavaScript 创造的多线程环境。可以新建并将部分任务分配到 worker 线程并行运行,两个线程可 独立运行,互不干扰,可通过自带的
    消息机制 相互通信。
    用法:
    //创建 worker
    const worker = new Worker('work.js');
    //向 worker 线程推送消息
    worker.postMessage('hello world');
    //监听 worker 线程发送过来的消息
    worker.onmessage = function(event){
    console.log('received message'+event.data);
    }

    限制:
    同源限制
    无法使用 document / window / alert / confirm
    无法加载本地资源

    8、内存泄露
    意外的全局变量:无法被回收
    定时器:未被正确关闭,导致所引用的外部变量无法被释放
    事件监听:没有正确销毁
    闭包:会导致父级中的变量无法被释放
    dom引用:dom元素被删除时,内存中的引用未被正确清空

    chrome中的timeline进行内存标记,可视化查看内存的变化情况,找出异常点。

     服务端与网络

    1、http / https 协议
    1.0、协议缺陷:
    无法复用链接,完成即断开,重新慢启动 和 TCP 3次握手
    head of line blocking:线头阻塞,导致请求之间互相影响
    1.1、改进:
    长连接(默认 keep-alive),复用
    host字段指定对应的虚拟站点
    新增功能:
    断点续传
    身份认证
    状态管理
    cache缓存
    Cache-Control
    Expires
    last-Modified
    Etag
    2.0、
    多路复用
    二进制分帧层:应用层和传输层之间
    首部压缩
    服务端推送
    https:较为安全的网络传输协议:
    证书(公钥)
    SSL加密
    端口443
    TCP:
    三次握手
    四次挥手
    滑动窗口:流量控制
    拥塞处理:
    慢开始
    拥塞避免
    快速重传
    快速恢复
    缓存策略:可分为 强缓存 和协商缓存

    2、常见状态码
    1xx:接受,继续处理
    200:成功,并返回数据
    201:已创建
    202:已接受
    203:成功,但未授权
    204:成功,无内容
    205:成功,重置内容
    206:成功,部分内容
    301:永久移动,重定向
    302:临时移动,可使用原有url
    304:资源未修改,可使用缓存
    305:需代理访问
    400:请求语法错误
    401:要求身份认证
    403:拒绝请求
    404:资源不存在
    500:服务器错误

    3、get/post
    get:缓存,请求长度受限,会被历史保存记录
    post:安全,大数据,更多编码类型
    
    

     4、websocket

         websockt是一个 持久化的协议,基于http,服务端可以主动push

         new Websocket(url)

         ws.onerror = fn

         ws.onclose = fn

         ws.onopen = fn

         ws.onmessage = fn

         ws.send()

    5、TCP三次握手

        建立连接前,客户端和服务端需要通过握手来确认对方:

           客户端发送 syn(同步序列编号)请求,进入 syn_send 状态,等待确认

           服务端接收并确认 syn包后发送 syn+ack 包,进入 syn_recv 状态

           客户端接收 syn+ack包后,发送 ack包,双方进入 established 状态

    6、TCP四次挥手

          客户端 -- FIN --> 服务端,FIN-WAIT

          服务端 -- ACK --> 客户端,CLOSE-WAIT

          服务端 -- ACK,FIN --> 客户端,LAST-ACK

          客户端 -- ACK --> 服务端,CLOSED

    7、node 的 event loop:6阶段

          timer阶段:执行到期的 setTimeout / setInterval 队列回调

          I/O 阶段:执行上轮循环残流的 callback

          idle,prepare

          poll:等待回调

             1、执行回调

             2、执行定时器

                2.1、如有到期的 setTimeout / setInterval ,则返回 timer阶段

                2.2、如有 setImmediate,则前往check阶段

          check:

             执行 setImmediate

          close callbacks

    8、跨域:

         JSONP:利用<script> 标签不受跨域限制的特点,缺点是只能支持get请求

             function jsonp(url,jsonpCallback,success){

                const script = document.createElement('script');

                script.src = url;

                script.async = true;

                script.type = 'text/javascript';

                window[jsonpCallback] = function(data){

                   success && success(data)

                }

                document.body.appendChild(script);

             }

          设置 CORS: Access-Control-Allow-Origin:'*'

          postMessage

    9、安全

         XSS 攻击:注入恶意代码

             cookie 设置 httpOnly

             转义页面上的输入内容和输出内容

        CSRF:跨站请求伪造,防护:
             get不修改数据

             不被第三方网站访问到用户的cookie

             设置白名单,不被第三方网站请求

             请求校验

     vue

    1、nextTick
    在下次dom更新循环结束之后执行延迟回调,可用于获取更新后的dom状态。
    macrotasks 任务的实现: setImmediate / MessageChannel / setTimeout

    2、生命周期
    _init_:
    initLifecyle / Event,往 vm 上挂载各种属性
    callHook: beforeCreated --实例刚创建
    initInjection/initState: 初始化注入和data响应性
    created: 创建完成,属性已经绑定,但还未生成真实dom
    进行元素的挂载: $el / vm.$mount()
    是否有 template: 解析成 render function
    *.vue文件:vue-loader 会将 <template> 编译成 render function
    beforeMount: 模板编译 / 挂载之前
    执行 render function,生成真实的 dom,并替换到 dom tree 中
    mounted:组件已挂载

    update:
    执行diff算法,比对改变是否需要触发UI更新
    flushScheduleQueue:
    watcher.before: 触发 beforeUpdate 钩子 - watcher.run():执行watcher中的notify,通知所有依赖项更新UI
    触发 updated 钩子:组件已更新

    actived / deactivated(keep-alive):不销毁,缓存,组件激活与失活。

    destroy:
    beforeDestroy:销毁开始
    销毁自身且递归销毁子组件以及事件监听:
    remove():删除节点
    watcher.teardown():清空依赖
    vm.$off():解绑监听
    destroyed:完成后触发钩子

    哇哦,下面见代码,看vue的初始化
    new Vue({})
    //初始化 vue 实例
    function _init(){



    }


    3、数据响应(数据劫持)
    数据响应的实现由两部分构成:观察者 watcher 和 依赖收集器 dep, 其核心是 defineProperty 这个方法,它可以重写属性的 get 与 set
    方法,从而完成监听数据的改变。
    Observe(观察者)观察 props 与 state:
    遍历 props与state,对每个属性创建独立的监听器(watcher)。
    使用 defineProperty 重写每个属性的 get/set(defineReactive):
    get:收集依赖
    Dep.depend():
    watcher.addDep()
    set:派发更新
    Dep.notify()
    watcher.update()
    queenWatcher()
    nextTick
    flushScheduleQueue
    watcher.run()
    updateComponent()

    见代码梳理:
    let data = {a:1};
    //数据响应性
    observe(data)
    //初始化观察者
    new Watcher(data,'name',updateComponent)
    data.a = 2;
    //简单表示用于数据更新后的操作
    function updateComponent(){
    vm._update() // patchs
    }
    //监视对象
    function observe(obj){
    //遍历对象,使用 get/set 重新定义对象的每个属性值
    Object.keys(obj).map(key => {
    defineReactive(obj,key,obj[key])
    })
    }

    function defineReactive(obj,k,v){
    //递归子属性
    if(type(v)=='object') observe(v)

    //新建依赖收集器
    let dep = new Dep()
    //定义 get/set
    Object.defineProperty(obj,k,{
    enumerable:true,
    configurable:true,
    get:function reactiveGetter(){
    //当有获取该属性时,证明依赖于该对象,因此被添加进收集器中
    if(Dep.target){
    dep.addSub(Dep.target)
    }
    return v
    },
    //重新设置值时,触发收集器的通知机制
    set:function reactiveSetter(nV){
    v = nV
    dep.notify()
    }
    })

    },
    //依赖收集器
    class Dep{
    construtor(){
    this.subs = [];
    }
    addSub(sub){
    this.subs.push(sub)
    }
    notify(){
    this.subs.map(sub=>{
    sub.update()
    })
    }
    }
    Dep.target = null

    //观察者
    class Watcher{
    constructor(obj,key,cb){
    Dep.target = this;
    this.cb = cb
    this.obj = obj
    this.key = key
    this.value = obj[key]
    Dep.target = null
    }
    addDep(Dep){
    Dep.addSub(this)
    }
    update(){
    this.value = this.obj[this.key]
    this.cb(this.value)
    }
    before(){
    callHook('beforeUpdate')
    }
    }

    4、virtual dom 原理实现
    创建dom树
    树的diff,同层对比,输入 patchs(listDiff/diffChildren/diffProps):
    没有新的节点,返回
    新的节点 tagName 与 key 不变,对比props,继续递归遍历子树:
    对比属性(对比新旧属性列表):
    旧属性是否存在与新属性列表中
    都存在的是否有变化
    是否出现旧列表中没有的新属性
    tagName 和 key值变化了,则直接替换成新节点
    渲染差异:
    遍历 patchs,把需要更改的节点取出来
    局部更新 dom

    见代码梳理:
    //diff算法的实现
    function dff(oldTree,newTree){
    //差异收集
    let pathchs = {}
    dfs(oleTree,newTree,0,patchs)
    return pathchs
    }
    function dfs(oldNode,newNode,index,pathchs){
    let curPathchs = [];
    if(newNode){
    //当新旧节点的tagName和key值完全一致时
    if(oldNode.tagName === newNode.tagName && oldNode.key === newNode.key){
    //继续比对属性差异
    let props = diffProps(oldNode.props,newNode.props)
    curPathchs.push({type:'changeProps',props})
    //递归进入下一层级的比较
    diffChildrens(oldNode.children,newNode.children,index,pathchs)
    }else{
    //当tagName 或者 key 修改了后,表示已经时全新节点,无需再比
    curPathchs.push({type:'replaceNode',node:newNode})
    }
    }
    //构建出整颗差异树
    if(curPathchs.length){
    if(pathchs[index]){
    pathchs[index] = pathchs[index].concat(curPathchs)
    }else{
    pathchs[index] = curPathchs
    }
    }
    }
    //属性对比实现
    function diffProps(oldProps,newProps){
    let propsPathchs = []
    //遍历新旧属性列表,查找删除项,查找修改项,查找新增项
    forin(oldProps,(k,v)=>{
    if(!newProps.hasOwnProperty(k)){
    propsPathchs.push({type:'remove',prop:k})
    }else{
    if(v !== newProps[k] ){
    propsPathcchs.push({type:'chage',prop:k,value:newProps[k]})
    }
    }
    })
    forin(newProps,(k,v)=>{
    if(!oldProps.hasOwnProperty(k)){
    propsPathchs.push({type:'add',prop:k,value:v})
    }
    })
    return propsPathchs
    }
    //对比子级差异
    function diffChildrens(oldChild,newChild,index,pathchs){
    //标记子级的删除、新增、移动
    let {change,list} = diffList(oldChild,newChild,index,pathchs)
    if(change.length){
    if(pathchs[index]){
    pathchs[index] = pathchs[index].concat(chage)
    }else{
    pathchs[index] = change
    }
    }
    //根据key获取原本匹配的节点,进一步递归从头开始对比
    oldChild.map((item,i)=>{
    let keyIndex = list.indexOf(item,key)
    if(keyIndex){
    let node = newChild[keyIndex]
    //进一步递归对比
    dfs(item,node,index,pathchs)
    }
    })
    }
    //列表对比,主要也是根据key 值查找匹配项
    //对比出新旧列表的新增,删除,移动
    function diffList(oldList,newList,index,pathchs){
    let chage = []
    let list = []
    const newKeys = getKey(newList)
    oldList.map(v=>{
    if(newKeys.indexOf(v.key) > -1){
    list.push(v.key)
    }else{
    list.push(null)
    }
    })
    //标记删除
    for(let i=list.length-1;i>=0;i++){
    if(!list[i]){
    list.splice(i,1)
    change.push({type:'remove',index:1})
    }
    }
    //标记新增和移动
    newList.map((item,i)=>{
    const key = item.key
    const index = list.indexOf(key)
    if(index===-1 || key==null){
    //新增
    change.push({type:'add',node:item,index:i})
    list.splice(i,0,key)
    }else{
    //移动
    if(index !==i){
    change.push({
    type:'move',
    form:index,
    to:i
    })
    move(list,index,i)
    }
    }
    })
    return { change , list }
    }

    5、proxy 相比于 defineProperty 的优势
    数组变化也能监听到。
    不需要深度遍历监听
    let data = {a:1}
    let reactiveData = new Proxy(data,{
    get:function(target,name){
    //....
    }
    })

    6、vue-router
    mode:
    hash
    history
    跳转
    this.$router.push()
    <router-link to=""></router-link>
    占位
    <router-view></router-view>

    7、vuex
    state:状态中心
    mutations:更改状态
    actions:异步更改状态
    getters:获取状态
    modules:将 state 分成 多个 modules ,便于管理


    vue.js 源码揭秘网址:
    https://ustbhuangyi.github.io/vue-analysis/v2/prepare/build.html#%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC 

    算法:

    //五大算法
    贪心算法:局部最优解法
    分治算法:分成多个小模块,与原问题性质相同
    动态规划:每个状态都是过去历史的一个总结
    回溯法:发现原先选择不优时,退回重新选择
    分支限界法

    基础排序算法:
    冒泡排序:两两比较
    function bubleSort(arr){
    let len = arr.length;
    for(let i=len;i>=2;i--){ //这个地方也可以直接写 i>=1
    for(let j=0;j<=i-1;j++){ //对应的这里改成 j<=i 即可
    if(arr[j] > arr[j+1]){
    [arr[j],arr[j+1]] = [arr[j+1],arr[j]]
    }
    }
    }
    return arr;
    }
    插入排序:即将元素插入到已排序好的数组中
    function insertSort(arr){
    for(let i=0;i<arr.length;i++){
    for(let j=i;j>0;j--){
    if(arr[j] < arr[j-1]){
    [arr[j],arr[j-1]] = [arr[j-1],arr[j]];
    }else{
    break;
    }
    }
    }
    return arr;
    }

    递归运用(费波那契数列):爬楼梯问题
    初始在第一级,到第一级有1种方法( s(1)=1),到第二级也只有一种方法( s(2)=1 ),第三级(s(3) = s(1)+s(2))
    function cStairs(n){
    if(n ===1 || n===2){
    return 1;
    }else{
    return cStairs(n-1) + cStairs(n-2)
    }
    }

    数据树:
    二叉树:最多只有两个子节点
    完全二叉树
    满二叉树:
    深度为h,有n个节点,且满足 n=2^h -1
    二叉查找树:是一种特殊的二叉树,能有效地提高查找效率 BST
    小值在左,大值在右
    节点n的所有左子树值小于n,所有右子树值大于n。
    ...

    天平找次品
    有n个硬币,其中1个为假币,假币重量较轻,有一把天平,需要称多少次能保证一定找到假币?
    三等分算法:
    1、将硬币分成3组,随便取其中两组天平称重
    平衡,假币在剩余那组,取其继续1循环
    不平衡,假币在轻的那一组,取其继续1循环。

    //记录小程序里面有个api获取滚动距离

    wx.createSelectorQuery().select('#container').boundingClientRect(function(rect){ //container这个容器一定
    //是最大那个div。
    if(rect){
    bottom = Math.abs(rect.bottom);
    if(parseInt(bottom) == windowHeight){ //这里的windowHeight是通过wx.getSystemInfo()获取的。
    //然后这里可以做处理了
    //这里表示 滚动到底部了
    }else{

    }
    }
    })

    参考链接:https://juejin.im/post/6844903776512393224#heading-13

  • 相关阅读:
    pyCharm django 中新加app
    Amazon Redshift 架构
    Amazon DynamoDB 概述
    Amazon EFS 性能
    Amazon RDS 现在支持 Storage Auto Scaling
    只读副本与多可用区部署
    RDS也和EC2一样支持snapshot的跨Region复制:Cross-Region Snapshot Copy for Amazon RDS
    Automated Cross-Region Snapshot Copy for Amazon Redshift
    EC2的跨Region复制或部署,Cross Region EC2 AMI Copy
    RDS for MySQL, PostgreSQL, Aurora 都支持Cross-Region Read Replicas。采用异步复制,只读副本有网络时延
  • 原文地址:https://www.cnblogs.com/sunnyeve/p/13948569.html
Copyright © 2011-2022 走看看