精华内容
下载资源
问答
  • 下面通过两个维度展开编程能力层次模型的讨论。一个维度是编程技能层次,另一个维度是领域知识层次。 编程技能层次编程技能层次,指的程序员设计和编写程序的能力。这是程序员的根本。 0段—非程序员:初学编程者,...

    来自 网络,供参考。对原作者表示感谢!
    前言

    程序员的编程技能随着经验的积累,会逐步提高。我认为编程能力可以分为一些层次。下面通过两个维度展开编程能力层次模型的讨论。一个维度是编程技能层次,另一个维度是领域知识层次。
    编程技能层次

    编程技能层次,指的程序员设计和编写程序的能力。这是程序员的根本。
    

    0段—非程序员:

    初学编程者,遇到问题,完全是懵懵懂懂,不知道该怎么编程解决问题。也就是说,还是门外汉,还不能称之为“程序员”。计算机在他面前还是一个神秘的黑匣子。
    1段—基础程序员:

    学习过一段时间编程后,接到任务,可以编写程序完成任务。

    编写出来的代码,正常情况下是能够工作的,但在实际运行中,碰到一些特殊条件就会出现各类BUG。也就是说,具备了开发Demo软件的能力,但开发的软件真正交付给客户使用,恐怕会被客户骂死。

    程序员程序是写好了,但到底为什么它有时能正常工作,有时又不行,程序员自己也不知道。

    运行中遇到了bug,或者需求改变,需要修改代码或者添加代码,很快程序就变得结构混乱,代码膨胀,bug丛生。很快,就连最初的开发者自己也不愿意接手维护这个程序了。
    2段—数据结构:

    经过一段时间的编程实践后,程序员会认识到“数据结构+算法=程序”这一古训的含义。他们会使用算法来解决问题。进而,他们会认识到,算法本质上是依附于数据结构的,好的数据结构一旦设计出来,那么好的算法也会应运而生。

    设计错误的数据结构,不可能生长出好的算法。

    记得某一位外国先贤曾经说过:“给我看你的数据结构!”
    3段—面向对象:

     再之后,程序员就会领略面向对象程序设计的强大威力。大多数现代编程语言都是支持面向对象的。但并不是说,你使用面向对象编程语言编程,你用上了类,甚至继承了类,你就是在写面向对象的代码了。
    

    我曾经见过很多用Java,Python,Ruby写的面向过程的代码。

    只有你掌握了接口,掌握了多态,掌握了类和类,对象和对象之间的关系,你才真正掌握了面向对象编程技术。

    就算你用的是传统的不支持面向对象的编程语言,只要你心中有“对象”,你依然可以开发出面向对象的程序。

    如,我用C语言编程的时候,会有意识的使用面向对象的技巧来编写和设计程序。用struct来模拟类,把同一类概念的函数放在一起模拟类。如果你怀疑用C语言是否能编写出面向对象的代码,你可以看一下Linux内核,它是用C语言编写的,但你也可以看到它的源代码字里行间散发出的浓浓的“对象”的味道。

    真正掌握面向对象编程技术并不容易。

    在我的技术生涯中,有两个坎让我最感头疼。

    一个坎是Dos向Windows开发的变迁过程中,框架的概念,很长一段时间我都理解不了。Dos时代,都是对函数库的调用,你的程序主动调用函数。Windows时代,则换成了框架。就算是你的main程序,其实也是被框架调用的。UI线程会从操作系统获取消息,然后发送给你的程序来处理。Java程序员熟悉的Spring框架,也是这样一个反向调用的框架。

    现在因为“框架”这个术语显得很高大上,因此很多“类库”/“函数库”都自称为“框架”。在我看来这都是名称的滥用。

    “类库”/“函数库”就是我写的代码调用它们。

    “框架”就是我注册回调函数到框架,框架来调用我写的函数。

    另一个坎就是面向对象。很长一段时间我都不知道应该怎么设计类和类之间的关系,不能很好的设计出类层次结构来。

    我记得当时看到一本外国大牛的书,他讲了一个很简单、很实用的面向对象设计技巧:“叙述问题。然后把其中的名词找出来,用来构建类。把其中的动词找出来,用来构建类的方法”。虽然这个技巧挺管用的,但也太草根了点,没有理论依据,也不严谨。如果问题叙述的不好,那么获得的类系统就会是有问题的。

    掌握面向对象思想的途径应该有很多种,我是从关系数据库中获得了灵感来理解和掌握面向对象设计思想的。
    

    在我看来,关系数据库的表,其实就是一个类,每一行记录就是一个类的实例,也就是对象。表之间的关系,就是类之间的关系。O-Rmapping技术(如Hibernate),用于从面向对象代码到数据库表之间的映射,这也说明了类和表确实是逻辑上等价的。

    既然数据库设计和类设计是等价的,那么要设计面向对象系统,只需要使用关系数据库的设计技巧即可。
    关系数据库表结构设计是很简单的:

    1,识别表和表之间的关系,也就是类和类之间的关系。是一对一,一对多,多对一,还是多对多。这就是类之间的关系。

    2,识别表的字段。一个对象当然有无数多的属性(如,人:身高,体重,性别,年龄,姓名,身份证号,驾驶证号,银行卡号,护照号,港澳通行证号,工号,病史,婚史etc),我们写程序需要记录的只是我们关心的属性。这些关心的属性,就是表的字段,也就是类的属性。“弱水三千,我取一瓢饮”!

    4段—设计模式:

    曾经在网上看到这样一句话:“没有十万行代码量,就不要跟我谈什么设计模式”。深以为然。

    记得第一次看Gof的设计模式那本书的时候,发现虽然以前并不知道设计模式,但在实际编程过程中,其实还是自觉使用了一些设计模式。设计模式是编程的客观规律,不是谁发明的,而是一些早期的资深程序员首先发现的。

    不用设计模式,你也可以写出满足需求的程序来。但是,一旦后续需求变化,那么你的程序没有足够的柔韧性,将难以为继。而真实的程序,交付客户后,一定会有进一步的需求反馈。而后续版本的开发,也一定会增加需求。这是程序员无法回避的现实。

    写UI程序,不论是Web,Desktop,Mobile,Game,一定要使用MVC设计模式。否则你的程序面对后续变化的UI需求,将无以为继。

    设计模式,最重要的思想就是解耦,通过接口来解耦。这样,如果将来需求变化,那么只需要提供一个新的实现类即可。

    主要的设计模式,其实都是面向对象的。因此,可以认为设计模式是面向对象的高级阶段。只有掌握了设计模式,才能认为是真正彻底掌握了面向对象设计技巧。

    我学习一门新语言时(包括非面向对象语言,如函数式编程语言),总是会在了解了其语法后,看一下各类设计模式在这门语言中是如何实现的。这也是学习编程语言的一个窍门。
    5段–语言专家:

    经过一段时间的编程实践,程序员对某一种常用的编程语言已经相当精通了。有些人还成了“语言律师”,擅长向其他程序员讲解语言的用法和各种坑。
    
    这一阶段的程序员,常常是自己所用语言的忠实信徒,常在社区和论坛上和其他语言的使用者争论哪一种语言是最好的编程语言。他们认为自己所用的语言是世界上最好的编程语言,没有之一。他们认为,自己所用的编程语言适用于所有场景。他们眼中,只有锤子,因此会把所有任务都当成是钉子。
    

    6段–多语言专家:

    这一个阶段的程序员,因为工作关系,或者纯粹是因为对技术的兴趣,已经学习和掌握了好几种编程语言。已经领略了不同编程语言不同的设计思路,对每种语言的长处和短处有了更多的了解。
    

    他们现在认为,编程语言并不是最重要的,编程语言不过是基本功而已。

    他们现在会根据不同的任务需求,或者不同的资源来选择不同的编程语言来解决问题,不再会因为没有使用某一种喜爱的编程语言开发而埋怨。

    编程语言有很多种流派和思想,有一些编程语言同时支持多种编程范式。
    静态类型编程范式

    采用静态类型编程范式的编程语言,其变量需要明确指定类型。代表语言:C,C++,Pascal,Objective-C,Java,C#,VB.NET,Swif,Golang。
    这样做的好处是:

    1,编译器可以在编译时就能找出类型错误。

    2,编译器编译时知道类型信息,就可以提高性能。

     这种范式认为,程序员肯定知道变量的类型,你丫要是不知道变量的类型,那你就别混了!编译时,程序会报错。
    
    Swift和Go语言都是静态类型编程语言,但它们都不需要明确指定类型,而是可以通过推断由编译器自动确定其类型。
    

    动态类型编程范式

     采用静态类型编程范式的编程语言,其变量不需要明确指定类型。任意变量,可以指向任意类型的对象。代表语言:Python,Ruby,JavaScript。
    
    动态类型的哲学可以用鸭子类型(英语:ducktyping)这个概念来概括。JamesWhitcombRiley提出的鸭子测试可以这样表述:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
    

    这种范式认为,程序员肯定知道变量的类型和它支持的方法和属性,你丫要是不知道变量的类型,那你就别混了!运行时程序会崩溃!程序崩溃怨谁?怨你自己呗,你不是合格的程序员!
    动态类型的好处是:

    不需要明确定义接口和抽象类型。只要一个类型支持需要的方法和属性,那么就OK。程序会相当灵活和简单。C++,Java,C#视之为命脉的接口/基类,在动态语言这里都视如无物!
    缺点是:

    1,如果类型不对,编译器也无法找到错误,而是运行时程序崩溃。

    2,因为编译器不知道变量的类型,因此无法优化性能。

    面向对象编程范式

    面向对象编程范式,从上世纪70年代末开始兴起。它支持类和类的实例作为封装代码的模块。代表语言:Smalltalk,C++,Objective-C,Java,C#,VB.NET,Swift,Go,Python,Ruby,ActionScritp,OCaml.
    

    早期编程语言都是面向过程的。就是顺序,条件,循环,构成一个个函数。随着代码规模的增大,人们发现有必要对代码进行模块化。一个概念对应的代码放在一个文件中,这样便于并发开发和进行代码管理。

    人们还发现了“程序=数据结构+算法”的规律。因此,一个概念对应的数据结构和函数应该放在一个文件中。这就是类的概念。

    面向对象编程范式,确实极大地提高了生产效率,因此得到了广泛的应用,因此在语言层面支持面向对象编程范式的语言是极多的。

    C语言尽管在语言层面上并不支持面向对象编程范式,但现代的C语言开发都会应用面向对象的模块化思想,把同一类的数据结构和函数放在一个文件中,采用类似的命名方式。

    毕竟C语言没有在语言层面上支持面向对象,因此就有很多程序员想给C语言添加面向对象支持。其中的代表是C++和Objective-C。

    C++是一种新的语言,但大部分语言元素是和C兼容的。

    Objective-C是完全兼容的C的。Objective-C是给C添加了薄薄的一层语法糖以支持接口(就是其他语言的类)和协议(就是其他语言的接口)。甚至,Objective-C一开始的实现,就是一个C语言的预编译器。Objective-C坦白讲,除了添加的语法不太符合C流外,实际上其面向对象系统设计是相当精妙的。乔布斯早年慧眼识珠,把Objective-C收人囊中,因为封闭于Apple/NextStep系统内,因此少有人知。随着iOs系统的普及,Objective-C近几年才名满天下。
    函数式编程范式

     函数式编程范式,是一些数学家发明的编程语言,他们认为程序就是数学函数嘛。代表语言:Lisp,Erlang,JavaScript,OCaml,Prog。
    
     有很多大牛极力鼓吹过函数式编程语言,认为其极具革命性。但我认为他们过高估计了函数式编程范式的威力,我并不认为函数式编程范式相对于面向对象编程范式有何高明之处。
    
    函数式编程语言,核心就是函数,它们没有Class类的概念。但它的函数又不是传统面向过程语言的函数,它的函数支持“闭包”的概念。
    

    在我看来,函数式编程语言的函数,也就是“闭包”,说白了,其实就是“类”。编程语言发展到今天,就是需要模块化,就是需要把“数据结构”和“算法”结合起来。不论何种语言,不把它们结合起来的编程方式,都是没有出路的。

    面向对象编程语言,用类把“数据结构”和“算法”结合起来。类的核心是“数据结构”,也就是其“属性”,而不是“算法”,其“函数”。在类中,是函数依附于属性。
    
    而函数式编程语言,用闭包把“数据结构”和“算法”结合起来。是函数能够抓取外部的字段。是“属性”依附于“函数”。
    

    “类”本质上和“闭包”是等价的。现在很多面向对象编程语言都加上了对闭包的支持。观察其代码,我们可以发现,它们实际上都是用“类”来实现“闭包”的。

    “类”和“闭包”谁更易用?明显是“类”。

    而“闭包”更简洁一些,因此“闭包”在面向对象编程语言中常用来替换匿名类。只有一个函数的类,写成一个类太麻烦,不如写成闭包,更加简洁。

     吐槽一下OCaml语言,其前身Caml语言本身是一种挺好的函数式语言,硬生生添加了一套完整的面向对象机制,同时支持面向对象和函数式编程范式,很容易像C++一样脑裂的。
    

    也有很多面向对象语言控看着JavaScript嫌烦,总是想把面向对象支持添加到JavaScript上。ActionScript就是其中一种尝试。我用过,真的是和Java没多少区别了。

    再吐槽一下ExtJS。当初选型Web前端开发框架时比较了ExtJS和JQuery。

    ExtJS明显是Java高手开发的,硬生生用JavaScript模拟Swing的设计思想,搞了一套UI库。

    JQuery开发者明显是领悟了JavaScript的函数式编程范式,依据JavaScript的动态函数式编程语言的特点打造了一套UI库,立刻秒杀ExtJS。

    由ExtJS和JQuery的故事,我们可以看到多语言编程能力是多么的重要。ExtJS的作者精通并喜爱Java,因此他把手术刀JavaScript当做锤子Java使,一通乱敲,费力不讨好。

    函数式编程语言,还有尾递归等一些小技巧。尾递归可以不用栈,防止递归调用时栈溢出。
    模板编程范式

    模板编程,就是把类型作为参数,一套函数可以支持任意多种类型。代表语言:C++。
    

    模板编程的需求,是在C++开发容器库的时候发明的。因为容器需要保存任意类型的对象,因此就有了泛型的需求。

     C++的模板编程,是在编译时,根据源码中的使用情况,创建对应类型的代码。除了C++这种方式,Java,C#也有类似的机制,叫做“泛型”,但它们的实现方式和C++的模板很不同。它们的编译器不会生成新的代码,而是使用强制类型转换的方式实现。
    

    在没有模板/泛型的编程语言中,怎样在容器中存放对象呢?存取公共基类类型(Java,C#)的对象,或者void*指针(C)即可,取出时自己强制类型转换为实际类型。动态类型语言,不关心类型,更是无所谓了,随便什么对象直接往容器里扔进去,取出来直接用即可。

    一些C++高手又在模板的基础上搞出了“模板元编程”。因为模板编程,就是C++的编译器搞定的嘛,模板元编程就是让编译器运算,编译完结果也就算出来了。我不知道除了研究和炫技,这玩意有啥用?
    小结

     一门语言是否值得学习,我认为有几个标准:
    

    1,是否要用,要用就得学,这么没有疑问的。毕竟我们都要吃饭的嘛。

    2,其语言特性是否给你耳目一新的感觉。如果是,那就值回票价了。如Go语言废掉了异常,改用返回多值。我深以为然。我其实已经主动不用异常好多年了。因为,我觉得既然C不支持异常也活得很好,为什么需要异常呢?出错了,返回错误码。无法挽回的错误,直接Abort程序就可以嘛!而且,异常实际上是违反面向过程编程原则的。一个函数应该只有一个入口一个出口。抛出异常就多了出口了。

    3,是否擅长某一个领域。如果你手里只有一把锤子,那么你就只能把所有任务都当做钉子猛锤一通。但如果工具箱里有多种工具,那面对不同的任务就得心应手多了。

    7段—架构设计

    还需要掌握架构设计的能力,才能设计出优秀的软件。架构设计有一些技巧:
    

    1,分层

    一个软件通常分为:
    

    表现层–UI部分

    接口层–后台服务的通讯接口部分

    服务层–实际服务部分

    存储层—持久化存储部分,存储到文件或者数据库。

    分层的软件,可以解耦各个模块,支持并行开发,易于修改,易于提升性能。
    

    2,SOA

     模块之间通过网络通讯互相连接,松耦合。每一个模块可以独立部署,可以增加部署实例从而提高性能。每一个模块可以使用不同的语言和平台开发,可以重用之前开发的服务。SOA,常用协议有WebService,REST,JSON-RPC等。
    

    3,性能瓶颈

    1)化同步为异步。

    用内存队列(Redis),工作流引擎(JBpm)等实现。内存队列容易丢失数据,但是速度快。工作流引擎会把请求保存到数据库中。

    通过化同步请求为异步请求,基本上99.99%的性能问题都可以解决。
    2)用单机并行硬件处理。

    如,使用GPU,FPGA等硬件来处理,提高性能。
    3)用集群计算机来处理。

    如,Hadoop集群,用多台计算机来并行处理数据。

    自己的软件栈中,也可以把一个模块部署多份,并行处理。
    4)用cache来满足请求。常用的内容加热cache后,大量的用户请求都只是内存读取数据而已,性能会得到很大的提升。

    cache是上帝算法,记得好像它的性能只比最佳性能低一些,就好像你是上帝,能够预见未来一样。现在X86CPU遇到了主频限制,CPU提升性能的主要途径就是增加高速Cache了。
    4,大系统小做

    遇到大型系统不要慌,把它切分成多个模块,用多个小程序,通过SOA协作来解决。这秉承了Unix的设计思想。Unix上开发了大量单一目的的小程序,它主张用户通过管道来让多个小程序协作,解决用户的需求。当然,管道方式通讯限制太多,不够灵活。因此,现在我们可以通过URI,通过SOA的方式来让多个程序协作。Andorid和iOS上的应用程序,现在都是通过URI实现协作的。这也算是Unix设计思想的现代发展吧?!
    5,Sharding切片

    现在有一个潮流,就是去IOE。I-IBM大型机,O-Oracle数据库,E-EMC存储。之前,大型系统常用IOE去架构,在大型机上部署一个Oracle数据库,Oracle数据库用EMC存储保存数据。IOE是当今最强的计算机,数据库和存储。但他们面对海量系统也有抗不住的一天。
    
    Oracle数据库是Shareeverything的,它可以在一个计算机集群(服务器节点不能超过16个)上运行。计算机集群都共用一个存储。
    
    去IOE运动,标志着ShareEverything模式的破产。必须使用ShareNothing,系统才能无限扩展。
    
     用MySQL数据库就可以应付任意规模的数据了。前提是,你会Sharding分片。把大系统切分成若干个小系统,切分到若干台廉价服务器和存储上。更Modern一些,就是切分到大量虚拟机上。
    
    
    
      如,铁道部的12306网站。我们知道火车票都是从属于某一列列车的。那么我们把每一个列车作为一个单元来切分,就可以把12306网站切分成几千个模块。一台虚拟机可以承载若干个模块。当某些列车成为性能瓶颈之后,就可以把它们迁移到独立的虚拟机上。即使最终有部分列出服务不可用,系统也不会完全不可用。
    
    
    
     12306网站,只有一个全局的部分,就是用户登录。这个可以交给第三方负责。如可以让用户用微信,微博,qq等账户登录。
    
     也可以自己实现用户登录服务。还是用切片的方式用多台Redis服务器提供服务。Redis服务器存储每一个登录用户的sessionId和userId,角色,权限等信息。sessionId是随机生成的,可选择其部分bit用于标识它在哪一个Redis服务器上。用户登录后,把sessionId发给客户。用户每次请求时把sessionId发回给服务器。服务器把sessionId发给Redis服务器查询得到其用户信息,对用户请求进行处理。如果在redis服务器上找不到sessionId,则让用户去登录。即使所有注册用户同时登陆,也不需要太多的内存。而且,可以在session内存过多时,删除最早登陆的用户的session,强制他再次登陆。同时活跃的用户数不会太多。
    
    展开全文
  • DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序编程接口)。...节点分为几种不同的类型,每种类型分别表示文档中不同的信息及(或)标记。每个节点都拥有各自的特定、数据和方法,另外也与其它节点存在某种...

    DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序编程接口)。DOM描绘了一个层次化的节点树,允许添加、移除和修改页面的一部分。DOM1级为基本的文档结构即查询提供了接口。

    节点层次

    DOM可以将任何HTML或XML文档描绘成一个由多层节点构成的结构。节点分为几种不同的类型,每种类型分别表示文档中不同的信息及(或)标记。每个节点都拥有各自的特定、数据和方法,另外也与其它节点存在某种关系。节点之间的关系构成了层次,而所有页面标记则表现为一个以特定节点为根节点的树形结构。HTML为例:

    Sample Page

    Hello World!

    >

    d5db00da1c6a

    简单的HTML文档层次结构

    文档节点是每个文档的根节点。在这个例子中,文档节点只有一个子节点,即元素,我们称之为文档元素。文档元素是文档的最外层元素,文档中的其他所有元素都包含在文档元素中。每个文档只能有一个文档元素。在HTML页面中,文档元素始终都是。在XML中,没有预定义的元素,因此任何元素都可能成为文档元素。

    每一段标记都可以通过树中的一个节点来表示:HTML元素通过元素节点表示,特性通过特性节点表示,文档类型通过文档类型节点表示,而注释通过注释节点表示。总共有12种节点类型,这些类型都继承自一个基类型。

    1.Node类型

    DOM1级定义了一个Node接口,该接口将由DOM中的所有节点类型实现。这个Node接口在JavaScript中是作为Node类型实现的。除了IE之外,其他所有浏览器都可以访问这个类型。JavaScript中的所有节点都继承自Node类型,因此所有节点类型都共享者相同的基本属性和方法。

    每个节点都有一个nodeType属性,用于表明节点的类型。节点类型由在Node类型中定义的下列12个数值来表示:

    Node.ELEMENT_NODE(1)

    Node.ATTRIBUTE_NODE(2)

    Node.TEXT_NODE(3)

    Node.CDATA_SECTION_NODE(4)

    Node.ENTITY_REFERENCE_NODE(5)

    Node.ENTITY_NODE(6)

    Node.PROCESSING_INSTRUCTION_NODE(7)

    Node.COMMENT_NODE(8)

    Node.DOCUMENT_NODE(9)

    Node.DOCUMENT_TYPE_NODE(10)

    Node.DOCUMENT_FRAGMENT_NODE(11)

    Node.NOTATION_NODE(12)

    通过比较上面这些常量,可以很容易地确定节点的类型。

    if (someNode.nodeType == Node.ELEMENT_NODE) {//在IE中无效

    alert("Node is an element.");

    }

    为了确保浏览器兼容,最后还是将nodeType属性与数字值进行比较。

    if (someNode.nodeType == 1) {//适用于所有浏览器

    alert("Node is an element.");

    }

    并不是所有节点都受到Web浏览器的支持,最常用的是元素和文本节点。

    1.nodeName和nodeValue属性

    要了解节点的具体信息,可以使用nodeName和nodeValue这两个属性。这两个属性的值完全取决于节点的类型,在使用这两个值以前,最好先检测以下节点的类型。

    if (someNode.nodeType == 1) {//适用于所有浏览器

    value = someNode.nodeName; //nodeName的值是元素的标签名

    }

    对于元素节点,nodeName中保存的始终都是元素的标签名,而nodeValue的值则始终为null。

    2.节点关系

    每一个节点都有一个childNodes属性,其中保存着一个NodeList对象。NodeList是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点。虽然可以通过方括号语法来访问NodeList的值,而且这个对象也有length属性,但它不是Array的实例。NodeList对象的独特之处在于,它实际上是基于DOM结构动态执行查询的结构,因此DOM结构的变化能够自动反映在NodeList对象中。

    访问存在NodeList中的节点——可以通过方括号,也可以使用item()方法。

    var firstChild = someNode.childNodes[0];

    var secondChild = someNode.childNodes.item(1);

    var count = someNode.childNodes.length;

    length属性表示的是访问NodeList那一刻,其中包含的节点数量。

    对arguments对象使用Array.prototype.slice()方法可以将其转换为数组,同样的方法,也可以将NodeList对象转换为数组。

    //在IE8及之前的版本无效

    var arrayOfNodes = Array.prototype.slice.call(someNode.childNodes,0);

    function convertToArray(nodes) {

    var array = null;

    try{

    array = Array.prototype.slice.call(nodes,0); //针对非IE浏览器

    }catch(ex){

    array = new Array();

    for(var i=0, len = nodes.length; i

    array.push(nodes[i]);

    }

    }

    return array;

    }

    每一个节点都有一个parentNode属性,该属性指向文档树中的父节点。包含在childNodes列表中的每个节点相互之间都是同胞节点。通过使用列表中每个节点的previousSibling和nextSibling属性,可以访问同一列表汇总的其他节点。

    d5db00da1c6a

    节点关系

    hasChildNodes()在节点包含一或多个子节点时返回true。

    所有节点都有的最后一个属性是ownerDocument,该属性指向表示整个文档的文档节点。

    3.操作节点

    因为关系指针都是只读的,所有DOM提供了一些操作节点的方法。最常用的方法是appendChild(),用于向childNodes列表的末尾添加一个节点。添加节点后,childNodes的新增节点、父节点及以前的最后一个子节点的关系指针都会相应的得到更新。更新完成后,appendChild()返回新增的节点。

    var returnedNode = someNode.appendChild(newNode);

    alert(returnedNode == newNode); //true

    alert(someNode.lastChild == newNode); //true

    如果传入到appendChild()中的节点已经是文档的一部分,那结果就是将该节点从原来的位置转移到新位置上。

    var returnedNode = someNode.appendChild(someNode.firstChild);

    alert(returnedNode == someNode.firstChild); //false

    alert(someNode.lastChild ==someNode.lastChild); //true

    如果需要把节点放在childNodes列表中某个特定的位置上,而不是放在末尾,那么可以使用insertBefore()方法。这个方法接受两个参数:要插入的节点和作为参照的节点。插入节点后,被插入的节点会变成参照节点的前一个同胞节点(previousSibling),同时被方法返回。如果参照节点是null,则insertBefore()和appendChild()执行相同的操作。

    returnedNode = someNode.insertBefore(newNode,null);

    alert(newNode == someNode.lastChild); //true

    returnedNode = someNode.insertBefore(newNode,someNode.firstChild);

    alert(returnedNode == newNode); //true

    alert(newNode == someNode.firstChild); //true

    returnedNode = someNode.insertBefore(newNode,someNode.lastChild);

    alert(newNode == someNode.childNodes[someNode.childNodes.length-2]); //true

    replaceChild()方法接收两个参数:要插入的节点和要替换的节点。要替换的节点将有这个方法返回并从文档树中被移除,同时由要插入的节点占据其位置。

    var returnedNode = someNode.replaceChild(newNode,someNode.firstChild);

    returnedNode = someNode.replaceChild(newNode,someNode.lastChild);

    如果只想移除而非替换节点,可以使用removeChild()方法。这个方法接受一个参数,即要移除的节点,被移除的节点将成为方法的返回值,

    var formerFirstChild = someNode.removeChild(someNode.firstChild);

    var formerFirstChild = someNode.replaceChild(someNode.lastChild);

    4.其他方法

    有两个方法是所有类型的节点都有的。cloneNode()和normalize()。

    cloneNode(),用于创建调用这个方法的节点的一个完全相同的副本。cloneNode()方法接受一个布尔值参数,表示是否执行深复制。在参数为true的情况下,执行深复制,也就是复制节点及其整个子节点树;在参数为false的情况下,执行浅复制,只复制 节点本身。

    cloneNode()方法不会复制添加到DOM节点中的JavaScript属性,如事件处理程序等。只复制特性、子节点。

    normalize(),这个方法唯一的作用就是处理文档树中的文本节点。由于解析器的实现或DOM操作等原因,可能会出现文本节点不包含文本,或接连储量俩个文本节点的情况。当在某个节点上调用这个方法时,就会在该节点的后代节点中中查找上述两种情况。如果找到了空文本节点,删除它;如果找到相邻的文本节点,合并它们。

    展开全文
  • 胡扯OSI模型的七个层次的关系。

    千次阅读 2016-07-28 13:37:33
    物理层->数据链路层->网络层->传输层->会话层->表示层->应用层。 从左到右是第一层到第七层,怎么记? 我觉得应该这样理解OSI的含义是说:开放式系统互联,指说明任意两个不同系统之间如何通信的一个理论模型,...
    OSI模型一共是有七层框架
    
    物理层->数据链路层->网络层->传输层->会话层->表示层->应用层。
    从左到右是第一层到第七层,怎么记?
    我觉得应该这样理解OSI的含义是说:开放式系统互联,指说明任意两个不同系统之间如何通信的一个理论模型,说明OSI重点是要通信,通信的目的是在不同计算机系统的数据进行共享应用(互联网说白了也就是对数据进行操作,个人理解,轻拍),所以可以知道在这OSI的七层中肯定会与数据,网络,通信,应用等相关的层次。所以第一层是最底层也就是物理层面的东西,也就是第一层->物理层,对应最高层也就是第七层->应用层。而回到两个不同系统之间如何去把彼此的数据交互?应该是是要在不同的系统之间构造出网络层来通信,但由物理层的数据到网络层之间应该要有过渡,网的构成该是由许多链路组成的,这些链路的组成是数据,所以在物理层和网络层之间该是数据链路层,把第二层->数据链路层,也就推出第三层->网络层,数据经由数据链路通过网络,那么应该是要实现在任意两个系统之间去进行传输(想想OSI的目的不就是要让数据从一个系统到另一个系统吗),所以很明显第四层->传输层。现在有了网络,也有了传输层,那么不同的两个系统之间的数据应该是可以交互了,但注意,OSI的核心点之一是不同系统之间的相互通信而不去考虑底层的架构,那么想想一个只懂英语的一猿喜欢一个只懂爪哇语的媛,他想向媛表达爱意啊,但没有什么联系方式,只能用最土的方式写小字条。他找来一张纸,写上:I LOVE YOU ,此时物理层搞定,然后猿很害羞,所以,他托二猿去给他送信(数据链路层),二猿本不想干这事,但看着一猿都快五十了,居然还没女票,所以。。。。。但走着走着想起家里在烧开水,然后托三猿去送(网络层),三猿是个好猿,二话不说就走去送了(传输层),信是送到了媛手里啊,但媛是说爪哇语的,看不到啥子叫I LOVE YOU ,所以媛拿着这封不知道是什么东西的东西去找她的邻居猫博士,猫博士一看知道了是有猿喜欢上了他邻居,好心的猫博士把信的内容翻译给媛说有只多毛的东西说要跟你生猴子(会话层),媛你怎么想,看这只猿还蛮急的,你赶紧回复下,表个态(表示层),媛说,好吧,我答应了(女程序员真的是这么好泡吗,我要学面向对象编程。。。。),时候猿和媛愉快地走在了乡间的小路上(应用层)。
    这样子,是不是把七层都记住了。当然这些都是乱扯,目的是要更好的记忆七层到底是啥跟啥。。。
    事实上,这七层的作用,更像是在一方面从7层到1层,对数据层次包装对数据添加不同的报文,在另一个系统则是从1层到7层层层分解,最终得到数据。
    展开全文
  • 一个神经网络自然语言模型当然需要神经网络的结构层次,但是在进入神经网络之前,怎么把单词表示成要输入的词向量,这也是一个非常重要的问题。其实,神经网络语言模型主要分两大部分,第一,输入词向量的表示问题,...

    一个神经网络自然语言模型当然需要神经网络的结构层次,但是在进入神经网络之前,怎么把单词表示成要输入的词向量,这也是一个非常重要的问题。其实,神经网络语言模型主要分两大部分,第一,输入词向量的表示问题,第二,神经网络结构的选择问题。只要处理好这两方面的问题,剩下的就交给训练了,当然其中还有一些细节。本文所描述的是一个一般化的多层神经网络结构,首先要说明一些标记记号:
    假设一个神经网络函数为fθ()f_\theta(\cdot),其参数为θ\theta。如果有LL层的前馈网络,则认为由fθl()f_\theta^l(\cdot)组成,
    fθ()=fθL(fθL1(fθ1()))f_\theta(\cdot)=f_\theta^L(f_\theta^{L-1}(\cdot\cdot\cdot f_\theta^1(\cdot)\cdot\cdot\cdot))
    再假设,给定一个矩阵AA,则[A]i,j[A]_{i,j}表示AA中第ii行第jj列的元素。<A>idwin<A>_i^{d_{win}}表示是由在矩阵AAii列向量周围的dwind_{win}个列向量拼接而成的向量。也即AA中第ii列左右各dwin/2d_{win}/2个列向量拼接而成。特别的,<A>i1<A>^1_i表示矩阵AAii列向量。对于一个向量vv[v]i[v]_i表示其第ii个标量元素。最后,序列{x1,x2,...,xT}\{x_1,x_2,...,x_T\}可写为[x]1T[x]^T_1,序列的第ii个元素为[x]i[x]_i
    ##转化单词为特征向量
    首先,每一个单词都有一个索引,网络的第一层就是通过一个查询表(lookup table)把单词索引映射为一个特征向量。
    对每一个单词wD,Dw\in D, D为一个有限的字典,一个dwrdd_{wrd}维的特征向量由查询表层LTW()LT_W(\cdot)给出:
    LTW(w)=<W>w1LT_W(w)=<W>^1_w
    其中,WRdwrd×DW\in R^{d_{wrd}\times |D|}是一个要学习的矩阵参数<W>w1Rdwrd<W>^1_w\in R^{d_{wrd}}WW的第ww列,dwrdd_{wrd}为单词向量维度(由用户选择的超参)。给定一个句子或任何具有TT个字典DD中的单词[w]1T[w]^T_1序列,则查询表会产生一个输出矩阵:
    LTW([w]1T)=(<W>[w]11<W>[w]21...<W>[w]T1)(1)LT_W([w]^T_1)=(<W>_{[w]_1}^1\quad <W>_{[w]_2}^1... <W>_{[w]_T}^1)\tag{1}
    通过对这些特征向量的连接可以输入到后续的神经网络层中。
    ###扩展到单词的离散特征
    更详细地,可以把每个单词向量更细分一下,即每个单词可以由多个离散的特征组成(这个对于英语语言来说,汉语好像没有这个问题)。比如一个单词,它有词根,它的小写的结尾和它大写的开头等特征,由这些特征组成这个单词的特征。
    一般来说,假设一个单词由KK个离散特征表示,wD1××DKw\in D^1\times \cdots\times D^K,其中,DkD^k为第kk个特征的字典。我们把每个特征关联一个查询表LTWk()LT_{W^k}(\cdot),其参数WkRdwrdk×DkW^k\in R^{d^k_{wrd}\times|D^k|},其中,dwrdkNd^k_{wrd}\in N是一个用户设定的维度大小。给定一个单词ww,它的特征向量维度为dwrd=Σkdwrdkd_{wrd}=\Sigma_kd^k_{wrd},也就是把组成它的离散特征拼接在一起:
    LTW1,...,WK(w)=[LTW1(w1)LTWK(wK)]=[<W1>w11<WK>wK1]LT_{W^1,...,W^K}(w)=\begin{bmatrix} LT_{W^1}(w_1)\\ \vdots\\ LT_{W^K}(w_K) \end{bmatrix} =\begin{bmatrix} <W^1>^1_{w_1}\\ \vdots\\ <W^K>^1_{w_K} \end{bmatrix}
    上面那是一个单词的由多个离散特征向量拼接表示的特征向量。
    那么,单词序列[w]1T[w]^T_1的查询表层的输出为一个矩阵:
    LTW1,...,WK([w]1T)=[<W1>[w1]11<W1>[w1]T1<WK>[wK]11<W1>[wK]T1](2)LT_{W^1,...,W^K}([w]^T_1)=\begin{bmatrix} <W^1>^1_{[w_1]_1} &\cdots &<W^1>^1_{[w_1]_T}\\ \vdots&\quad &\vdots\\ <W^K>^1_{[w_K]_1}&\cdots &<W^1>^1_{[w_K]_T} \end{bmatrix}\tag{2}
    其中,矩阵中的每一列为一个单词的由多个离散特征向量拼接表示的特征向量。
    其实,我认为这种离散特征可以不被考虑,因为这些参数都是随机初始化的,并且在传入网络中训练,最后得到的词向量应该都会一样的,可能比较好的是,这种离散化可能提取每个词的词根向量和大小写向量。
    ##神经网络的输入方法
    有两种方法把单词向量输入到神经网络中去,一种是基于窗口的方法;另一种是基于句子的方法,也称为卷积方法。
    ###基于窗口的方法
    基于窗口方法认为一个单词的标注主要依赖于它近邻的单词,因此,要标注一个单词,我们使用一个固定大小为kszk_{sz}(超参数)的窗口,窗口中的每一个单词都通过查询表(1)或(2)找到对应的词向量,这就产生一个dwrd×kszd_{wrd}\times k_{sz}大小的词向量矩阵,然后把各个单词的词向量拼接成一个dwrdkszd_{wrd}k_{sz}维的列向量作为后续标准的神经网络的输入,因此可以写为:
    fθ1=<LTW([w]1T)>tdwin=[<W>[w]tdwin/21<W>[w]t1<W>[w]t+dwin/21]f_\theta^1=<LT_{W}([w]^T_1)>_t^{d_{win}}=\begin{bmatrix} <W>^1_{[w]_{t-d_{win}/2}}\\ \vdots\\ <W>^1_{[w]_t}\\ \vdots\\ <W>^1_{[w]_{t+d_{win}/2}} \end{bmatrix}

    从下面一张图中可以清楚看出模型的结构:
    这里写图片描述

    每一个词由多个离散特征组成,通过设定窗口,再把对应各个单词的离散特征向量从查询表(记住,此查询表是需要训练的,得到的每一列是各个单词的词向量,即word embedding 或 word representation,但是具体地技术细节怎么实现训练呢?)中抽出,拼接成一个列向量,然后再经过标准的神经网络训练,此监督学习方法可以得到词性标注(POS),命名实体识别(NER)等,得到的副产品就是词向量。

    基于卷积的方法

    使用基于窗口的方法能解决大多数自然语言处理工作,但是对语义角色标注(SRL)力有所逮,因为假设一个单词标注依赖于一个前面的动词,但这个动词在窗口之外,那么它就不太可能标注正确,这种情况下,标注一个单词需要整个句子。这时候,基于卷积的方法就派上用场了。该卷积方法又称为时间延迟神经网络(TDNNs)。
    卷基层:卷基层可以看做窗口方法的一般化,给定一个序列,其可以表示成为一个矩阵fθl1f_\theta^{l-1},矩阵中的每一列都是序列中一个单词的词向量,然后对这个单词序列做卷积操作:
    <fθl>t1=Wl<fθl1>tdwin+blt<f_\theta^l>_t^1=W^l<f_\theta^{l-1}>_t^{d_{win}}+b^l\quad \forall t
    其中,权重矩阵WlW^l是共享的,相当于卷积核,窗口的大小为tt,一般通过多个卷积层来提取更高级的特征。
    最大池化层:卷积层的输出的大小依赖于句子长度的大小,由于神经网络的全连接层需要输入固定长度大小的特征,因此局部特征向量需要整合为一个全局特征向量,一般的最大池化层是取平均或取最大值,由于句子中大多数单词对于一个要标注单词的语义角色没多大影响,所以取平均操作没多大意义,所以可以用最大化方法。给定一个由卷积层l1l-1输出的矩阵fθl1f_\theta^{l-1},则最大池化层输出的向量为fθlf_\theta^l
    [fθl]i=maxt[fθl1]i,t1inhul1[f_\theta^l]_i=max_t[f_\theta^{l-1}]_{i,t}\quad 1\le i\le n_{hu}^{l-1}
    给出它的结构图形:
    这里写图片描述
    这里写图片描述
    从上图可以清楚看出卷积层和最大池化层的操作,然后就是进入标准的神经网络结构了。
    对于标准的神经网络,训练量十分庞大,如果是单纯的要训练词向量的话,可以使用Word2vec模型,它更改了神经网络中的一些结构,使得训练更具有效率,详情可看word2vec以及GloVe总结

    参考文献
    【Ronan Collobert, Jason Weston, Leon Bottou, Michael Karlen, Koray Kavukcuogluy, Pavel Kuksaz】Natural Language Processing (almost) from Scratch
    【Yoav Goldberg】A Primer on Neural Network Models for Natural Language Processing

    展开全文
  • OSI模型将系统间通信划分成了七个层次,其中最上面的三层,可以归属到应用层之中,因为这三层不关心如何将数据传送到对方,只关心如何组织和表达要传送的数据。 第七层--应用层  应用层是OSI模型的最上层,它...
  • 以上完整表示了HTTP请求和响应的7个步骤,下面从TCP/IP协议模型的角度来理解HTTP请求和响应如何传递的。 二、TCP/IP协议 TCP/IP协议模型(Transmission Control Protocol/Internet Protocol),包含了一系列构成...
  • 然而我们可以将许多的类似感知器的模型按照层次结构连接起来,这样就能表现出非线性决策的边界了,这也叫做多层感知器,重要的是怎么样学习多层感知器,这个问题有两个方面: 1、  要学习网络结构; 2、  要...
  • 数据库复习

    2021-06-13 15:25:35
    1 数据库绪论 数据独立性 模式(schema) 是数据库逻辑结构和特征的描述,是型的描述,相对稳定。 模式的一个实例(instance) 是模式的一个具体值,...物理模型 怎么存的 概念模型、逻辑模型、物理模型 概念模型
  • 2.接口调试运行,一个都不能少,可以对参数进行加密,从md5到aes一应俱全,返回参数与模型实时分析对比,给出不一致的地方,找出接口可能出现的问题。如果你不想手写文档,那么试试接口的数据生成功能,可以对接口...
  • 计算机网路编程

    2020-10-06 23:00:35
    为了简化网络复杂度,网络通信的不同方面被分解为多层次结构,每个层次只和自己挨着的层次进行交互,只要层与层之间的接口保持不变,里面怎么修改都不会影响到其他层次; OSI7层模型: 应用,表示,会话,传输,网络...
  • 为了准确的表示如何编号,怎么生产八位字节流,Unicode Technical Report (UTR) #17提出现代编码模型的5个层次: 1. 抽象字符表:系统所支持的所有抽象字符的集合 2. 编码字符集:就是通过某种规则把抽象字符...
  • 网络编程基础知识

    2018-08-01 16:34:40
    网络协议层次结构 分层: layer “层”: 功能模块。软件设计方法学,主张把一个大的复杂的工程分成不同的代码码,实现不同的功能。功能模块(function) OSI七层模型: 应用层 表示层 会话层 传输层 网络层 数据链路...
  • 论文笔记(二)

    2021-05-17 21:57:34
    所以接下来我们将在模型里引入权重来反映子树的结构,引入层次嵌入的方法生成向量S。层次嵌入的效率将在后面的文章被实验证明。 层次嵌入的图示如下: 让我们先来翻译一下图示下的文字,每一个模块中是一个嵌入...
  • 系统的结构设计,进入设计阶段,要把软件“做什么”的逻辑模型变换为怎么做的物理模型,即着手实现软件的需求,并将设计的结果反映在“设计规划说明书”文档中,所以软件设计时一个软件需求转换为软件表示的过程。...
  • 数据挖据基础

    2019-05-01 21:33:53
    然而我们可以将许多的类似感知器的模型按照层次结构连接起来,这样就能表现出非线性决策的边界了,这也叫做多层感知器,重要的是怎么样学习多层感知器,这个问题有两个方面: 1、 要学习网络结构; 2、 要学习连接...
  • 需求模型的表现形式有自然语言、半形式化(如图、表、结构化英语等)和形式化表示等三种。需求概念模型的要求包括实现的独立性:不模拟数据的表示和内部组织等;需求模拟技术又分为企业模拟、功能需求模拟和非功能需求...
  • J2EEvs.NET

    2021-02-04 15:00:31
    看到这个标题,也许会有人表示疑惑,J2EE和.NET并不在一个层次上,怎么能将它们放在一起呢?需要指出的是,通常所说的.NET包含了一个相当广泛的产品家族,包括开发平台、操作系统、服务器、终端设备等,此外还包括...
  • 三个层次来解释词汇,并尽量实现通信的哲学“你传达的复杂信息,到底有没有人愿意听、能够懂、记得住、还给点赞。”由于本人也是初学者,解释的难免会有片面,错误的情况,希望如果有大佬发现可以帮忙指正,提前表示...
  • 520初识MongoDB

    2020-05-21 02:12:51
    背景 由于我们在开发的过程中难免会遇到数据库选型的问题,那么数据库...mongo是面向文档的数据库,为了获得更好的扩展性采用的不是关系型数据库,使用一条记录就可以表示非常复杂的层次关系 没有固定的模式,文档的键
  • J2EE VS .NET

    2008-02-20 11:37:00
    看到这个标题,也许会有人表示疑惑,J2EE和.NET并不在一个层次上,怎么能将它们放在一起呢?需要指出的是,通常所说的.NET包含了一个相当广泛的产品家族,包括开发平台、操作系统、服务器、终端设备等,此外还包括...
  • 看到这个标题,也许会有人表示疑惑,J2EE和.NET并不在一个层次上,怎么能将它们放在一起呢?需要指出的是,通常所说的.NET包含了一个相当广泛的产品家族,包括开发平台、操作系统、服务器、终端设备等,此外还包括...

空空如也

空空如也

1 2 3 4
收藏数 68
精华内容 27
关键字:

层次模型怎么表示