精华内容
下载资源
问答
  • Vue中的双向绑定 这篇文章用简化Vue模型和双向绑定基本原理进行讲解,最后会放上Demo代码供大家...所以这篇文章不会深入教你双向绑定基本原理到底是什么,而是默认你对双向绑定有一定了解,想了解它和Vue渲染过程

    Vue中的双向绑定

    这篇文章用简化的Vue模型和双向绑定基本原理进行讲解,最后会放上Demo代码供大家调试, 要理解双向绑定并不难,看过双向绑定基本原理的同学都可以说出个一二,但很多人都处于:"哇,Object.defineProperty这么神奇,学到了学到了!",但是具体Vue是怎么把它和组件渲染关联的,就有些懵逼。笔者之前也处于这种状态,深有体会,什么?你说你没有这种感觉?!那没事了……

    所以这篇文章不会深入教你双向绑定基本原理到底是什么,而是默认你对双向绑定有一定的了解,想了解它和Vue渲染过程是如何关联,希望在这里可以让你学习到一点东西

    第一步

    让我们先定义一个超级简化的VueClass类来模拟Vue,为了专注双向绑定这个实现逻辑,这个类的结构非常简单

    • 拥有一个render函数(外部传入)
    • 拥有一个更新组件的函数updateComponent

    这里为什么有一个render函数?首先我们要知道render函数做了什么和双向绑定息息相关的事情。 如果你不熟悉render,那你只要写过Vue就一定知道<template></template>,这是Vue中定义的,你的浏览器并不能识别template标签,Vue提供了compiler去编译<template></template>,最终会生成render函数,所以最后在浏览器执行的,就是这个render函数

      class VueClass {
          constructor(options) {
              // 只关心data
              this.data = options.data
              // Vue的编译器会把模板template编译成render函数
              this.render = options.render
          }
          // 更新组件,可以理解为是VueClass的渲染函数
          updateComponent() {
              // 构建VNode树(不理解VNode树没关系,不影响双向绑定理解)
              this.render()
              // ...
              // 省略挂载Dom的操作
          }
      }
    复制代码

    大家在使用模板编写代码时,会绑定一些数据上去,比如下面这样:

    <template>{{msg}}</template>
    复制代码

    要想展示msg,就得获取它的值,所以render函数被调用时会获取到被绑定到模板中的变量!! 现在不理解没关系,现在大家先记住这一点,render函数被调用时会获取到被绑定到模板中的变量!!,这对理解双向绑定很重要。这也是我要在简化模型中再定义一个render的原因,之后我们会模拟render获取模板变量的过程。

    第二步:双向绑定基本原理

    好了,上面的代码先放在一边,下面上关键性代码observe的实现,这里我们只考虑target是对象的情况,对于数组,Vue做了额外的一些处理,这里暂不提及。

    代码逻辑也不复杂,递归对target对象的每一个属性进行配置,拦截它的gettersetter,这样我们就可以在属性访问或属性赋值的时候对它为所欲为进行一些其他操作了(比如渲染)

    是的,这一切是不是都这么熟悉,当你访问一些属性进行修改时,会触发该属性的setter函数,如果这时候可以插入一个渲染逻辑重新渲染页面,那这不就是双向绑定吗!

    function observe(target) {
      if(target && typeof target !== 'object') return
        Object.keys(target).forEach(key => {
            defineReactive(target, key, target[key])
        }) 
    }
    
    function defineReactive(obj, key, val) {
      // 对子属性进行递归, 这里不需要判断参数是否合法,判断在observe内部进行,如果val不是对象,则不会进行任何操作
      observe(val)
      Object.defineProperty(obj, key, {
          // 可枚举
          enumerable: true,
          // 可配置
          configurable: true,
          get() {
              // 当属性被访问时触发
              return val
          },
          set(value) {
              // 当属性被赋值时触发
              val = value
          }
      })
    }
    复制代码

    我们需要借助两个类, DepWatcher,如果你要问为啥要两个类,那就来个套公式大法:既然是观察者模式了,那肯定有订阅者和发布者啊,先不管DepWatcher对应哪个,总之要两个就对了!

    观察者模式

    不理解观察者模式,别急,借一下修大的例子,Dep是产品经理,Watcher是苦逼程序员。

    现在公司开了一个新项目,这个项目就是要"渲染页面",但是具体的需求还没出(还没有人改变数据),于是产品经理(Dep)预先创了一个“xx2077迭代”群,既然Dep是群主,他当然拥有拉人进群的权限,把干活的人(Watcher)拉进群之后,可能群里就没人说话了,因为需求还没定下来,大家可以去干自己的事,互不打扰。

    突然某一天,需求文档出了,要按照文档(客户修改了数据)重新渲染页面,产品经理(Dep)立马通知大家,“2077需求文档终于出了!大家来干活吧,加油打工人!”于是大家(Watcher)开始了手头的工作……

    这里拉人进群的操作就是添加订阅者,在群里发布需求更新文档,就是发布消息,订阅者们就开始干活。这就是观察者模式

    这里为了简化逻辑,Watcher类只举例渲染用的Watcher,啥意思呢,就是这个Watcher只会干一件事,那就是渲染页面,所以我们也可以叫它渲染Watcher,实际Vue源码中是传入了一个回调函数(可以干任何事),不理解的我之后会有一小段代码来说明

    // 产品经理Dep类
    class Dep {
      constructor() {
          // 创建一个群
          this.deps = []
       }
      // 拥有拉人进群的权限, sub是一个Watcher
      addSub(sub) {
          this.deps.push(sub)
      }
      // 通知大家干活啦
      notify() {
        for(let i=0,j=this.deps.length; i<j; i++) {
            // 这个群的每个打工仔都得干活
            this.deps[i].update()
        }
      }
    }
    
    // 苦逼程序员Watcher类
    class Watcher {
      // 初始化,传入一个VueClass实例,为啥要传?打工人肯定得知道老板是谁啊,不然谁发工资?
      constractor(vm) {
          this.vm = vm
      }
      // 打工人开始干活
      update() {
          // 我是渲染Watcher,要干活了!(渲染)
      }
    }
    复制代码

    打工仔Watcher

    现在我们有三个类VueClassDepWatcher,以及一个黑科技函数observe

    setter

    上面的例子中,产品经理Dep是有感知需求文档变化(客户修改数据)的能力的,于是,我们把它放到对应属性的setter中,只要修改了数据,就会调用setter,产品经理Dep就可以感知变化,然后发送通知,大家就开始干活

    属性数据修改 ->> setter被触发!! ->> 调用deps.notify 通知所有Watcher

    现在我们要改造一下defineReactive,我们之前定义了每个属性的gettersetter,我说过是为了做拦截,现在让我们为所欲为一下

    function observe() {
    	//... 没有改变
    }
    
    function defineReactive(obj, key, val) {
    	// 把每个属性都当一个项目组,每个项目组都安排一个产品经理
        let deps = new Dep()
        
       	observe(val)
    	Object.defineProperty(obj, key, {
        	enumerable: true,
            configurable: true,
        	get() {
            	// Dep.target是全局性的,值是当前正在等待入群的Watcher
            	if(Dep.target) {
                	deps.addSub(Dep.target)
                }
            	return val
            },
            set(value) {
                // 稍微做个简单的判断,如果值没改变,不做任何操作
                if(val === value) return
                val = value
                // **当该属性值被更新时,通知所有打工仔干活**
                deps.notify()
            }
        })
    }
    
    class Watcher {
    	constructor(vm) {
        	this.vm = vm
        	Dep.target = this
            // 初始化Watcher的时候先调用一次渲染函数
            this.vm.updateComponent()
            // 添加完成,划掉这个名字
            Dep.target = null
        }
        update() {
        	// 这个打工仔专门干渲染的事
        	this.vm.updateComponent()
        }
    }
    复制代码

    getter

    这里为什么要在Watcher初始化的时候调用渲染函数,还记得我之前说过,render函数内部会获取到被绑定到模板中的变量!!,Watcher的初始化步骤就是这样的:

    初始化Watcher对象 ->> vm.updateComponent ->> vm.render [拿到被绑定的值] ->> 触发getter!!! ->> 把Watcher加入项目组

    这就是Vue巧妙的地方,通过触发对象属性的getter来进行一系列操作,至于在Watcher初始化的时候调用渲染函数是否合理,当然不能每个Watcher都这样做,不然浏览器疯狂渲染还得了,我上面也说了,我们这个例子里的Watcher只干一件事,那就是渲染,而Vue的渲染Watcher是在组件初始化的时候被new出来的,也就是说,Vue定义了渲染的函数,但是不会自己去调用,而是全权交给干渲染活的打工仔渲染Watcher来调用,第一次渲染是这样,之后触发的渲染也是这样。

    这么说不太直观,我举个其他Watcher的例子,我们例子里的Watcher把工作内容定死了,但实际上,在初始化Watcher的时候会传递一个exp来描述他需要关注的工作对象是谁,回调函数cb来说明他的工作内容是什么

    // exp来说明绑定值的对象
    // cb说明工作内容(触发watcher后要干什么)
    class WatcherOther {
        constructor(vm, exp, cb) {
            this.vm = vm
            this.exp = exp
            this.cb = cb
            this.val = this.get()
        }
        get() {
            Dep.target = this
            // 和渲染watcher一样 获取exp这个属性对应的值,触发它的getter,把watcher添加进对应的Dep
            let value = this.vm.data.exp
            Dep.target = null
            return value
        }
        update() {
            this.cb()
        }
    }
    复制代码

    我希望大家能理解我把Watcher类直接简化为渲染Watcher类的意义,我不想在Watcher中添加一些回调逻辑,这样对理解双向绑定的核心没有任何意义,大家只要知道我们现在使用的Watcher是专门用来渲染的就好

    其实到这里,整个流程已经基本完成了,但如果要把demo跑起来让他可以允许,还剩最后一件事: 伪造render函数内部获取模板参数的操作

    拿之前的代码做🌰,假设有这样的模板函数,把它放到编译器里,它会生成一个render函数

    <template>{{msg}}</template>
    
    <script>
    let vm = new VueClass({
        data: {
            msg: 'hello 2077'
        }
    })
    </script>
    
    复制代码

    模板会被编译成一个render函数,就是这么简单,最后会这样创建一个VueClass实例:

    let vm = new VueClass({
        data: {
            msg: 'hello 2077'
        },
        render() {
            let msg = this.data.msg
            console.log(`开始生成虚拟节点,发现用户使用了${msg}!`)
        }
    })
    复制代码

    上面的代码都是直接手写的,没有测试,只理了逻辑,下面上完整代码,大家可以copy下来自己跑一下:

    class VueClass {
      constructor(options) {
          this.data = options.data;
          // Vue的编译器会把模板template编译成render函数
          this.render = options.render;
      }
      // 更新组件,可以理解为是VueClass的渲染函数
      updateComponent() {
          // 构建VNode树(不理解VNode树没关系,不影响双向绑定理解)
          this.render();
          // ...
          // 省略挂载Dom的操作
      }
    }
    
    function observe(target) {
      if (target && typeof target !== "object") return;
      Object.keys(target).forEach((key) => {
          defineReactive(target, key, target[key]);
      });
    }
    
    function defineReactive(obj, key, val) {
      // 把每个属性都当一个项目组,每个项目组都安排一个产品经理
      let deps = new Dep();
    
      observe(val);
      Object.defineProperty(obj, key, {
          // 可枚举
          enumerable: true,
          // 可配置
          configurable: true,
          get() {
              // Dep.target是全局性的,值是当前正在等待入群的Watcher
              if (Dep.target) {
                  deps.addSub(Dep.target);
              }
              return val;
          },
          set(value) {
              // 稍微做个简单的判断,如果值没改变,不做任何操作
              if (val === value) return;
              val = value;
              // **当该属性值被更新时,通知所有打工仔干活**
              deps.notify();
          },
      });
    }
    
    // 产品经理Dep类
    class Dep {
      constructor() {
          // 创建一个群
          this.deps = [];
      }
      // 拥有拉人进群的权限, sub是一个Watcher
      addSub(sub) {
          this.deps.push(sub);
      }
      // 通知大家干活啦
      notify() {
          for (let i = 0, j = this.deps.length; i < j; i++) {
              // 这个群的每个打工仔都得干活
              this.deps[i].update();
          }
      }
    }
    
    // 苦逼程序员Watcher类
    class Watcher {
      // 初始化,传入一个VueClass实例,为啥要传?打工人肯定得知道老板是谁啊,不然谁发工资?
      constructor(vm) {
        this.vm = vm;
        Dep.target = this;
        // 初始化Watcher的时候先调用一次渲染函数
        this.vm.updateComponent();
        // 添加完成,划掉这个名字
        Dep.target = null;
      }
      // 打工人开始干活
      update() {
        // 这个打工仔专门干渲染的事
        this.vm.updateComponent();
      }
    }
    
    // 开始测试
    let vm = new VueClass({
        data: {
          msg: "hello 2077",
          other: "other text"
        },
        render() {
            console.log(`我拿到了this.data.msg,值为${this.data.msg},开始生成VNode树`);
        },
    });
    
    // 监听vm.data
    observe(vm.data);
    
    // 创建vm实例的渲染Watcher,这个过程会自动开始第一次渲染
    new Watcher(vm);
    
    // 修改data的属性值 看看会发生什么吧!
    vm.data.msg = "2077又跳票了";
    
    vm.data.other = "other text changed"
    
    复制代码

    Amazing!! vm.data.msg改变的时候,触发了render函数,但是vm.data.other改变却没有触发,为什么呢,秘密就在于vm.data.other并没有被绑定到模板上,也就是说 render函数中并没有出现过vm.data.other,那么它的getter不会被触发,自然就不会为它添加Watcher

    如果你看完了这段代码,稍微思考一下可能会有几个疑问

    1. 为什么要给每个属性值new一个Dep,在例子里每个Dep里最多也只有一个Watcher,也完全没必要用数组去储存Watcher

      答:因为例子里是只有一个渲染Watcher,但是实际情况下用户还会对一些属性手写watch监听(你肯定干过),这时候就要为这个属性新增一个Watcher了,当值发生改变时,会调用Deps.notify依次触发多个Watcher

    2. 如果再往模版上绑定一个数据,对它进行修改,渲染Watcher不就会多次触发渲染吗

      答:如果你能想到这个问题,恭喜你基本已经完全理解Vue双向绑定原理了。在我们的例子里,绑定多个数据,确实是多次触发render,并且同一个数据在一个tick内多次改变值,也会触发多次render。这个很好解决,Vue也针对于这一块做了很多优化,在一个tick内,你可以使用map来保存触发过的Watcher id,如果发现有重复的id出现,不再重复触发。

    3. 渲染Watcher和普通Watcher除了干的活不一样,还有什么其他区别吗?

      答: 有! 渲染Watcher会自动添加到每一个被render函数调用过的属性所对应的deps里,而普通Watcher只会被添加到指定的绑定属性上

      其实双向绑定这一块,Vue还做了其他优化,这里不一一举例,如果感兴趣,强烈推荐自己去阅读源码,或许你在阅读时你会很痛苦,但是痛苦过后,你会发现自己有质地的提升。

    如果大家想学习前端方面的技术,我把我多年的经验分享给大家,还有一些学习资料,免费领取V:xxy12311007

     

     

    展开全文
  • 本人个接触JAVA2个月的菜鸟,最近在研究UDP广域网的通信,实现的过程也就是常说的双向通信:客户端(局域网内)先发数据给远方的服务器(服务器公网IP,映射了个端口),服务器能收到,但是服务器不能回...
  • 13.5.2 开发过程是漫长的 13.6 小结 第14课 程序调试 14.1 程序的可调试性 14.1.1 增加注释 14.1.2 使用log 14.2 程序调试的基本方法 14.2.1 借助编译器的代码审查 14.2.2 跟踪程序执行流程 14.2.3 断点...
  • 13.5.2 开发过程是漫长的 380 13.6 小结 380 第14课 程序调试 381 14.1 程序的可调试性 382 14.1.1 增加注释 382 14.1.2 使用log 382 14.2 程序调试的基本方法 390 14.2.1 借助编译器的代码审查 ...
  • 27、GC是什么? 为什么要有GC?  GC是垃圾收集意思(Gabage Collection),内存处理是编程人员容易出现问题地方,忘记或者错误内存回收会导致程序或系统不稳定甚至崩溃,Java提供GC功能可以自动监测对象...
  • 器内容的改变,而是从工程的角度直接看程序运行和电路工作的过程和结果。 对于这样的仿真实验,从某种意义上讲,弥补了实验和工程应用间脱节的矛 第5 页共27 页 盾和现象。 3 系统详细设计: 3.1 硬件设计 3.1.1 ...
  • 4.2. 动态链接的过程 4.3. 共享库的命名惯例 5. 虚拟内存管理 21. 预处理 1. 预处理的步骤 2. 宏定义 2.1. 函数式宏定义 2.2. 内联函数 2.3. #、##运算符和可变参数 2.4. 宏展开的步骤 3. 条件预处理指示 4. 其它...
  • 1.1 Nginx是什么 1.2 为什么选择Nginx 1.3 准备工作 1.3.1 Linux操作系统 1.3.2 使用Nginx必备软件 1.3.3 磁盘目录 1.3.4 Linux内核参数优化 1.3.5 获取Nginx源码 1.4 编译安装Nginx 1.5 configure详解 1.5.1 ...
  • 全书共8章,首先讲解Linux系统引导过程;然后对Linux内核3大核心模块——内存管理、进程管理、中断和异常处理进行了深入分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中...
  • 全书共8章,首先讲解Linux系统引导过程;然后对Linux内核3大核心模块——内存管理、进程管理、中断和异常处理进行了深入分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中...
  • 全书共8章,首先讲解Linux系统引导过程;然后对Linux内核3大核心模块——内存管理、进程管理、中断和异常处理进行了深入分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中...
  • 全书共8章,首先讲解Linux系统引导过程;然后对Linux内核3大核心模块——内存管理、进程管理、中断和异常处理进行了深入分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中...
  • 全书共8章,首先讲解Linux系统引导过程;然后对Linux内核3大核心模块——内存管理、进程管理、中断和异常处理进行了深入分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中...
  • 全书共8章,首先讲解Linux系统引导过程;然后对Linux内核3大核心模块——内存管理、进程管理、中断和异常处理进行了深入分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中...
  • 全书共8章,首先讲解Linux系统引导过程;然后对Linux内核3大核心模块——内存管理、进程管理、中断和异常处理进行了深入分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中...
  • 全书共8章,首先讲解Linux系统引导过程;然后对Linux内核3大核心模块——内存管理、进程管理、中断和异常处理进行了深入分析; 在此基础上,对时间度量、系统调用进行了分析和讨论;最后讲解了Linux内核中...
  • UART和波特率

    2010-08-04 15:28:00
    什么是 UARTUART一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。在嵌入式设计中,UART用来与PC进行通信,包括与监控调试器和其它器件,如EEPROM通信。 UART通信 UART首先将接收...
    什么是 UART
    UART是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。在嵌入式设计中,UART用来与PC进行通信,包括与监控调试器和其它器件,如EEPROM通信。

    UART通信

    UART首先将接收到的并行数据转换成串行数据来传输。消息帧从一个低位起始位开始,后面是7个或8个数据位,一个可用的奇偶位和一个或几个高位停止位。接收器发现开始位时它就知道数据准备发送,并尝试与发送器时钟频率同步。如果选择了奇偶,UART就在数据位后面加上奇偶位。奇偶位可用来帮助错误校验。

    在接收过程中,UART从消息帧中去掉起始位和结束位,对进来的字节进行奇偶校验,并将数据字节从串行转换成并行。UART也产生额外的信号来指示发送和接收的状态。例如,如果产生一个奇偶错误,UART就置位奇偶标志。

    数据方向和通信速度

    数据传输可以首先从最低有效位(LSB)开始。然而,有些UART允许灵活选择先发送最低有效位或最高有效位(MSB)。

    微控制器中的UART传送数据的速度范围为每秒几百位到1.5Mb。例如,嵌入在ElanSC520微控制器中的高速UART通信的速度可以高达1.1152Mbps。UART波特率还受发送和接收线对距离(线长度)的影响。

    目前,市场上有只支持异步通信和同时支持异步与同步通信的两种硬件可用于UART。前者就是UART名字本身的含义,在摩托罗拉微控制器中被称为串行通信接口(SCI);Microchip微控制器中的通用同步异步收发器(USART)和在富士通微控制器中的UART是后者的两个典型例子。

    计算机中的UART

    UART是计算机中串行通信端口的关键部分。在计算机中,UART相连于产生兼容RS232规范信号的电路。RS232标准定义逻辑“1”信号相对于地为 3到25伏,而逻辑“0”相对于地为-3到-25伏。所以,当一个微控制器中的UART相连于PC时,它需要一个RS232驱动器来转换电平。 调制解调器的通讯速度。波特率是指线路状态更改的次数。只有每个信号符合所传输数据的一位时,才等于每秒位数。

    为了在彼此之间通讯,调制解调器必须使用相同的波特率进行操作。如果将调制解调器的波特率设置为高于其他的调制解调器的波特率,则较快的调制解调器通常要改变其波特率以匹配速度较慢的调制解调器。

    波特率(BaudRate)
      模拟线路信号的速率,也称调制速率,以波形每秒的振荡数来衡量。如果数据不压缩,波特率等于每秒钟传输的数据位数,如果数据进行了压缩,那么每秒钟传输的数据位数通常大于调制速率,使得交换使用波特和比特/秒偶尔会产生错误。
    波特率是指数据信号对载波的调制速率,它用单位时间内载波调制状态改变的次数来表示,其单位是波特(Baud)。波特率与比特率的关系是比特率=波特率X单个调制状态对应的二进制位数。

    在信息传输通道中,携带数据信息的信号单元叫码元,每秒钟通过信道传输的码元数称为码元传输速率,简称波特率。波特率是传输通道频宽的指标。
    每秒钟通过信道传输的信息量称为位传输速率,简称比特率。比特率表示有效数据的传输速率。

    波特率
    电子通信领域,波特率即调制速率,指的是信号被调制以后在单位时间内的波特数,即单位时间内载波参数变化的次数。它是对信号传输速率的一种度量,通常以“波特每秒”(Bps)为单位。 波特率有时候会同比特率混淆,实际上后者是对信息传输速率(传信率)的度量。波特率可以被理解为单位时间内传输码元符号的个数(传符号率),通过不同的调制方法可以在一个码元上负载多个比特信息。

    波特率与比特率
    比特率 在数字信道中,比特率是数字信号的传输速率,它用单位时间内传输的二进制代码的有效位(bit)数来表示,其单位为每秒比特数bit/s(bps)、每秒千比特数(Kbps)或每秒兆比特数(Mbps)来表示(此处K和M分别为1000和1000000,而不是涉及计算机存储器容量时的1024和1048576)。
    波特率 波特率指数据信号对载波的调制速率,它用单位时间内载波调制状态改变次数来表示,其单位为波特(Baud)。 波特率与比特率的关系为:比特率=波特率X单个调制状态对应的二进制位数。
    如何区分两者? 显然,两相调制(单个调制状态对应1个二进制位)的比特率等于波特率;四相调制(单个调制状态对应2个二进制位)的比特率为波特率的两倍;八相调制(单个调制状态对应3个二进制位)的比特率为波特率的三倍;依次类推。
    展开全文
  • 用C语言进行编程不仅仅在程序中使用正确的句法,编程的风格以及程序的调试在编写程序的过程中也占有相当大的篇幅,从而有助于程序的良好运行且易于维护。本书不仅仅向你介绍编程的机制,同时也告诉你如何创建易于...
  • Linux内核源码+电子书

    热门讨论 2011-02-21 15:13:10
    10.1.1 什么是模块 10.1.2 为什么要使用模块? 10.2 实现机制 10.2.1 数据结构 10.2.2 实现机制分析 10.3 模块装入和卸载 10.3.1 实现机制 10.3.2 如何插入和卸载模块 10.4 内核版本 10.4.1 内核版本与...
  • 10.1.1 什么是模块 10.1.2 为什么要使用模块? 10.2 实现机制 10.2.1 数据结构 10.2.2 实现机制分析 10.3 模块装入和卸载 10.3.1 实现机制 10.3.2 如何插入和卸载模块 10.4 内核版本 10.4.1 内核版本与...
  • 利用计算机算法为计算机解题的过程实际上在实施某种算法。 (1)算法的基本特征 算法一般具有4个基本特征:可行性、确定性、有穷性、拥有足够的情报。 (2)算法的基本运算和操作 算法的基本运算和操作包括:算术...
  • 如虚拟主机调试,则将网站文件全部上传到空间商指定文件夹下,再执行安装过程,安装路径网址后加install/index.php,比如你网址http://www.abc.com,则安装路径http://www.abc.com/install/index.php,...
  • java 面试题 总结

    2009-09-16 08:45:34
    24、GC是什么? 为什么要有GC?  GC是垃圾收集意思(Gabage Collection),内存处理是编程人员容易出现问题地方,忘记或者错误内存回收会导致程序或系统不稳定甚至崩溃,Java提供GC功能可以自动监测对象...
  • JAVA面试题最全集

    2010-03-13 13:09:10
    87.UNIX中QT是什么意思? 88.在软件开发生命周期中哪个阶段开始测试? 89.dotnet与J2EE比较? 90.什么是ActiveX? 91.Java中IDL是什么? 92.ISO9000和CMM是什么?IS09000和CMM(软件能力成熟度模型)认证是国际上...
  • ASP.NET精品课程+源代码

    千次下载 热门讨论 2009-01-05 20:15:51
    本课程通过一个ASP.NET网站构建向学生阐释ASP.NET是什么,怎么来开发。 涵盖了代码规范、运行模型、服务控件、验证控件、数据绑定技术、ADO.NET技术、数据库技术、文件操作等内容。 所列出内容均是ASP.NET开发...
  • windowsnt 技术内幕

    2014-04-09 20:47:17
    多域环境下帐号转置 集中式管理简介 配置单向和双向委托 理解委托域和受托域之间差别 使用内建组管理委托 理解传递身份审核 跨越委托向用户授权访问资源 管理被破坏委托关系理解委托不可传递性问题 服务器...
  • DELPHI串口编程

    2015-12-10 21:39:48
    第四章 串口编程的调试及其相关工具 27 串口通信编程剖析 第一章 背景知识 1. 概述 串口计算机上I/O接口一种,要掌握串口通信编程相关知识,必须先了解I/O接口相关知识。 I/O接口接口一种。 2. ...
  • asp.net知识库

    2015-06-18 08:45:45
    利用反射实现ASP.NET控件和数据实体之间的双向绑定,并且在客户端自动验证输入内容是否合法 asp.net报表解决方法 SQLDMO类使用 SQL过程自动C#封装,支持从表到基本存储过程生成 使用SQLDMO控制 SQL Server 使用SQL...

空空如也

空空如也

1 2 3
收藏数 48
精华内容 19
关键字:

双向调试的过程是什么