首页> 搜索结果页
"radius证书作用" 检索
共 17 条结果
strongswan之ipsec.conf配置手册(上)
ipsec.conf是strongSwan的关键配置,文件指定了strongSwan IPsec子系统的大部分配置和控制信息。主要的例外是身份验证的密钥,配置保存在ipsec.secrets文件中。该文件是一个文本文件,由一个或多个部分组成。#后面跟空格,再后面任何到行尾的任何内容都是注释并被忽略,不在一个部分内的空行也是如此。包含include和文件名的行,以空格分隔,将替换为该文件的内容。如果文件名不是完整路径名,则认为它是相对于包含文件的目录,这样的包含可以嵌套。只能提供一个文件名,它可能不包含空格,但它可能包含shell通配符,例如:include ipsec.*.conf包含工具的目的主要是允许将连接或连接集的信息与主配置文件分开。这允许更改此类连接描述,将其复制到所涉及的其他安全网关等,而不必不断地从配置文件中提取它们,然后将它们重新插入其中。还要注意允许将单个逻辑部分(例如连接描述)分成几个实际部分的参数(如下所述)。一个部分以如下形式的一行开始:type name其中type表示后面是什么类型的节,name是一个任意名称,用于将该节与其他相同类型的节区分开来。所有后续以空格开头的非空行都是该部分的一部分。 共享相同名称的相同类型的部分将被合并。通常具有以下形式parameter=value(注意前面的强制性空格)。 = 两边可以有空格。参数名称特定于节类型。空值代表参数的系统默认值(如果有),即大致相当于完全省略参数行。这对于清除从 %default 部分或通过参数(见下文)继承的设置可能很有用。一个值可能包含单个空格(额外的空格减少为一个空格)。为了保留写入的空白,请将整个值括在双引号 (") 中;在此类值中,双引号本身可以通过在它们前面加上 \ 字符来进行转义。双引号字符串可以通过以 \ 字符结尾来跨越多行(以下行不必以空格开头,因为它将被保留)。此外,以下控制字符可以编码在双引号字符串中:\n、\r、\t、\b、\f。数值被指定为“整数”(数字序列)或“十进制数”(数字序列可选地后跟“.”和另一个数字序列)。当前有一个参数可用于任何类型的部分:该值也是一个部分名称;该节的参数由当前节继承。当前节中的参数总是覆盖继承的参数,即使它们后面也跟着一个。指定的节必须存在并且必须具有相同的节类型;如果它是在当前部分之前或之后定义的,则不会。允许嵌套,并且单个部分中也可能有多个(引用部分的参数按照这些参数的顺序被继承和覆盖)。名称为 %default 的部分指定相同类型的部分的默认值。其中的所有参数都由该类型的所有其他部分继承。目前有三种类型的部分:CONFIG部分指定IPsec的一般配置信息,CONN部分指定IPsec连接,而CA部分指定证书颁发机构的特殊属性。CONN部分conn 部分包含连接规范,定义要使用 IPsec 建立的网络连接。 给定的名称是任意的,用于标识连接。 这是一个简单的例子:conn snt left=192.168.0.1 leftsubnet=10.1.0.0/16 right=192.168.0.2 rightsubnet=10.1.0.0/16 keyingtries=%forever auto=add关于术语的注释:有两种通信正在进行:用户 IP 报文的传输,以及用于密钥、重新密钥和一般控制的网关到网关协商。控制连接的路径在 IKEv1 中称为“ISAKMP SA”,在 IKEv2 协议中称为“IKE SA”。正在协商的内核级数据路径称为“IPsec SA”或“子 SA”。 strongSwan 以前使用过两个单独的键控守护进程 pluto 和 charon。本手册不再讨论 pluto 选项,而只讨论自 strongSwan 5.0 支持 IKEv1 和 IKEv2 以来的 charon。 为了避免简单地编辑配置文件以使其适合连接中涉及的每个系统,连接规范是根据左右参与者而不是本地和远程来编写的。哪个参与者被认为是左或右是任意的;对于每个连接描述,都会尝试确定本地端点应该充当左端点还是右端点。这是通过将两个端点定义的 IP 地址与分配给本地网络接口的 IP 地址相匹配来完成的。如果找到匹配项,则匹配的角色(左或右)将被视为本地角色。如果在启动过程中没有找到匹配项,left 被认为是本地的。这允许在两端使用相同的连接规范。有没有对称性的情况;一个好的约定是使用 left 表示本地端和 right 表示远程端(第一个字母是一个很好的助记符)。 许多参数与一个参与者或另一个参与者有关;这里只列出了 left 的参数,但每个以 left 开头的参数都有一个右对应物,其描述相同,但左右颠倒。 除非标记为“(必需)”,否则参数是可选的。CONN参数除非另有说明,否则要使连接正常工作,通常两端必须在这些参数的值上完全一致。aaa_identity = <id>定义在 IKEv2 EAP 身份验证期间使用的 AAA 后端的身份。 如果 EAP 客户端使用验证服务器身份的方法(例如 EAP-TLS),但它与 IKEv2 网关身份不匹配,则需要这样做。aggressive = yes | no是使用 IKEv1 野蛮模式还是主模式(默认)。ah = <cipher suites>用于连接的AH算法的逗号分隔列表,例如sha1-sha256-modp1024。符号是完整性[-dhgroup]。对于IKEv2,同一类型的多个算法(用 - 分隔)可以包含在单个提案中。IKEv1仅包含提案中的第一个算法。只能使用关键字ah或esp,不支持 AH+ESP同时使用。没有默认的AH密码套件,因为默认使用ESP。 守护程序将其广泛的默认提议添加到配置的值。要将其限制为已配置的提案,可以在末尾添加感叹号 (!)。如果指定了dh-group,则CHILD_SA/Quick Mode设置和密钥更新包含单独的 Diffie-Hellman 交换。also = <name>包含 conn 部分 <名称>。auth = <value>pluto IKEv1 守护进程使用 AH 对 ESP 加密报文进行完整性保护,但在 charon 中不支持。ah关键字指定用于AH完整性保护的算法,但不加密。 不支持 AH+ESP 同时使用。authby = pubkey | rsasig | ecdsasig | psk | secret | never | xauthpsk | xauthrsasig两个安全网关应如何相互验证; 可接受的值为预共享密钥的 psk 或 secret、公钥签名的 pubkey(默认值)以及 RSA 数字签名的同义词 rsasig 和椭圆曲线 DSA 签名的 ecdsasig。 如果永远不会尝试或接受协商,则可以使用 never(对于 shuntonly conns 很有用)。 数字签名在各方面都优于共享密钥。 除了分别基于共享密钥或数字 RSA 签名的 IKEv1 主模式之外,IKEv1 还支持 xauthpsk 和 xauthrsasig 值,它们将启用扩展身份验证 (eXtended AUTHentication,XAUTH)。 不推荐使用此参数,因为两个对等体不需要就 IKEv2 中的身份验证方法达成一致。请改用 leftauth 参数来定义身份验证方法。auto = ignore | add | route | startIPsec 启动时应自动执行哪些操作(如果有); 当前接受的值是 add、route、start 和 ignore(默认值)。 add 加载连接而不启动它。 route 加载连接并安装内核陷阱。 如果检测到左子网和右子网之间的流量,则建立连接。 start 加载一个连接并立即启动它。 ignore 忽略连接。 这相当于从配置文件中删除一个连接。 仅本地相关,另一端无需同意。closeaction = none | clear | hold | restart定义远程对等体意外关闭 CHILD_SA 时要采取的操作。如果对等体使用重新身份验证或 uniquids 检查,则不应使用关闭操作,因为这些事件可能会在不需要时触发定义的操作。compress = yes | no是否在连接上建议IPComp压缩内容(链路级压缩对加密数据不起作用,因此要有效,必须在加密之前进行压缩); 可接受的值为 yes 和 no(默认值)。 值为 yes 会导致守护程序建议压缩和未压缩,并且更喜欢压缩。 no 值阻止守护进程提议或接受压缩。dpdaction = none | clear | hold | restart控制死节点检测协议 (Dead Peer Detection,DPD, RFC 3706) 的使用,其中定期发送 R_U_THERE 通知消息 (IKEv1) 或空 INFORMATIONAL 消息 (IKEv2) 以检查 IPsec 对等点的活跃性。 值 clear、hold 和 restart 都激活 DPD 并确定超时时要执行的操作。 clear连接关闭后,不采取进一步行动。 hold 安装一个陷阱策略,它将捕获匹配的流量并尝试按需重新协商连接。 restart 将立即触发重新协商连接的尝试。 默认值为 none,禁用 DPD 消息的主动发送。dpddelay = 30s | <time>定义将 R_U_THERE 消息/INFORMATIONAL 交换发送到对等体的周期时间间隔。 只有在没有收到其他流量时才会发送这些信息。 在 IKEv2 中,值为 0 时不发送额外的信息消息,并且仅使用标准消息(例如要重新加密的消息)来检测死节点。dpdtimeout = 150s | <time>定义超时间隔,在此之后与对等体的所有连接都将在不活动的情况下被删除。 这仅适用于 IKEv1,在 IKEv2 中,默认重传超时适用,因为每个交换都用于检测死对等体。inactivity = <time>定义超时间隔,在此之后,如果 CHILD_SA 未发送或接收任何流量,则将其关闭。 在 CHILD_SA 更新密钥期间,不活动计数器被重置。这意味着不活动超时必须小于重新生成密钥的间隔才能生效。eap_identity = <id>定义客户端用来回复 EAP 身份请求的身份。 如果在 EAP 服务器上定义,则定义的身份将在 EAP 身份验证期间用作对等体身份。 特殊值 %identity 使用 EAP 身份方法向客户端询问 EAP 身份。 如果未定义,IKEv2 身份将用作 EAP 身份。esp = <cipher suites>用于连接的 ESP 加密/身份验证算法的逗号分隔列表,例如 aes128-sha256。 表示法是加密完整性[-dhgroup][-esnmode]。 对于 IKEv2,同一类型的多个算法(用 - 分隔)可以包含在单个提案中。 IKEv1 仅包含提案中的第一个算法。 只能使用 ah 或 esp 关键字,不支持 AH+ESP 同时使用。默认为 aes128-sha256。守护程序将其广泛的默认提议添加到此默认值或配置值。要将其限制为已配置的提案,可以在末尾添加感叹号 (!)。注意:作为响应者,守护进程默认选择第一个配置的提案,该提案也受到对等体的支持。这可以通过 strongswan.conf更改为选择对等体发送的第一个可接受的提案。为了限制响应者只接受特定的密码套件,可以使用严格标志(!,感叹号),例如:aes256-sha512-modp4096!如果指定了 dh-group,则 CHILD_SA/快速模式密钥更新和初始协商使用指定组的单独 Diffie-Hellman 交换。但是,对于 IKEv2,使用 IKE_SA 隐式创建的 CHILD_SA 的密钥将始终来自 IKE_SA 的密钥材料。因此,此处指定的任何 DH 组仅在 CHILD_SA 稍后被重新加密或使用单独的 CREATE_CHILD_SA 交换创建时才适用。因此,建议不匹配可能不会在 SA 建立时立即被注意到,但可能会导致更新密钥失败。esnmode 的有效值为 esn 和 noesn。指定两者都与对等体协商扩展序列号支持,默认为 noesn。forceencaps = yes | no即使未检测到 NAT 情况,也强制对 ESP 报文进行 UDP 封装。 这可能有助于克服限制性防火墙。 为了强制对等体封装报文,NAT 检测有效负载是伪造的。fragmentation = yes | accept | force | no是否使用 IKE 分片(根据 RFC 7383 的专有 IKEv1 扩展或 IKEv2 分片)。 可接受的值为 yes(默认值)、accept、force 和 no。 如果设置为yes,并且对等体支持,超大的IKE 消息将分片发送。 如果设置为接受,则会向对等体宣布对分片的支持,但守护进程不会以分片的形式发送自己的消息。 如果设置为强制(仅支持 IKEv1),初始 IKE 消息将在需要时被分片。 最后,将该选项设置为 no 将禁用宣布对此功能的支持。请注意,无论此选项的值如何(即使设置为 no),对等体发送的分片 IKE 消息总是被接受。ike = <cipher suites>要使用的 IKE/ISAKMP SA 加密/身份验证算法的逗号分隔列表,例如 aes128-sha256-modp3072。 符号是加密完整性[-prf]-dhgroup。 如果没有给出 PRF,则为完整性定义的算法用于 PRF。 prf 关键字与完整性算法相同,但具有 prf 前缀(例如 prfsha1、prfsha256 或 prfaesxcbc)。在 IKEv2 中,可能包含多种算法和提议,例如 aes128-aes256-sha1-modp3072-modp2048,3dessha1-md5-modp1024。默认为 aes128-sha256-modp3072。 守护程序将其广泛的默认提议添加到此默认值或配置值。 要将其限制为已配置的提案,可以在末尾添加感叹号 (!)。注意:作为响应者,守护进程接受从对等体收到的第一个支持的提案。 为了限制响应者只接受特定的密码套件,可以使用严格标志(!,感叹号),例如:aes256-sha512-modp4096!ikedscp = 000000 | <DSCP field>要在从此连接发送的传出 IKE 报文上设置的区分服务字段代码点。 该值是定义要设置的代码点的六位二进制编码字符串,如 RFC 2474 中所定义。ikelifetime = 3h | <time>在重新协商之前,连接(ISAKMP 或 IKE SA)的密钥通道应该持续多长时间。 另请参阅下面的“SA到期/更新密钥”。installpolicy = yes | no决定是否由 charon 守护进程为给定连接在内核中安装 IPsec 策略。允许和平合作,例如与想要控制内核策略的移动 IPv6 守护进程 mip6d 一起使用。 可接受的值为 yes(默认值)和 no。keyexchange = ike | ikev1 | ikev2应该使用哪个密钥交换协议来启动连接。 标有 ike 的连接在启动时使用 IKEv2,但在响应时接受任何协议版本。keyingtries = 3 | <number> | %forever在放弃之前应该进行多少次尝试(整数或 %forever)来协商连接或替换连接(默认 3)。 值 %forever 表示“永不放弃”。 仅本地相关,另一端无需同意。left = <ip address> | <fqdn> | %any | <range> | <subnet>左侧参与者的公共网络接口的 IP 地址或几个魔术值之一。本地端点的值 %any(默认值)表示在协商期间要填写的地址(通过自动键入)。如果本地对等体发起连接设置,则会查询路由表以确定正确的本地 IP 地址。如果本地对等体响应连接设置,则将接受分配给本地接口的任何 IP 地址。完全限定域名或 IP 地址前面的前缀 % 将隐式设置 leftallowany=yes。如果 %any 用于远程端点,它的字面意思是任何 IP 地址。如果分配了 FQDN,则每次完成配置查找时都会对其进行解析。如果 DNS 解析超时,则查找会延迟该时间。要将连接限制在特定范围的主机,可以指定范围(10.1.0.0-10.2.255.255)或子网(10.1.0.0/16),多个地址、范围和子网可以用逗号分隔。虽然可以自由组合这些项目,但要启动连接,至少需要一个范围/子网。请注意,使用通配符时,多个连接描述可能会匹配给定的传入连接尝试。在这种情况下使用最具体的描述。leftallowany = yes | noleft 的修饰符,尽管已分配了具体的 IP 地址或域名,但使其行为为 %any。leftauth = <auth method>在本地(左)使用或从远程(右)端使用的身份验证方法。可接受的值是用于公钥认证 (RSA/ECDSA) 的 pubkey,用于预共享密钥认证的 psk,用于(要求)在 IKEv2 中使用可扩展认证协议的 eap,以及用于 IKEv1 扩展认证的 xauth。要要求远程端的信任链公钥强度,请指定密钥类型,后跟以位为单位的最小强度(例如 ecdsa-384 或 rsa-2048-ecdsa-256)。要限制信任链验证的可接受散列算法集,请将散列算法附加到 pubkey 或密钥强度定义(例如 pubkey-sha256-sha512、rsa-2048-sha256-sha384-sha512 或 rsa-2048-sha256-ecdsa- 256-sha256-sha384)。除非在 strongswan.conf中禁用,或者配置了明确的 IKEv2 签名约束(见下文),否则这些密钥类型和哈希算法也将作为对远程端使用的 IKEv2 签名认证方案的约束。如果两个对等点都支持 RFC 7427(“IKEv2 中的签名认证”),则可以配置在 IKEv2 认证期间使用的特定散列算法。语法与上面相同,但带有 ike: 前缀。例如,对于 ike:pubkeysha384-sha256,具有 SHA-384 或 SHA-256 的公钥签名方案将用于身份验证,按照该顺序并取决于对等体支持的哈希算法。如果未配置特定的哈希算法,则默认优先选择匹配或超过签名密钥强度的算法。如果没有配置带有 ike: 前缀的约束,则任何签名方案约束(没有 ike: 前缀)也将应用于 IKEv2 身份验证,除非在 strongswan.conf中禁用此功能。要使用或要求 RSASSA-PSS 签名,请使用 rsa/pss 而不是 rsa,例如ike:rsa/pss-sha256。如果配置了 pubkey 或 rsa 约束,则只有在 strongswan.conf中启用时,才会使用/接受 RSASSA-PSS 签名。对于 eap,可以附加一个可选的 EAP 方法。当前定义的方法有 eap-aka、eap-gtc、eap-md5、eap-mschapv2、eap-peap、eap-sim、eap-tls、eap-ttls、eap-dynamic 和 eap-radius。或者,接受 IANA 分配的 EAP 方法编号。供应商特定的 EAP 方法以 eap-type-vendor 的形式定义(例如 eap-7-12345)。要为 EAP-(T)TLS 指定签名和信任链约束,请在 EAP 方法后附加一个冒号,后跟上面讨论的密钥类型/大小和哈希算法。对于 xauth,可以指定 XAuth 身份验证后端,例如 xauth-generic 或 xauth-eap。如果在 leftauth 中使用 XAuth,则使用混合身份验证。对于传统的 XAuth 身份验证,在 lefauth2 中定义 XAuth。leftauth2 = <auth method>与 leftauth 相同,但定义了额外的身份验证交换。 在 IKEv1 中,第二轮认证只能使用 XAuth。 IKEv2 使用 RFC 4739 中定义的“多重身份验证交换”支持多轮完整的身份验证。例如,这允许对主机和用户进行单独的身份验证。leftca = <issuer dn> | %same证书颁发机构的专有名称,需要位于从左参与者证书到根证书颁发机构的信任路径中。 %same 表示应该重用为正确参与者配置的值。leftca2 = <issuer dn> | %same与 leftca 相同,但用于第二轮身份验证(仅限 IKEv2)。leftcert = <path>左侧参与者的 X.509 证书的路径。 该文件可以以 PEM 或 DER 格式编码。 也支持 OpenPGP 证书。 绝对路径或相对于 /etc/ipsec.d/certs 的路径都被接受。 默认情况下,leftcert 将 leftid 设置为证书主题的可分辨名称。 但是,可以通过指定必须由证书认证的 leftid 值来覆盖左侧参与者的 ID。 %smartcard[<slot nr>[@<module>]]:<keyid> 形式的值定义要从 PKCS#11 后端为此连接加载的特定证书。 有关智能卡定义的详细信息,请参阅 ipsec.secrets。 仅当使用 leftid 选择证书不够时才需要 leftcert,例如,如果多个证书使用相同的主题。 可以在逗号分隔的列表中指定多个证书路径或 PKCS#11 后端。 如果可能,守护程序会根据收到的证书请求选择证书,然后再强制执行第一个。leftcert2 = <path>与 leftcert 相同,但用于第二轮身份验证(仅限 IKEv2)。leftcertpolicy = <OIDs>对等体的证书必须具有的证书策略 OID 的逗号分隔列表。 OID 使用数字点表示来指定。leftdns = <servers>要作为配置属性交换的 DNS 服务器地址的逗号分隔列表。 在启动器上,服务器是一个固定的 IPv4/IPv6 地址,或 %config4/%config6 来请求没有地址的属性。 在响应者上,仅允许使用固定的 IPv4/IPv6 地址并定义分配给客户端的 DNS 服务器。leftfirewall = yes | no左侧参与者是否正在使用 iptables 对来自 leftsubnet 的流量进行转发防火墙(包含伪装),一旦建立连接,就应该关闭(对于到另一个子网的流量);可接受的值为 yes 和 no(默认值)。不能在与 leftupdown 相同的连接描述中使用。作为默认 ipsec _updown 脚本的参数实现。请参阅下面的注释。仅本地相关,另一端无需同意。如果一个或两个安全网关都在进行转发防火墙(可能包含伪装),并且这是使用防火墙参数指定的,则使用 IPsec 建立的隧道不受其影响,因此报文可以通过隧道保持不变。 (这意味着以这种方式连接的所有子网必须具有不同的、不重叠的子网地址块。)这是由默认的 ipsec _updown 脚本完成的。在需要更多控制的情况下,用户最好提供他自己的 updown 脚本,以便对他的系统进行适当的调整。leftgroups = <group list>逗号分隔的组名列表。 如果 leftgroups 参数存在,则对等体必须是该参数定义的至少一个组的成员。leftgroups2 = <group list>与 leftgroups 相同,但用于使用 leftauth2 定义的第二轮身份验证。lefthostaccess = yes | no使用默认的 ipsec _updown 脚本插入一对 INPUT 和 OUTPUT iptables 规则,从而在主机的内部接口是协商的客户端子网的一部分的情况下允许访问主机本身。 可接受的值为 yes 和 no(默认值)。leftid = <id>如何识别左参与者以进行身份验证;默认为 left 或使用 leftcert 配置的证书的主题。如果配置了 leftcert,则必须通过证书确认身份。可以是 IP 地址、完全限定域名、电子邮件地址或可识别名称,其 ID 类型会自动确定,字符串会转换为适当的编码。此转换的规则在下面的“身份解析”中描述。在某些特殊情况下,上面的身份解析可能不充分或产生错误的结果。例如需要将 FQDN 编码为 KEY_ID,或者字符串解析器无法生成证书 DN 的正确二进制 ASN.1 编码。对于这些情况,可以强制执行特定的身份类型并提供身份的二进制编码。为此,可以使用前缀,后跟冒号 (:)。如果数字符号 (#) 跟在冒号后面,则剩余数据被解释为十六进制编码,否则将字符串原样用作标识数据。注意:后者意味着不对非字符串身份执行任何转换。例如,ipv4:10.0.0.1 不会创建有效的 ID_IPV4_ADDR IKE 身份,因为它不会转换为二进制 0x0a000001。相反,可以使用 ipv4:#0a000001 来获得有效身份,但仅使用具有自动转换的隐式类型通常更简单。这同样适用于 ASN.1 编码类型。以下前缀是已知的:ipv4、ipv6、rfc822、email、userfqdn、fqdn、dns、asn1dn、asn1gn 和 keyid。自定义类型前缀可以通过用大括号包围数字类型值来指定。对于 IKEv2 和 rightid,身份前面的前缀 % 可防止守护程序在其 IKE_AUTH 请求中发送 IDr,并允许它根据响应者证书中包含的主题和 subjectAltNames 验证配置的身份(否则仅与 IDr 进行比较由响应者返回)。如果响应者为 leftid 配置了不同的值,则发起者发送的 IDr 可能会阻止响应者找到配置。leftid2 = <id>
文章
算法  ·  网络协议  ·  安全  ·  Shell  ·  网络安全  ·  数据安全/隐私保护  ·  网络虚拟化
2023-02-24
【番外01】吐血整理5万字100道高频基础面试题 无名面试集《烂俗前端》
《烂俗前端》是一部以前端为题材的小说,涉及讨论职业、社会、技术、情感等话题,正在更新中。之前吴明在对赵铁柱考验之前,扔了一份面试题集合让赵铁柱背,说:“你现在这个阶段,做到理解这些题还比较难,所以想过一些面试,就一个字,'背'!当然,死记硬背是在你尝试去理解未果的前提下。”,“另外,在这之前快速看完HTML/CSS/JS的基础内容, 比如两天看一遍。不然看面试题就是一脸懵逼。”有些同学总觉得光背这些不去理解的话没什么鸟用,能理解当然好,不能理解,背会了对面试官来说,那也是属于你的知识,学习态度也算ok。铁柱硬着头皮背了下来。下面是面试题正文。作者:吴明声明:本面试题非完全原创,作者负责筛选整理、编辑、补全解答、撰写。主要读者人群:入门新人、社招面试者、初级前端。01、什么是HTML语义化?HTML语义化就是让页面内容结构化,它有如下优点:1、易于用户阅读,样式丢失的时候能让页面呈现清晰的结构。2、有利于SEO,搜索引擎根据标签来确定上下文和各个关键字的权重。3、方便其他设备解析,如盲人阅读器根据语义> 渲染网页4、有利于开发和维护,语义化更具可读性,代码更好维护,与CSS3关系更和谐02、行内元素和块级元素?img算什么?行内元素怎么转化为块级元素??行内元素:和有他元素都在一行上,高度、行高及外边距和内边距都不可改变,文字图片的宽度不可改变,只能容纳文本或者其他行内元素;其中img是行元素。块级元素:总是在新行上开始,高度、行高及外边距和内边距都可控制,可以容纳内敛元素和其他元素。行元素转换为块级元素方式:display:block;03、请说出一些HTML5新增标签能记多少记得少,太少用的我就不列出来了章节:<section> 定义文档中的一个章节,一般来说会有包含一个 heading<nav>定义一个含有多个超链接的区域,这个区域包含转到其他页面,或者页面内部其他部分的链接列表<article> 表示文档、页面、应用或网站中的独立结构,其意在成为可独立分配的或可复用的结构<aside> 定义和页面内容联度较低的内容--如果被删除,剩下的内容仍然很合理<header> 定义页面或章节的头部。它经常包含logo、页面标题和导航性的目录<footer> 定义页面或章节的尾部。它经常包含版权信息、法律信息链接和反馈建议用的地址<main> 定义文档中主要或重要的独一无二的内容。一个文档中不能出现一个以上的<main>标签文字形式:<data> 将一个指定内容和机器可读的翻译联系在一起。但如果内容是与time和date相关的,一定要使用<time><time> 代表日期和时间值;机器可读的等价形式通过datetime属性指定<mark> 代表一段需要被高亮的引用文字,用来表示上下文的关联性<ruby> 表示被ruby注释标记的文本,如中文汉字和它的拼音<bdi> 代表需要脱离父元素文本方向的一段文本。它允许嵌入一段不同或未知文本方向格式的文本<wbr> 代表建议换行,当文本太长需要换行时将会在此处添加换行符嵌入内容:<embed> 代表一个嵌入的外部资源,如应用程序或交互内容,换句话说,就是一个插件。如<embed type="video/quicktime" src="movie.mov" width="640" height="480"><video> 代表一段视频及其视频文件和字幕,并提供了播放视频的用户界面<audio> 代表一段声音或音频流。 <audio> 元素可以包含多个音频资源, 这些音频资源可以使用 src 属性或者<source> 元素来进行描述<source> 为<video>或<audio>这类媒体元素指定媒体源<track> 为<video>或<audio>这类媒体元素指定文本轨道(字幕)<canvas> 代表位图区域,可以通过脚本在它上面实时呈现图形,如图表、游戏绘图等<svg> 定义一个嵌入式矢量图<math> 定义一段数学公式表单:<datalist> 代表提供给其他控件的一组预定义选项<keygen> 代表一个密钥对生成器控件<output> 代表计算值<meter> 代表滑动条<progress> 代表进度条,用来显示一项任务的完成进度交互元素:<details> 代表一个用户可以(点击)获取额外信息或控件的小部件。与summary配合使用<summary> 代表 <details> 元素的综述或标题<menuitem> 代表一个用户可以点击的菜单项<menu> 代表菜单,呈现了一组用户可执行或激活的命令。这既包含了可能出现在屏幕顶端的列表菜单,也包含了那些隐藏在按钮之下、当点击按钮后显示出来的文本菜单。04、src和href的区别src 是指向外部资源的位置,指向的内容会嵌入到文档当前标签所在的位置,如css、js脚本、img等href 是指向网络资源所在的位置(的超链接),如<a href='xxx'></a>05、前端页面有哪三层构成,分别是什么?作用是什么?分成:结构层、表示层、行为层。结构层(structural layer)由 HTML 或 XHTML 之类的标记语言负责创建。标签,也就是那些出现在尖括号里的单词,对网页内容的语义含义做出了描述,但这些标签不包含任何关于如何显示有关内容的信息。例如,P 标签表达了这样一种语义:“这是一个文本段。”表示层(presentation layer)由 CSS 负责创建。 CSS 对“如何显示有关内容”的问题做出了回答。行为层(behaviorlayer)负责回答“内容应该如何对事件做出反应”这一问题。这是 Javascript 语言和 DOM 主宰的领域。06、请写出至少5个HTML块元素标签div、p、ul、li、table、h1、h2、h3 ... h6、form 等07、请写出至少5个HTML行内元素标签span、a、i、label、img、input、button、textarea、select 等08、常用浏览器有哪些,内核都是什么?常用浏览器有IE、火狐(firefox)、chrome、safari 、360、搜狗等内核:IE的是 Trident,新版微软浏览器Edge使用Webkit火狐的是 Geckosafari 用的是 Webkit360和搜狗这些分极速模式和兼容模式,极速模式用的Webkit的内核,兼容模式用的Trident内核09、对 WEB 标准以及 W3C 的理解与认识标签闭合、标签小写、不乱嵌套、提高搜索机器人搜索几率、使用外 链 css 和 js 脚本、结构行为表现的分离、文件下载与页面速度更快、内容能被更多的用户所访问、内容能被更广泛的设备所访问、更少的代码和组件,容易维 护、改版方便,不需要变动页面内容、提供打印版本而不需要复制内容、提高网站易用性。10、前端需要注意哪些 SEO合理的 title、description、keywords:搜索对着三项的权重逐个减小,title 值强调重点即可,重要关键词出现不要超过 2 次,而且要靠前,不同页面 title 要有所不同;description 把页面内容高度概括,长度合适,不可过分堆砌关键词,不同页面 description 有所不同;keywords 列举出重要关键词即可语义化的 HTML 代码,符合 W3C 规范:语义化代码让搜索引擎容易理解网页重要内容 HTML 代码放在最前:搜索引擎抓取 HTML 顺序是从上到下,有的搜索引擎对抓取长度有限制,保证重要内容一定会被抓取重要内容不要用 js 输出:爬虫不会执行 js 获取内容少用 iframe:搜索引擎不会抓取 iframe 中的内容非装饰性图片必须加 alt提高网站速度:网站速度是搜索引擎排序的一个重要指标11、Canvas 和 SVG 有什么区别?Canvas 和 SVG 都允许您在浏览器中创建图形,但是它们在根本上是不同的。Canvas通过 Javascript 来绘制 2D 图形。是逐像素进行渲染的。其位置发生改变,会重新进行绘制。SVG一种使用 XML 描述的 2D 图形的语言SVG 基于 XML 意味着,SVG DOM 中的每个元素都是可用的,可以为某个元素附加 Javascript 事件处理器。在 SVG 中,每个被绘制的图形均被视为对象。如果 SVG 对象的属性发生变化,那么浏览器能够自动重现图形。比较Canvas依赖分辨率不支持事件处理器弱的文本渲染能力能够以 .png 或 .jpg 格式保存结果图像最适合图像密集型的游戏,其中的许多对象会被频繁重绘SVG不依赖分辨率支持事件处理器最适合带有大型渲染区域的应用程序(比如谷歌地图)复杂度高会减慢渲染速度(任何过度使用 DOM 的应用都不快)不适合游戏应用12、meta viewport 原理是什么?meta viewport 标签的作用是让当前 viewport 的宽度等于设备的宽度,同时不允许用户进行手动缩放viewport的原理:移动端浏览器通常都会在一个比移动端屏幕更宽的虚拟窗口中渲染页面,这个虚拟窗口就是 viewport; 目的是正常展示没有做移动端适配的网页,让他们完整的展示给用户;解析:Viewport :字面意思为视图窗口,在移动 web 开发中使用。表示将设备浏览器宽度虚拟成一个特定的值(或计算得出),这样利于移动 web 站点跨设备显示效果基本一致。移动版的 Safari 浏览器最新引进了 viewport 这个 meta tag,让网页开发者来控制 viewport 的大小和缩放,其他手机浏览器也基本支持。在移动端浏览器当中,存在着两种视口,一种是可见视口(也就是我们说的设备大小),另一种是视窗视口(网页的宽度是多少)。举个例子:如果我们的屏幕是 320 像素 * 480 像素的大小(iPhone4),假设在浏览器中,320 像素的屏幕宽度能够展示 980 像素宽度的内容。那么 320 像素的宽度就是可见视口的宽度,而能够显示的 980 像素的宽度就是视窗视口的宽度。为了显示更多的内容,大多数的浏览器会把自己的视窗视口扩大,简易的理解,就是让原本 320 像素的屏幕宽度能够容下 980 像素甚至更宽的内容(将网页等比例缩小)。13、Viewport 属性值width 设置 layout viewport 的宽度,为一个正整数,或字符串"width-device"initial-scale 设置页面的初始缩放值,为一个数字,可以带小数minimum-scale 允许用户的最小缩放值,为一个数字,可以带小数maximum-scale 允许用户的最大缩放值,为一个数字,可以带小数height 设置 layout viewport 的高度,这个属性对我们并不重要,很少使用user-scalable 是否允许用户进行缩放,值为"no"或"yes", no 代表不允许,yes 代表允许这些属性可以同时使用,也可以单独使用或混合使用,多个属性同时使用时用逗号隔开就行了。14、为什么最好把 CSS 的<link>标签放在<head></head>之间?为什么最好把 JS 的<script>标签恰好放在</body>之前,有例外情况吗?把<link>放在<head>中把<link>标签放在<head></head>之间是规范要求的内容。此外,这种做法可以让页面逐步呈现,提高了用户体验。将样式表放在文档底部附近,会使许多浏览器(包括 Internet Explorer)不能逐步呈现页面。一些浏览器会阻止渲染,以避免在页面样式发生变化时,重新绘制页面中的元素。这种做法可以防止呈现给用户空白的页面或没有样式的内容。把<script>标签恰好放在</body>之前脚本在下载和执行期间会阻止 HTML 解析。把<script>标签放在底部,保证 HTML 首先完成解析,将页面尽早呈现给用户。例外情况是当你的脚本里包含document.write()时。但是现在,document.write()不推荐使用。同时,将<script>标签放在底部,意味着浏览器不能开始下载脚本,直到整个文档(document)被解析。也许,对此比较好的做法是,<script>使用defer属性,放在<head>中。15、img 上 title 与 alttitle 指图片的信息、alt 指图片不显示时显示的文字16、DOM Tree是如何构建的?HTML 解释器HTML 解释器的工作就是将网络或者本地磁盘获取的 HTML 网页和资源从字节流解释成 DOM 树结构。JavaScript 的执行在 HTML 解释器的工作过程中,可能会有 JavaScript 代码需要执行,它发生在将字符串解释成词语之后、创建各种节点的时候。这也是为什么全局执行的 JavaScript 代码不能访问 DOM 的原因——因为 DOM 树还没有被创建完呢。17、video标签的几个个属性方法src:视频的URLposter:视频封面,没有播放时显示的图片preload:预加载autoplay:自动播放loop:循环播放controls:浏览器自带的控制条width:视频宽度height:视频高度18、script标签中defer和async的区别defer 浏览器指示脚本在文档被解析后执行,script被异步加载后并不会立即执行,而是等待文档被解析完毕后执行<script type="text/javascript" src="x.min.js" defer="defer"></script>defer只适用于外联脚本,如果script标签没有指定src属性,只是内联脚本,不要使用defer如果有多个声明了defer的脚本,则会按顺序下载和执行defer脚本会在DOMContentLoaded和load事件之前执行async 同样是异步加载脚本,区别是脚本加载完毕后立即执行,这导致async属性下的脚本是乱序的,对于script又先后依赖关系的情况,并不适用<script type="text/javascript" src="x.min.js" async="async"></script>只适用于外联脚本,这一点和defer一致如果有多个声明了async的脚本,其下载和执行也是异步的,不能确保彼此的先后顺序async会在load事件之前执行,但并不能确保与DOMContentLoaded的执行先后顺序19、meta标签常用属性Keywords(关键词)说明:告诉搜索引擎你网页的关键字(keywords)使用方法:<meta name="keywords" content="标签,属性,seo优化">Robots (机器人向导)说明:Robots用来告诉搜索机器人页面需要或者不需要索引。Content的參数有all、none、index、noindex、follow、nofollow。默认是all。使用方法:<meta name="robots" content="All|None|Index|Noindex|Follow|Nofollow">all:文件将被检索,且页面上的链接能够被查询。none:文件将不被检索。且页面上的链接不能够被查询。(和 "noindex, no follow" 起同样作用)index:文件将被检索;(让robot/spider登录)follow:页面上的链接能够被查询;noindex:文件将不被检索,但页面上的链接能够被查询;(不让robot/spider登录)nofollow:文件将不被检索,页面上的链接能够被查询。(不让robot/spider顺着此页的连接往下探找)viewport(视窗/移动端)**说明:viewport 是用户网页的可视区域,即“视区”。使用方法:<meta name="viewport" content="width=device-width, initial-scale=1.0">width:控制 viewport 的大小,可以指定的一个值,如 600,或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)。height:和 width 相对应,指定高度。initial-scale:初始缩放比例,也即是当页面第一次 load 的时候缩放比例。maximum-scale:允许用户缩放到的最大比例。minimum-scale:允许用户缩放到的最小比例。user-scalable:用户是否可以手动缩放。http-equiv="X-UA-Compatible" (这是一个文档兼容模式的定义)使用: <meta http-equiv = "X-UA-Compatible" content = "chrome=1" >X-UA-Compatible:是IE8新加的一个设置,对于IE8以下的浏览器是不识别的,通过在meta中设置X-UA-Compatible的值,可以指定网页的兼容性模式设置。< meta http-equiv = "X-UA-Compatible" content = "chrome=1" >用以声明当前页面用chrome内核来渲染。Edge模式告诉IE以最高级 模式渲染文档,也就是任何IE版本都以当前版本所支持的最高级标准模式渲染,避免版本升级造成的影响。renderer(指定双核浏览器默认以何种方式渲染页面)使用:<meta name="renderer" content="webkit">这段代码意思:强制浏览器使用Webkit内核。若页面需默认用极速核,增加标签:<meta name="renderer" content="webkit">若页面需默认用ie兼容内核,增加标签:<meta name="renderer" content="ie-comp">若页面需默认用ie标准内核,增加标签:<meta name="renderer" content="ie-stand">举例说明a. 设置屏幕宽度为设备宽度,禁止用户手动调整缩放<meta name="viewport" content="width=device-width,user-scalable=no" />b. 设置屏幕密度为高频,中频,低频自己主动缩放,禁止用户手动调整缩放)<meta name="viewport" content="width=device-width, target-densitydpi=high-dpi, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>另外iOS 7.1的Safari为meta标签新增minimal-ui属性,在网页载入时默认隐藏地址栏与导航栏。20、HTML5 为什么只需要写<!DOCTYPE HTML>,而不需要引入 DTD?HTML5 不基于 SGML,因此不需要对 DTD 进行引用,但是需要 DOCTYPE 来规范浏览器的行为(让浏览器按照它们应该的方式来运 行)。而 HTML4.01 基于 SGML ,所以需要对 DTD 进行引用,才能告知浏览器文档所使用的文档类型。21、DTD 介绍DTD( Document Type Definition 文档类型定义)是一组机器可读的规则,它们定义 XML 或 HTML 的特定版本中所有允许元 素及它们的属性和层次关系的定义。在解析网页时,浏览器将使用这些规则检查页面的有效性并且采取相应的措施。DTD 是对 HTML 文档的声明,还会影响浏览器的渲染模式(工作模式)。22、简述前端优化的方式尽量减少HTTP请求次数减少DNS查找次数避免跳转可缓存的AJAX推迟加载内容预加载减少DOM元素数量根据域名划分页面内容使iframe的数量最小不要出现404错误使用内容分发网络为文件头指定Expires或Cache-Control 13、Gzip压缩文件内容配置ETag尽早刷新输出缓冲使用GET来完成AJAX请求把样式表置于顶部避免使用CSS表达式(Expression)使用外部JavaScript和CSS削减JavaScript和CSS用<link>代替@import避免使用滤镜把脚本置于页面底部剔除重复脚本23、CSS盒子模型盒模型分为标准盒模型和怪异盒模型(IE模型)/* 使用css指定某个元素的盒子模型类型 */ box-sizing:content-box; /*标准盒模型*/ box-sizing:border-box; /*怪异盒模型*/上图显示:在CSS盒子模型规定了元素处理元素的几种方式:width和height:内容的宽度、高度(不是盒子的宽度、高度)。padding:内边距。border:边框。margin:外边距。CSS盒模型和IE盒模型的区别:在 标准盒子模型中,width 和 height 指的是内容区域的宽度和高度。增加内边距、边框和外边距不会影响内容区域的尺寸,但是会增加元素框的总尺寸。IE盒子模型中,width 和 height 指的是内容区域+border+padding的宽度和高度。24、为什么要初始化CSS样式。因为浏览器的兼容问题,不同浏览器对有些标签的默认值是不同的,如果没对CSS初始化往往会出现浏览器之间的页面显示差异。25、如何让一个div 上下左右居中?<div class="div1"></div> /*给出三种css答案,实际上还有更多方法*/ /*方法一*/ .div1{ width:400px; height:400px; border:#CCC 1px solid; /*下面几个才是居中的关键属性*/ position:absolute; left:50%; top:50%; transform: translate(-50%,-50%); } /*方法二*/ .div1{ width:400px; height:400px; border:#CCC 1px solid; /*下面几个才是居中的关键属性*/ position: absolute; left:0; top: 0; bottom: 0; right: 0; margin: auto; } /*方法三*/ .div1{ width:400px; height:400px; border:#CCC 1px solid; /*下面几个才是居中的关键属性*/ position: absolute; left: 50%; top:50%; margin-left:-200px; margin-top: -200px; }26、简述css hack?(现在浏览器)由于不同的浏览器,比如Internet Explorer 6,Internet Explorer 7,Mozilla Firefox等,对CSS的解析认识不一样,因此会导致生成的页面效果不一样,得不到我们所需要的页面效果。这个时候我们就需要针对不同的浏览器去写不同的CSS,让它能够同时兼容不同的浏览器,能在不同的浏览器中也能得到我们想要的页面效果。这个针对不同的浏览器写不同的CSS code的过程,就叫CSS hack,也叫写CSS hack。CSS hack是通过在CSS样式中加入一些特殊的符号,让不同的浏览器识别不同的符号(什么样的浏览器识别什么样的符号是有标准的,CSS hack就是让你记住这个标准),以达到应用不同的CSS样式的目的,比如.kwstu{width:300px;_width:200px;}, 一般浏览器会先给元素使用width:300px;的样式,紧接着后面还有个_width:200px;,由于下划线_width只有IE6可以识别,所以此样式在IE6中实际设置对象的宽度为200px,后面的把前面的给覆盖了,而其他浏览器不识别_width不会执行_width:200px;这句样式,所以在其他浏览器中设置对象的宽度就是300px;27、CSS 选择器有哪些?id选择器( #myid)类选择器(.myclassname)标签选择器(div, h1, p)相邻选择器(h1 + p)子选择器(ul > li)后代选择器(li a)通配符选择器( * )属性选择器(a[rel = “external”])伪类选择器(a:hover, li:nth-child)28、css选择器的权重(优先级)!important > 行内样式 > #id > .class > 元素和伪元素 > * > 继承 > 默认29、CSS3新特性新增选择器 p:nth-child(n){color: rgba(255, 0, 0, 0.75)}弹性盒模型 display: flex;多列布局 column-count: 5;媒体查询 @media(max-width: 480px) {.box: {column-count: 1;}}个性化字体 @font-face{font-family:BorderWeb;src:url(BORDERW0.eot);}颜色透明度 color: rgba(255, 0, 0,0.75);圆角 border-radius: 5px;渐变 background:linear-gradient(red, green, blue);阴影 box-shadow:3px 3px 3px rgba(0, 64, 128, 0.3);倒影 box-reflect: below 2px;文字装饰 text-stroke-color: red;文字溢出 text-overflow:ellipsis;背景效果 background-size: 100px 100px;边框效果 border-image:url(bt_blue.png) 0 10;转换旋转 transform: rotate(20deg);倾斜 transform: skew(150deg,-10deg);位移 transform:translate(20px, 20px);缩放 transform: scale(.5);平滑过渡 transition: all .3s ease-in .1s;动画 @keyframes anim-1 {50% {border-radius: 50%;}} animation: anim-1 1s;30、CSS隐藏元素的几种方法opacity: 0; 元素本身依然占据它自己的位置并对网页的布局起作用。它也将响应用户交互;visibility: hidden; 与 opacity 唯一不同的是它不会响应任何用户交互。此外,元素在读屏软件中也会被隐藏;display: none; 设为 none 任何对该元素直接打用户交互操作都不可能生效。此外,读屏软件也不会读到元素的内容。这种方式产生的效果就像元素完全不存在;31、css清除浮动的几种方式?父级div定义 height结尾处加空div标签 clear:both父级div定义 伪类:after 和 zoom父级div定义 overflow:hidden父级div定义 overflow:auto父级div 也一起浮动父级div定义 display:table32、谈谈css预处理器的理解CSS 预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为 CSS 增加了一些编程的特性,将 CSS 作为目标生成文件,然后开发者就只要使用这种语言进行编码工作。CSS 预处理器用一种专门的编程语言,进行 Web 页面样式设计,然后再编译成正常的 CSS 文件,以供项目使用。CSS 预处理器为 CSS 增加一些编程的特性,无需考虑浏览器的兼容性问题通俗的说,“CSS 预处理器用一种专门的编程语言,进行 Web 页面样式设计,然后再编译成正常的 CSS 文件,以供项目使用。CSS 预处理器为 CSS 增加一些编程的特性,无需考虑浏览器的兼容性问题”。例如你可以在 CSS 中使用变量、简单的逻辑程序、函数(如右侧代码编辑器中就使用了变量$color)等等在编程语言中的一些基本特性,可以让你的 CSS 更加简洁、适应性更强、可读性更佳,更易于代码的维护等诸多好处。CSS 预处理器技术已经非常的成熟,而且也涌现出了很多种不同的 CSS 预处理器语言,比如说:Sass(SCSS)LESSStylusTurbineSwithch CSSCSS Cacheer到目前为止,在众多优秀的 CSS 预处理器语言中就属 Sass、LESS 和 Stylus 使用较为广泛。优点:1、CSS变得更易于维护。2、易于编写嵌套选择器。3、用于一致主题的变量。可以跨不同项目共享主题文件。4、Mixins生成重复的CSS。5、诸如循环,列表和映射之类的Sass功能可以使配置更容易且更省力。6、将您的代码分成多个文件。CSS文件也可以拆分,但是这样做需要HTTP请求才能下载每个CSS文件。缺点:1、需要进行预处理的工具。重新编译时间可慢一些。2、不编写当前和潜在可用的CSS。例如,通过将诸如 postcss-loader之类的内容 与 webpack一起使用,您可以编写可能与将来兼容的CSS,从而使您可以使用CSS变量(而不是Sass变量)之类的东西33、请解释一下CSS3的flexbox(弹性盒布局模型),以及适用场景?该布局模型的目的是提供一种更加高效的方式来对容器中的条目进行布局、对齐和分配空间。在传统的布局方式中,block 布局是把块在垂直方向从上到下依次排列的;而 inline 布局则是在水平方向来排列。弹性盒布局并没有这样内在的方向限制,可以由开发人员自由操作。试用场景:弹性布局适合于移动前端开发,在Android和ios上也完美支持。34、CSS 单位最常用的单位:%百分比,px,rem,vh,vw有传统的单位如:% 百分比、cm 厘米、mm 毫米、px 像素(计算机屏幕上的一个点)、in 英寸、pt 磅,此外还有:rgb(x,x,x) rgb(x%,x%,x%) #rrggbb(十六进制)em:1em 等于当前字体尺寸(继承父元素的字体尺寸)rem:r 为 root,1rem 等于根元素字体尺寸(继承 html 的字体尺寸)vh:1vh 等于可视窗口高度的 1/100vw: 1vw 等于可视窗口宽度的 1/100vmin:可视窗口宽高更小的值的 1/100vmax:可视窗口宽高更大的值的 1/100ex:当前字体的一个 x-height,一般为当前字体的一个 em 的一半,因为一个 'x' 字母一般为字体大小的一半ch:设置 width:40ch 表示这个宽度可以容纳 40 个特定字体的字符35、有哪些方式可以对一个DOM设置它的CSS样式?外部样式表。使用<link>引入一个外部CSS文件;内部样式表。将CSS代码放在<head>标签内部;内联样式,将CSS样式直接定义在HTML元素内部;36、知道css有个content属性吗?有什么用?CSS的content属性专门应用在before/after伪元素上,用来插入生成内容。最常见的应用是利用伪类清除浮动:/*一种常见利用伪类清除浮动的代码*/ .clearfix:after { content:"."; /*这里利用到了content属性*/ display:block; height:0; visibility:hidden; clear:both; } .clearfix { *zoom:1; }after伪元素通过content在元素的后面生成一个点的块级元素,再利用clear: both清除浮动。37、display 有哪些值?各有何作用?常用的有以下(还有别的值,相对少用):block 元素按块类型元素一样显示。none 缺省值。元素按行内元素类型一样显示。inline 元素按行内元素类型一样显示。inline-block 元素按行内元素一样显示,但其内容像块类型元素一样显示。list-item 元素按块类型元素一样显示,并添加样式列表标记。38、position 中的 relative 和 absolute 定位的区别?absolute 生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。fixed 生成绝对定位的元素,相对于浏览器窗口进行定位。relative 生成相对定位的元素,相对于其正常位置进行定位。static 默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right z-index 声明)。inherit 规定从父元素继承 position 属性的值。39、用纯 CSS 创建一个三角形的原理是什么?把上、左、右三条边隐藏掉(颜色设为 transparent)#demo { width:0; height: 0; border-width: 20px; border-style: solid; border-color: transparent transparent red transparent; }40、什么是BFC?怎么创建BFC?BFC(block formatting context)指块级格式化上下文。BFC是一个独立的渲染区域,只有block-level box参与,它规定了内部的block-level box如何布局,并且与这个区域外部毫不相干。    BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之也如此,包括浮动和外边距合并等等,有了这个特性我们布局的时候就不会出现意外情况了哪些元素会产生BFCdisplay属性为block、list-item、table的元素,会产生BFC。(最常用的就是块级元素)什么情况下会触发BFC设置了float属性,并且不为noneposition属性为absolute或fixeddisplay为inline-block、table-cell、table-caption、flex、inline-flexoverflow属性不为visibleBFC元素所具有的特性在BFC中,盒子从顶端开始垂直地一个接一个的排列;盒子垂直方向的距离由margin决定,属于同一个BFC的盒子的margin会重叠;在BFC中,每一个盒子的左边缘会触碰到父容器的左边缘内部,也就是说在没有margin和padding时,父border的内边和子border的外边重叠;BFC的区域不会与浮动盒子产生交集,而是紧贴浮动边缘;如果父盒子没有设置高度,但子盒子中有浮动元素,那么在计算BFC的高度时, 会计算上浮动盒子的高度。41、什么叫优雅降级和渐进增强?渐进增强 progressive enhancement:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。优雅降级 graceful degradation:一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。区别:a. 优雅降级是从复杂的现状开始,并试图减少用户体验的供给b. 渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要c. 降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带42、什么是响应式设计?它是关于网站的制作或网页制作的工作。不同的设备有不同的尺寸和不同的功能。响应式设计是让所有的人能在这些设备上让网站运行正常。一部分是媒体查询和不同的视觉效果。一部分是不同的资源(如不同的Javascript来处理触摸与点击自动适应屏幕的对比)43、png,jpg,jpeg,gif,webp,bmp等图片格式?有哪些优缺点?首先jpg和jpeg就可以理解为同一个东西,这里就只讲jpg。jpg:优点:就是图片压缩后不至于太失真,色彩还原度较高缺点:无法做透明图,就是没办法抠出一个图片适用场景:基本上网页上的大图都是jpgpng:优点:能做透明图缺点:体积大,如果色彩较多的,是同等jpg的5-6倍适用场景:网页上的图标,一般都是用png24,png8有点半透明gif:优点:支持动画缺点:颜色种类有限适用场景:各种小动画。。webp:优点:简单说就是压得更小,图片质量却不差缺点:兼容性差,IE和Safari不支持适用场景:指定浏览器环境下可用bmp:优点:高质量图片缺点:太大了适用场景:Windows桌面壁纸44、聊聊Base 64图片优点:减少http请求,因为图片被base64编码进了 css文件中(一般是进css文件)缺点:如果加进css文件中去,css体积会增大,而且会阻塞渲染,(普通图片加载是异步的)适用场景:适用于一些体积较小的图片45、浏览器如何解析css选择器?浏览器会『从右往左』解析CSS选择器。我们知道DOM Tree与Style Rules合成为 Render Tree,实际上是需要将Style Rules附着到DOM Tree上,因此需要根据选择器提供的信息对DOM Tree进行遍历,才能将样式附着到对应的DOM元素上。以下这段css为例.mod-nav h3 span {font-size: 16px;}若从左向右的匹配,过程是:从 .mod-nav 开始,遍历子节点 header 和子节点 div然后各自向子节点遍历。在右侧 div 的分支中最后遍历到叶子节点 a ,发现不符合规则,需要回溯到 ul 节点,再遍历下一个 li-a,一颗DOM树的节点动不动上千,这种效率很低。如果从右至左的匹配:先找到所有的最右节点 span,对于每一个 span,向上寻找节点 h3由 h3再向上寻找 class="mod-nav" 的节点最后找到根元素 html 则结束这个分支的遍历。后者匹配性能更好,是因为从右向左的匹配在第一步就筛选掉了大量的不符合条件的最右节点(叶子节点);而从左向右的匹配规则的性能都浪费在了失败的查找上面46、谈谈对媒体查询的理解什么是媒体查询媒体查询由媒体类型和一个或多个检测媒体特性的条件表达式组成。媒体查询中可用于检测的媒体特性有:width、height和color(等)。使用媒体查询可以在不改变页面内容的情况下,为特性的一些输出设备定制显示效果。通常用于多中设备适配屏幕。媒体查询语法如下面的例子,根据浏览器窗口大小的改变,页面颜色就会改变。/*如果设备如果满足多个条件,以后面写的为准*/ /*屏幕尺寸最大为960px的屏幕下 */ @media screen and (max-width: 960px){ body{ background-color:#FF6699 } } /*屏幕尺寸最大为768px的屏幕下 */ @media screen and (max-width: 768px){ body{ background-color:#00FF66; } } /*屏幕尺寸最大为550px的屏幕下 */ @media screen and (max-width: 550px){ body{ background-color:#6633FF; } } /*屏幕尺寸最大为320px的屏幕下 */ @media screen and (max-width: 320px){ body{ background-color:#FFFF00; } }47、flex弹性布局的使用1.设置盒子的display属性为flex,或者line-flex,其对应还有六个css属性,分别为:flex-direction:设置子元素的排列方式(row,column,row-reverse,column-reverse)flex-warp:设置子元素的是否换行(nowarp,warp,warp-reverse)flex-flow:flex-direction和flex-warp的缩写,默认为row nowarpjustify-content:设置子元素的水平排列方式(flex-start,flex-end,center,span-around,span-between)align-items:设置子元素的垂直方式(flex-start,flex-end,center,stretch,baseline)align-content:设置多个轴线的排列方式(flex-start,flex-end,center,spand-around,spand-between,stretch)2. 对应的子元素项目也拥有自身的六个css属性,分别为:order:设置元素的排列权重 值越大越在后flex-grow:设置元素的放大比例flex-shrink:设置元素的缩小比例flex-basis:设置多余空间项目主轴所占比例空间flex:flex-grow和flex-shrink和flex-basis的缩写方式 默认为0 1 autoalign-self:设置子元素自己的垂直排列方式,默认为盒子的align-items的值设置flex布局后,子元素的float,clear,vertical-align都无效48、 CSS优化、提高性能的方法有哪些?避免过度约束避免后代选择符避免链式选择符使用紧凑的语法避免不必要的命名空间避免不必要的重复最好使用表示语义的名字。一个好的类名应该是描述他是什么而不是像什么避免!important,可以选择其他选择器尽可能的精简规则,你可以合并不同类里的重复规则修复解析错误避免使用多类选择符移除空的css规则正确使用display的属性:由于display的作用,某些样式组合会无效,徒增样式体积的同时也影响解析性能。display:inline后不应该再使用width、height、margin、padding以及float。display:inline-block后不应该再使用float。display:block后不应该再使用vertical-align。display:table-*后不应该再使用margin或者float。不滥用浮动:虽然浮动不可避免,但不可否认很多css bug是由于浮动而引起。不滥用web字体对于中文网站来说Web Fonts可能很陌生,国外却很流行。web fonts通常体积庞大,而且一些浏览器在下载web fonts时会阻塞页面渲染损伤性能。不声明过多的font-size:这是设计层面的问题,设计精良的页面不会有过多的font-size声明。不在选择符中使用ID标识符,主要考虑到样式重用性以及与页面的耦合性。不给h1~h6元素定义过多的样式全站统一定义一遍heading元素即可,若需额外定制样式,可使用其他选择符作为代替。不重复定义h1~h6元素值为0时不需要任何单位标准化各种浏览器前缀:通常将浏览器前缀置于前面,将标准样式属性置于最后.使用CSS渐变等高级特性,需指定所有浏览器的前缀避免让选择符看起来像正则表达式CSS3添加了一些类似~=等复杂属性,也不是所有浏览器都支持,需谨慎使用。遵守盒模型规则(Beware of broken box models)49、一个满屏“品”字布局如何设计?上面的 div 宽100%下面的两个 div 分别宽50%,然后用 float 或者 inline 使其不换行50、li 与 li 之间有看不见的空白间隔是什么原因引起的?有什么解决办法?行框的排列会受到中间空白(回车空格)等的影响,因为空格也属于字符,这些空白也会被应用样式,占据空间,所以会有间隔,把字符大小设为0,就没有空格了。解决方法:可以将<li>代码全部写在一排浮动li中float:left在ul中用font-size:0(谷歌不支持);可以 ul{letter-spacing: -4px;};li{letter-spacing: normal;}51、javascript typeof返会的数据类型有哪些object, string, undefined, number, function, booleanjs的基本数据类型:string, number, boolean, undefined, null数据类型检测:typeof 对于基本数据类型来说,除了 null 都可以显示正确的类型,typeof 对于对象来说,除了函数都会显示 objecttypeof 5 // 'number' typeof '5' // 'string' typeof undefined // 'undefined' typeof false// 'boolean' typeof Symbol() // 'symbol' console.log(typeof null) //object console.log(typeof NaN) //number typeof [] // 'object' typeof {} // 'object' typeof console.log // 'function'instanceof通过原型链来判断数据类型的p1 = new Person() p1 instanceof Person // trueObject.prototype.toString.call()可以检测所有的数据类型,算是一个比较完美的方法了。var obj={} var arr=[] console.log(Object.prototype.toString.call(obj)) //[object Object] console.log(Object.prototype.toString.call(arr)) //[object Array]52、知道Array对象的哪些方法?其中 push/pop/shift/unshift 初级考的最多。不改变array的方法indexOf() 和 lastIndexOf()indexof() : 返回元素在数组的第一次出现的索引,从0开始。若数组不存在该元素,则返回-1。var arr = [1, 2, 2]; arr.indexOf(1); //0 arr.indexOf(10); //-1lastIndexOf(): 返回元素在数组最后一次出现的索引,如果没有出现则返回-1.var arr = [1, 2, 2]; arr.lastIndexOf(2); //2 arr.lastIndexOf(10); //-1slice()方法与字符串的substring()方法一样,截取数组的一部分,返回一个新的数组。slice(start)索引从start开始截取var arr = [1, 2, 2, 5, 6]; arr.slice(2) // [2, 5, 6]slice(start,end)索引从start开始到索引end结束。通常,接受2个参数作为一个左闭右开区间,即包括开始索引位置的元素,但不包括结束索引位置的元素。var arr = [1, 2, 2, 5, 6]; arr.slice(1,3) // [2, 2]slice()没有参数,则是复制整个数组。var arr = [1, 2, 2, 5, 6]; arr.slice();concat():合并数组。把当前的数组和另一个数组连接起来,并返回一个新的数组。方法的参数可以有多个,也可以任意任意类型,数值、字符串、布尔值、数组、对象都可以,参数会被被添加到新的数组中。var arr1 = [1, 2, 3,4,5,6]; var arr2 = ['a','b','c']; var arr3 = arr1.concat(arr2); arr3; //[1, 2, 3, 4, 5, 6, "a", "b", "c"]注意,如果参数是数组, 会被拉平一次,即数组会被拆开来,加入到新的数组中。具体看示例:var arr1 = [1, 2, 3]; var arr2 = arr1.concat(66,'abc',true,[10,20],[30,[31,32]],{x:100}); arr2; //[1, 2, 3, 66, "abc", true, 10, 20, 30, [31,32], {x:100}]join(): 转成字符串。它会把当前Array的每个元素都用指定的字符串连接起来,然后返回连接后的字符串。参数是用来指定连接的字符串。见示例代码:var arr = [1, 2, 3]; arr.join('*') //"1*2*3"如果没有指定参数,默认是用 "," 连接。var arr = [1, 2, 3]; arr.join() //"1,2,3"toString(): 返回数组的字符串形式var arr = [1, 2, 3]; arr.toString() // "1,2,3" map():对数组的所有成员依次调用一个函数,返回值是一个新数组。arr.map(function(elem, index, arr) { return elem * index; }); //[0, 2, 6]map方法接受一个函数作为参数,该函数调用时,map方法会将其传入3个参数,分别是当前成员、当前位置和数组本身(后2个参数可选)。arr.map(function(elem, index, arr) { return elem * index; }); //[0, 2, 6]map方法还可以接受第2个参数,表示回调函数执行时this所指向的对象。forEach():与map方法很相似,也是遍历数组的所有成员,执行某种操作。注意:forEach方法一般没有返回值var arr = [1, 2, 3]; function log(element, index, array) { console.log('[' + index + '] = ' + element); } arr.forEach(log); // [0] = 1 // [1] = 2 // [2] = 3filter(): 删选var arr = [1, 2, 3, 4, 5]; arr.filter(function (elem, index, arr) { return index % 2 === 1; }); //[2, 4]some()和every()类似“断言”(assert),用来判断数组成员是否符合某种条件。接受一个函数作为参数,所有数组成员依次执行该函数,返回一个布尔值。该函数接受三个参数,依次是当前位置的成员、当前位置的序号和整个数组。some方法是只要有一个数组成员的返回值是true,则整个some方法的返回值就是true,否则false。var arr = [1, 2, 3, 4]; arr.some(function (elem, index, arr) { return elem >= 3; }); // trueevery方法则是所有数组成员的返回值都是true,才返回true,否则false。var arr = [1, 2, 3, 4]; arr.every(function (elem, index, arr) { return elem >= 3; }); // false注意,对于空数组,some方法返回false,every方法返回truereduce()和reduceRight():依次处理数组的每个成员,最终累计为一个值。reduce是从左到右处理(从第一个成员到最后一个成员)arr = [1, 2, 3] arr.reduce(function(x, y){ console.log(x, y) return x + y; }); // 1 2 // 3 3 // 6reduceRight则是从右到左处理(从最后一个成员到第一个成员)arr.reduceRight(function(x, y){ console.log(x, y) return x + y; }); // 3 2 // 5 1 // 6改变原数组的方法push():向数组的末尾添加若干元素。返回值是改变后的数组长度。var arr = [1, 2]; arr.push(3) ;// 3 arr; // [1, 2, 3] arr.push('b','c'); //5 arr; //[1, 2, 3, "b", "c"] arr.push([10,20]); //6 arr; //[1, 2, 3, "b", "c", [10,20]]pop()删除数组最后一个元素。返回值是删除的元素。var arr =[1, 2, 3, "b", "c", [10,20]]; arr.pop(); //[10, 20] arr; // [1, 2, 3, "b", "c"]unshift()向数组头部添加若干元素。返回值是改变后的数组长度。var arr = [1, 2]; arr.unshift(3,4 ); //4 arr; // [3, 4, 1, 2]shift()删除数组第一个元素。返回值是删除的元素var arr = ['a', 'b', 1, 2]; arr.shift(); //'a' arr; //['b', 1, 2]sort()数组排序。默认是将所有元素转换成字符串,再按字符串Unicode码点排序。返回值是新的数组。var arr = [1, 2, 12, 'a', 'b', 'ab', 'A', 'B'] arr.sort(); //[1, 12, 2, "A", "B", "a", "ab", "b"] 注意:12排在了2的前面如果元素都是数字,要按从小到大排序,可以传入一个回调函数作为参数。var arr = [1, 2, 12, 100] arr.sort(function(a,b){ return a-b; }); // [1, 2, 12, 100]reverse():颠倒数组中元素的位置var arr = [1, 2, 12, 'a', 'b', 'ab', 'A', 'B']; arr.reverse(); //["B", "A", "ab", "b", "a", 12, 2, 1]array.splice()array.splice(start[, deleteCount[, item1[, item2[, ...]]]])参数:start 为开始的索引,deletecount 表示要移除的数组元素的个数。item 为要添加进数组的元素如果 deleteCount 大于 start 之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。如果 deleteCount 被省略了,或者它的值大于等于array.length - start(也 + 就是说,如果它大于或者等于start之后的所有元素的数量),那么start之后数组的所有元素都会被删除。如果 deleteCount 是 0 或者负数,则不移除元素。这种情况下,至少应添加一个新元素只删除,不添加。可以传入2个参数:var arr = ['Alibaba', 'Tencent', 'Baidu', 'XiaoMi', '360']; // 从索引2开始删除3个元素 arr.splice(2, 3); // 返回删除的元素 ['Baidu', 'XiaoMi', '360'] arr; // ['Alibaba', 'Tencent'] 只添加,不删除。第2个参数设为0,即不删除元素。arr.splice(2, 0, 'Toutiao', 'Meituan', 'Didi'); // 返回[],因为没有删除任何元素 arr; //["Alibaba", "Tencent", "Toutiao", "Meituan", "Didi"]先删除若干元素,然后在删除的位置上在添加若干个元素。var arr =["Alibaba", "Tencent", "Toutiao", "Meituan", "Didi"] arr.splice(2,2,'Apple','Google'); //["Toutiao", "Meituan"] arr; //["Alibaba", "Tencent", "Apple", "Google", "Didi"]53、JS如何实现一个类构造函数法 (缺点:用到了 this 和 prototype,编写复杂,可读性差)function P(name, age){ this.name = name; this.age= age; } P.prototype.sal= function(){ } var pel= new P("jj", 1); pel.sell()ES6 语法糖 classclass Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } } var point = new Point(2, 3);54、聊聊对js原型链的理解?一句话解析什么是原型链:遍历一个实列的属性时,先遍历实列对象上的属性,再遍历它的原型对象,一直遍历到Object任何一个类(函数)都有原型对象,原型对象至少有两个属性(constructor,proto)。constructor指向函数本身,proto指向父类原型对象。函数上有一个prototype属性,指向原型对象,通过它可以访问原型对象函数的实列可以直接访问原型对象(因为实列上有proto指向构造函数的原型对象)function Dog(){} //类 var obj=new Dog(); //实列 obj.name='沪江'; Dog.prototype.name="旺财"; Dog.prototype.eat=function(){ console.log(this.name); }; console.log(Dog.prototype.name); //旺财 console.log(obj.prototype); //undefined,prototype是类上才有的,实列上没有 obj.eat(); //沪江(先遍历实列对象上的属性,再遍历它的原型对象)55、变量声明提升?在 JavaScript 中,函数声明(function aa(){})与变量声明(var)经常被 JavaScript 引擎隐式地提升到当前作用域的顶部。函数声明的优先级高于变量,如果变量名跟函数名相同且未赋值,则函数声明会覆盖变量声明声明语句中的赋值部分并不会被提升,只有变量的名称被提升56、作用域链?因为函数的嵌套形成作用域的层级关系。当函数执行时,从当前作用域开始搜,没有找到的变量,会向上层作用域查找,直至全局函数,这就是作用域链。在 JavaScript 中,作用域为 function(){}内的区域,称为函数作用域。全局函数无法查看局部函数的内部细节,但局部函数可以查看其上层的函数细节,直至全局细节57、作用域与执行上下文的区别作用域分全局作用域和函数作用域,由于js没有块级作用域(es6里规定了块级作用域,详情可自行查看),函数作用域可以用于隔离变量,不同作用域下同名变量不会有冲突的。作用域只是一个“地盘”,作用域是一个抽象的概念,其中没有变量。要通过作用域对应的执行上下文环境来获取变量的值。作用域中变量的值是在执行过程中产生的确定的,而作用域却是在函数创建时就确定了。执行全局代码时,会产生一个执行上下文环境,每次调用函数都又会产生执行上下文环境。当函数调用完成时,这个上下文环境以及其中的数据都会被消除(当然了闭包并不会乖乖就范),处于活动状态的执行上下文环境只有一个。58、对象深拷贝、浅拷贝对象浅拷贝是共用一个引用,因此更改新拷贝的对象时,也会更改原来的对象对象深拷贝是两个引用,有以下几种方式实现深拷贝: //使用 Object.assign,只能实现第一层属性的深拷贝 let clone = Object.assign({},obj) //使用 slice,如果数组中有引用类型的元素的话,只能实现第一层的深拷贝 let clone = arr.slice(0); //使用 concat,同 slice let clone = [].concat(arr); //使用 JSON 对象,无法实现属性值为 function 和 undefined 的拷贝,并且拷贝从原型链继承的值也会有问题,比如 constructor 的值变成了 Object function deepClone(obj) { let _obj = JSON.stringify(obj); let clone = JSON.parse(_obj); return clone; } //使用递归,在不使用库的情况下,这种方式可以实现真正的深层度的拷贝 function deepClone(obj) { let clone = Array.isArray(obj) ? [] : {}; if(obj && typeof obj === 'object') { for(let key in obj) { if(obj.hasOwnProperty(key) { if(obj[key] && typeof obj[key] === 'object') { clone[key] = deepClone(obj[key]); }else { clone[key] = obj[key]; } } } } return clone; } //通过 JQuery 的 extend 方法 //使用 lodash 函数库 在使用 console.log 这类方法输出对象时会显示内存的最新状态,在同一个 tick 中,即便更改对象是在 console.log 之后,那么输出的对象也是被更改过的对象,因此,如果想输出某个时刻的对象值时,应该进行深拷贝进行输出。59、for-in 和 for-of 的区别:1、for-in 遍历的总是对象的下标,因此如果给数组增加属性,那么这个属性(key)也会遍历出来,更适合遍历对象,遍历顺序可能不是按照内部顺序,通常配合 hadOwnProperty() 方法一起使用;2、for-of 就是迭代器,遍历的是数组元素的值,不会遍历增加的属性,是按照内部顺序遍历的,并且还可以遍历 Map 和 Set 数据结构。如果没有在内部使用 let 那么默认为 var60、图片懒加载、预加载图片懒加载:是为了降低一次性的 HTTP 请求数量,当图片很多时,或者同时在线人数较多时,图片懒加载可以起到很好的性能优化的作用。 实现步骤:设置自定义属性 data-src 来存储图片资源;页面初始化或者在滚动时判断图片是否出现在可视区域;在可视区域的话,将自定义属性 data-src 的值赋值给 src 属性。图片预加载:在需要显示图片之前,就加载完毕,当需要显示图片时,就从缓存中取图片,在图片不是特别多的时候,可以使用预加载。61、函数式编程函数式编程中的函数指的数学概念中的函数,即自变量的映射,得到的结果由输入的值决定,不依赖于其他状态,是声明式(依赖于表达式),而非命令式,组合纯函数来构建软件的编程方式。62、this 关键字在全局环境中,this 指向 window 对象,ES5 函数中,this 对象是在运行时基于函数的执行环境(变量对象,如全局是 window),匿名函数的执行环境具有全局性,因此其 this 对象通常指向 window(在非严格模式下),在严格模式下 this 指向的是 undefined,为了在严格模式下,this 重新指向 window,可以使用非直接调用 eval 的方式,如 (0, eval)('this'),使用了逗号运算符,括号前面会返回 eval,但是和直接调用的区别就是在严格模式下 this 指向不一样。ES6 的箭头函数中,this 对象是在函数定义的执行环境。this:上下文,会根据执行环境变化而发生指向的改变.1.单独的this,指向的是window这个对象alert(this); // this -> window2.全局函数中的thisfunction demo() { alert(this); // this -> window } demo(); 在严格模式下,this是undefined.function demo() { 'use strict'; alert(this); // undefined } demo();3.函数调用的时候,前面加上new关键字所谓构造函数,就是通过这个函数生成一个新对象,这时,this就指向这个对象。function demo() { //alert(this); // this -> object this.testStr = 'this is a test'; } let a = new demo(); alert(a.testStr); // 'this is a test' 4.用call与apply的方式调用函数function demo() { alert(this); } demo.call('abc'); // abc demo.call(null); // this -> window demo.call(undefined); // this -> window5.定时器中的this,指向的是windowsetTimeout(function() { alert(this); // this -> window ,严格模式 也是指向window },500) 6.元素绑定事件,事件触发后,执行的函数中的this,指向的是当前元素window.onload = function() { let $btn = document.getElementById('btn'); $btn.onclick = function(){ alert(this); // this -> 当前触发 } } 7.函数调用时如果绑定了bind,那么函数中的this指向了bind中绑定的元素window.onload = function() { let $btn = document.getElementById('btn'); $btn.addEventListener('click',function() { alert(this); // window }.bind(window)) }8.对象中的方法,该方法被哪个对象调用了,那么方法中的this就指向该对象let name = 'finget' let obj = { name: 'FinGet', getName: function() { alert(this.name); } } obj.getName(); // FinGet //---------------------------分割线---------------------------- let fn = obj.getName; fn(); //finget this -> window62、栈和堆的区别?栈(stack):由编译器自动分配释放,存放函数的参数值,局部变量等;堆(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统释放。63、JS中的匿名函数是什么?匿名函数:就是没有函数名的函数,如:(function(x, y){ alert(x + y); })(2, 3);这里创建了一个匿名函数(在第一个括号内),第二个括号用于调用该匿名函数,并传入参数。64、什么是事件代理/事件委托?事件代理/事件委托是利用事件冒泡的特性,将本应该绑定在多个元素上的事件绑定在他们的祖先元素上,尤其在动态添加子元素的时候,可以非常方便的提高程序性能,减小内存空间。64、什么是事件冒泡?什么是事件捕获?冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。捕获型事件:事件从最不精确的对象(document 对象)开始触发,然后到最精确(也可以在窗口级别捕获事件,不过必须由开发人员特别指定)。在添加事件时用addEventListener(event,fn,useCapture)方法,基中第3个参数useCapture是一个Boolean值,用来设置事件是在事件捕获时执行,还是事件冒泡时执行。注意:IE浏览器用attachEvent()方法,此方法没有相关设置,不过IE的事件模型默认是在事件冒泡时执行的,也就是在useCapture等于false的时候执行,所以把在处理事件时把useCapture设置为false是比较安全,也实现兼容浏览器的效果。65、如何阻止事件冒泡?w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true。例如:window.event.cancelBubble = true; e.stopPropagation();66、如何阻止默认事件?方法是e.preventDefault()67、DOM 事件有哪些阶段?js事件的三个阶段分别为:捕获、目标、冒泡 1.捕获:事件由页面元素接收,逐级向下,到具体的元素 2.目标:具体的元素本身 3.冒泡:跟捕获相反,具体元素本身,逐级向上,到页面元素 事件捕获:当使用事件捕获时,父级元素先触发,子元素后触发 事件冒泡:当使用事件冒泡时,子级元素先触发,父元素后触发68、JS有哪些内置对象Object是JavaScript中所有对象的父对象数据封装对象:Object、Array、Boolean、Number和String其他对象:Function、Arguments、Math、Date、RegExp、Error69、解释jsonp的原理,以及为什么不是真正的ajax答案:动态创建script标签,回调函数Ajax是页面无刷新请求数据操作70、null和undefined的区别?null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。当声明的变量还未被初始化时,变量的默认值为undefined。 null用来表示尚未存在的对象undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:(1)变量被声明了,但没有赋值时,就等于undefined。(2)调用函数时,应该提供的参数没有提供,该参数等于undefined。(3)对象没有赋值的属性,该属性的值为undefined。(4)函数没有返回值时,默认返回undefined。null表示"没有对象",即该处不应该有值。典型用法是:(1) 作为函数的参数,表示该函数的参数不是对象。(2) 作为对象原型链的终点。71、js延迟加载的方式有哪些?defer和async、动态创建DOM方式(创建script,插入到DOM中,加载完毕后callBack)、按需异步载入js72、js如何捕获异常?try{ //这里是可能出错并尝试捕获错误的代码 doSomething(); }catch(e){ //这里处理错误,e是错误信息,比如 console.log(e) } 73、解释AJAX的工作原理?创建ajax对象(XMLHttpRequest/ActiveXObject(Microsoft.XMLHttp))判断数据传输方式(GET/POST)打开链接 open()发送 send()当ajax对象完成第四步(onreadystatechange)数据接收完成,判断http响应状态(status)200-300之间或者304(缓存)执行回调函数73、react和vue比较来说有什么区别component层面,web component和virtual dom数据绑定(vue双向,react的单向)等好多计算属性 vue 有,提供方便;而 react 不行vue 可以 watch 一个数据项;而 react 不行vue 由于提供的 direct 特别是预置的 directive 因为场景场景开发更容易;react 没有生命周期函数名太长 directive74、说一下vue实例的生命周期?new Vue() > 初始化事件和生命周期 > beforeCreate > 数据绑定 > created > 如果有el属性,则编译模板 > beforeMount > 添加$el属性,并替换掉挂载的DOM元素 > mounted > 数据更新 > beforeUpdate > 重新编译模板并渲染DOM > updated > 调用$destoryed > beforeDestory > 销毁vue实例 > destroyed75、vue双向数据绑定的原理是什么首先传输对象的双向数据绑定 Object.defineProperty(target, key, decription),在decription中设置get和set属性(此时应注意description中get和set不能与描述属性共存)数组的实现与对象不同。同时运用观察者模式实现wather,用户数据和view视图的更新76、new操作符具体干了什么呢?1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。2、属性和方法被加入到 this 引用的对象中。3、新创建的对象由 this 所引用,并且最后隐式的返回 this 。77、如何防止出现中文乱码?<meta charset="UTF-8"/>78、DOM和BOM分别是什么?浏览器的javascript的组成包含:ECMAScript (核心):描述了 JS 的语法 和 基本对象。文档对象模型 (DOM):处理 网页内容 的方法和接口。浏览器对象模型 (BOM):与 浏览器交互 的方法和接口。区别:DOM 是 W3C 的标准; [所有浏览器公共遵守的标准]BOM 是 各个浏览器厂商根据 DOM在各自浏览器上的实现;[表现为不同浏览器定义有差别,实现方式不同]window 是 BOM 对象,而非 js 对象;javacsript是通过访问BOM(Browser Object Model)对象来访问、控制、修改客户端(浏览器)DOM 的 API :节点创建型 API:document.createElement(),document.createTextNode(),parent.cloneNode(true)document.createDocumentFragment() 创建文档片段,解决大量添加节点造成的回流问题页面修改型 API:parent.appendChild(child),parent.removeChild(child)parent.replcaeChild(newChild,oldChild)parent.insertBefore(newNode, referenceNode)节点查询型 API:document.getElementById()document.getElementsByTagName() 返回即时的 HTMLCollection 类型document.getElementsByName() 根据指定的 name 属性获取元素,返回即时的 NodeListdocument.getElementsByClassName() 返回即时的 HTMLCollectiondocument.querySelector() 获取匹配到的第一个元素,采用的是深度优先搜索docuemnt.querySelectorAll() 返回非即时的 NodeList,也就是说结果不会随着文档树的变化而变化节点关系型 API:父关系型:node.parentNode()兄弟关系型:node.previouSibling() 返回节点的前一个节点(包括元素节点,文本节点,注释节点)node.previousElementSibling() 返回前一个元素节点node.nextSibling() 返回下一个节点node.nextElementSibling() 返回下一个元素节点子关系型parent.childNodes() 返回一个即时的NodeList,包括了文本节点和注释节点parent.children() 一个即时的HTMLCollection,子节点都是Elementparent.firsrtNode(),parent.lastNode(),hasChildNodes()元素属性型 API:element.setAttribute(“name”,“value”) 为元素添加属性element.getAtrribute(“name”) 获取元素的属性元素样式型 API:window.getComputedStyle(element) 返回一个CSSStyleDeclaration,可以从中访问元素的任意样式属性。element.getBoundingClientRect() 返回一个DOMRect对象,里面 包括了元素相对于可视区的位置 top,left,以及元素的大小,单位为纯数字。可用于判断某元素是否出现在了可视区域BOM的 API :location对象.href、.search、.hash、.port、.hostname、pathnamehistory对象.go(n)(前进或后退指定的页面数)、history.back(后退一页)、.forward(前进一页)navigator对象navigator:包含了用户浏览器的信息navigator.userAgent:返回用户代理头的字符串表示(就是包括浏览器版本信息等的字符串)navigator.cookieEnabled:返回浏览器是否支持(启用) cookiewindow对象方法:alert() — 显示带有一段消息和一个确认按钮的警告弹出框。confirm() — 显示带有一段消息以及确认按钮和取消按钮的警告弹出框。prompt() — 显示带有一段消息以及可提示用户输入的对话框和确认,取消的警告弹出框。open() — 打开一个新的浏览器窗口或查找一个已命名的窗口。close() — 关闭浏览器窗口。setInterval() — 按照指定的周期(以毫秒计)来调用函数或计算表达式。每隔多长时间执行一下这个函数clearInterval() — 取消由 setInterval() 设置的 timeout。setTimeout() — 在指定的毫秒数后调用函数或计算表达式。clearTimeout() — 取消由 setTimeout() 方法设置的 timeout。scrollTo() — 把内容滚动到指定的坐标。79、介绍下递归在JavaScript程序中,函数直接或间接调用自己。通过某个条件判断跳出结构,有了跳出才有结果。递归的步骤(技巧)1、假设递归函数已经写好2、寻找递推关系3、将递推关系的结构转换为递归体4、将临界条件加入到递归体中(一定要加临界条件,某则陷入死循环,内存泄漏)例子(求1-100的和): //普通循环写法 var sum = 0; for(var i=1; i<=100; i++){ sum += i; } console.log(sum); // 5050 //递归写法 function sum(n){ if(n==1) return 1; return sum(n-1) + n; } var amount = sum(100); console.log(amount); // 505081、JS的垃圾回收机制JS 具有自动垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存,所需内存的分配以及无用内存的回收完全实现了自动管理。垃圾收集机制的原理:找到那些不再继续使用的变量,然后释放其占用的内存。垃圾收集机制会按照固定的时间间隔周期性地执行这一操作。垃圾收集机制必须跟踪哪个变量有用哪个变量无用,对于不再有用的变量打上标记,以备将来收回其占用的内存。JS 中最常用的跟踪方法是标记清除,当函数执行完后,就会给局部变量打上“离开环境”的标记(除了闭包),在下一次垃圾回收时间到来时就会清除这一块内存,手动将一个有值的变量赋值为 null,也是让这个值离开环境,也可以释放内存。还有一种跟踪方法是引用计数,这会引起循环引用的问题,但现在所有的浏览器都使用了标记清除式的垃圾回收机制,所以不用考虑这个问题了。82、什么是MVVM? MVC? MVP?mvc 的是 model view controller 的缩写,一种通过业务逻辑、数据、界面显示分离的方法进行代码组织的方法;其中 M 层处理数据、业务逻辑;v 层处理界面的显示结果;c 层起到桥梁的作用,来控制 v 层 和 M 层通信,以此达到分离视图显示和业务逻辑层;mvp 是从 mvc 演化而来的,与 mvc 有一定的相似性, p 即 presenter 作为view 和 model 交互的桥梁纽带,处理与用户交互的逻辑;v 即 view 负责绘制 dom 元素、以及与用户的交互;model 负责存储、检索、操作数据;mvp 和 mvc 的区别主要是:view 和 model 并不直接交互,而是通过与 presenter 交互来实现与 model 间接的交互;而在 mvc 中 view 和 model 是可以直接进行交互的;在 mvp 中,通常 view 和 presenter 是一对一的,但是复杂的 view 可能绑定多个 presenter 来处理逻辑;而在 mvc 中,controller 是基于行为层次的,并且可以被多个 view 共享,controller 可以负责决定显示那个 view;prresenter 与 view 的交互是通过接口来进行的;mvp 的缺点就是增加了很多的接口和实现类,代码逻辑虽然清晰,但是代码量会比较大;mvvm 是 mvp 的升级,其中 VM 是 viewModel 的缩写,可以理解成是 presenter和 view 的结合;viewModel 和 view 之间的交互不在是依赖于接口,而是通过 Data Binding 完成,而 Data Binding 可以实现双向的交互,从而使得视图和控制层之间的耦合度进一步的降低,分离更为彻底,同时减轻了 activity 的压力;83、知道哪些主流前端框架React、Vue、Angular、Antd、Element84、在前端中什么是组件化 什么是模块化组件化和模块化的价值都在于分治,web应用系统的复杂度不断提升,兼顾开发效率和产品实际运行效率,会在开发阶段运用组件化和模块化的手段分离关注点,结合构建工具合理打包。组件化更多关注的是UI部分,你看到的一个管理界面的弹出框,头部,内容区,确认按钮和页脚都可以是个组件,这些组件可以组成一个弹出框组件,跟其他组件组合又是一个新的组件。模块化侧重于功能或者数据的封装,一组相关的组件可以定义成一个模块,一个暴露了通用验证方法的对象可以定义成一个模块,一个全局的json配置文件也可以定义成一个模块。封装隔离来后,更重要的是解决模块间的依赖关系。babel作为现在最火的es6转换器,用babelify或者webpack的babel loader再或者基于task的构建系统插件都可以很方便用起来es6 modules85、介绍一下你对浏览器内核的理解主要分成两部分:渲染引擎(layout engineer或Rendering Engine)和 JS 引擎。渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。所有网页浏览器、电子邮件客户以及其他它所需要编辑、显示网络的应用程序都需要内核。JS引擎:解析和执行JavaScript 来实现网页的动态效果;最开始渲染引擎和 JS 并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只渲染引擎。86、浏览器页面渲染过程浏览器渲染页面的一般过程:浏览器解析html源码,然后创建一个 DOM树。并行请求 css/image/js在DOM树中,每一个HTML标签都有一个对应的节点,并且每一个文本也都会有一个对应的文本节点。DOM树的根节点就是 documentElement,对应的是html标签。浏览器解析CSS代码,计算出最终的样式数据。构建CSSOM树。对CSS代码中非法的语法它会直接忽略掉。解析CSS的时候会按照如下顺序来定义优先级:浏览器默认设置 < 用户设置 < 外链样式 < 内联样式 < html中的style。DOM Tree + CSSOM --> 渲染树(rendering tree)。渲染树和DOM树有点像,但是是有区别的。DOM树完全和html标签一一对应,但是渲染树会忽略掉不需要渲染的元素,比如head、display:none的元素等。而且一大段文本中的每一个行在渲染树中都是独立的一个节点。渲染树中的每一个节点都存储有对应的css属性。一旦渲染树创建好了,浏览器就可以根据渲染树直接把页面绘制到屏幕上。以上四个步骤并不是一次性顺序完成的。如果DOM或者CSSOM被修改,以上过程会被重复执行。实际上,CSS和JavaScript往往会多次修改DOM或者CSSOM。87、重排和重绘部分渲染树(或者整个渲染树)需要重新分析并且节点尺寸需要重新计算。这被称为重排。注意这里至少会有一次重排-初始化页面布局。由于节点的几何属性发生改变或者由于样式发生改变,例如改变元素背景色时,屏幕上的部分内容需要更新。这样的更新被称为重绘。88、什么情况会触发重排和重绘添加、删除、更新 DOM 节点通过 display: none 隐藏一个 DOM 节点-触发重排和重绘通过 visibility: hidden 隐藏一个 DOM 节点-只触发重绘,因为没有几何变化移动或者给页面中的 DOM 节点添加动画添加一个样式表,调整样式属性用户行为,例如调整窗口大小,改变字号,或者滚动。89、在浏览器中输入URL到整个页面显示在用户面前时这个过程中到底发生了什么DNS解析地址TCP连接发送HTTP请求服务器处理请求并返回HTTP报文浏览器解析渲染页面连接结束90、cookies,sessionStorage 和 localStorage 的区别sessionStorage 和 localStorage两者存储空间一般都在5M左右,sessionStorage在会话结束时会主动清除,localstorage则不会,需手动清除两者都有同源策略限制,跨域无法访问,sessionStorage有同标签页限制数据仅在客户端存储,不参与和服务器通信都是key value形式进行存储,value必须为字符串,如不是则自动转换成字符串,value如果是对象,需转换成JSON字符串操作方法一直,setItem(key, value)增/改、removeItem(key)删、getItem(key)查、localStorage.clear()/sessionStorage.clear()清空cookies存储大小为4k,一个站点最多20个cookies会通过http请求参与服务端的通信cookie可以设定会话时间,如不设置,则默认浏览器窗口关闭清除Cookie设置中有个HttpOnly参数,前端浏览器使用document.cookie是读取不到HttpOnly类型的Cookie的91、为什么会有同源策略同源策略限制从一个源加载的文档或脚本如何与另一个源的资源进行交互。这是用于隔离潜在恶意文件的关键安全机制。同源策略:协议相同、域名相同、端口相同,三者都必须相同什么叫限制:不同源的文档不能操作另一个源的文档,在以下几个方面操作不了:1)Cookie、localStorage、indexDB 无法读取2)DOM 无法获得3)AJAX 请求无法发送92、HTTP有哪些请求方法?HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。OPTIONS返回服务器针对特定资源所支持的HTTP请求方法,也可以利用向web服务器发送‘*’的请求来测试服务器的功能性HEAD向服务器索与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以再不必传输整个响应内容的情况下,就可以获取包含在响应小消息头中的元信息。GET向特定的资源发出请求。注意:GET方法不应当被用于产生“副作用”的操作中,例如在Web Application中,其中一个原因是GET可能会被网络蜘蛛等随意访问。Loadrunner中对应get请求函数:web_link和web_urlPOST向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 Loadrunner中对应POST请求函数:web_submit_data,web_submit_formPUT向指定资源位置上传其最新内容DELETE请求服务器删除Request-URL所标识的资源TRACE回显服务器收到的请求,主要用于测试或诊断CONNECT93、HTTP get和post方法的区别?1、GET请求,请求的数据会附加在URL之后,以?分割URL和传输数据,多个参数用&连接。URL的编码格式采用的是ASCII编码,而不是uniclde,即是说所有的非ASCII字符都要编码之后再传输。POST请求:POST请求会把请求的数据放置在HTTP请求包的包体中。上面的item=bandsaw就是实际的传输数据。因此,GET请求的数据会暴露在地址栏中,而POST请求则不会。2、传输数据的大小在HTTP规范中,没有对URL的长度和传输的数据大小进行限制。但是在实际开发过程中,对于GET,特定的浏览器和服务器对URL的长度有限制。因此,在使用GET请求时,传输数据会受到URL长度的限制。对于POST,由于不是URL传值,理论上是不会受限制的,但是实际上各个服务器会规定对POST提交数据大小进行限制,Apache、IIS都有各自的配置。3、安全性POST的安全性比GET的高。这里的安全是指真正的安全,而不同于上面GET提到的安全方法中的安全,上面提到的安全仅仅是不修改服务器的数据。比如,在进行登录操作,通过GET请求,用户名和密码都会暴露再URL上,因为登录页面有可能被浏览器缓存以及其他人查看浏览器的历史记录的原因,此时的用户名和密码就很容易被他人拿到了。除此之外,GET请求提交的数据还可能会造成Cross-site request frogery攻击94、http状态码100-199:成功接收请求,但需要进行下一步请求200-299:成功接收请求,并完成整个处理过程300-399:为完成全部请求,客户需近一步细化需求400-499:客户端请求有错误,包括语法错误或不能正常执行500-599:服务器端出现错误95、http与https有什么区别?HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。HTTPS和HTTP的区别主要如下:https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。96、你常用的开发工具是什么,为什么?vscode/chrome等;97、说说最近最流行的一些东西吧?常去哪些网站?Node.js、MVVM、Flutter、WebAssembly、Vue、Uni-app、React-native、Angular、Weex等CSDN,Segmentfault,博客园,掘金,简书,Stackoverflow,伯乐在线,阮一峰的网络日志等98、聊聊你的前端职业规划推荐大家看看这篇文章:写给前端应届生的职业规划建议99、你如何看待加班?这是一道半开放题. 没有准确答案,也不建议大家太主观地回答, 类似"加班是一种态度,不加班是一种能力,能力不够时就要展现我的态度!”算是不错的答案."结合公司实际情况, 建议:表现出自己过硬的工作实力,尽力避免由于自身问题导致被动型加班。表现出自己谦虚的学习态度,愿意牺牲自己的一部分个人时间提升个人能力,以便日后更好工作。表现出对公司和岗位的个人认识,通过面试前的准备,了解到求职岗位是否需要经常性加班,并表明是否接受。表现出自己较高的效率意识,拒绝形式主义的加班和空耗时间。此条有风险视情况而定,如果在民营企业或是工作较为紧张的单位,可以这样讲,说不定会加分;如果在事业单位或是公务员,最好就不要提及啦。根据个人情况的不同,表明个人对加班的其他看法。最后也考虑(抖机灵)地考虑一下反问面试官,自己有哪里没有涉及到,或者还有哪些需要加班的场景呢?100、面试官问“你还有什么问题”,应该怎么回答开放问题, 最好不要回答"没有了"之类的话, 怎么回答也看情况看个人, 具体可以参考: 在面试的时候,快到最后了,技术面试官问你有什么要问他的吗,这时候应该怎么回答啊?
文章
Web App开发  ·  存储  ·  前端开发  ·  JavaScript  ·  安全  ·  搜索推荐  ·  机器人  ·  Go  ·  API  ·  索引
2023-01-30
25 PostgreSQL 数据库安全认证 | 学习笔记
开发者学堂课程【PostgreSQL 快速入门:25 PostgreSQL 数据库安全认证】学习笔记,与课程紧密连接,让用户快速学习知识。课程地址:https://developer.aliyun.com/learning/course/16/detail/8425 PostgreSQL 数据库安全认证内容介绍:一、数据库认证二、基于角色的权限管理三、事件触发器四、数据传输加密一、数据库认证数据库认证和认证相关的配置文件为pg_hba.conf-METHOD,该文件使用次数非常高。位于 d SPGDATA下方的cat pg_hba.conf,cat pg_hba.conf的格式为:第一字段TYPE表示连接类型,是通过本地的Unix socket连接,或者是host的TCBIP socket(127.0.0.1/321)连接。host是允许非SSL连接或者SSL连接,如果是hostssl连接,表示是强制指定,代码必须是SSL进行匹配;host no ssl表示强制不加密,数据传输强制不加密的连接。第二字段DATABASE表示数据库名,第三字段USER表示用户名,第四字段ADDRESS表示连接的应用程序服务器的IP地址。METHOD表示认证的方法,既是trust认证,md5认证还是其他Idap,pan,peer的认证。第四字段ADDRESS支持一个网站,可以写地址可以写野码,可以写reject,reject表示不允许。因有黑名单和白名单,现阶段写的是白名单,如果不在其中都是不允许连接,如果写黑名单就是reject。1、认证类型(pg.hba.conf-TYPE)认证类型:unix socket,host,hostssl,hostnossl;(host支持hostssl和hostnossl两种模式),ssl表示数据传输过程必须是加密的,包括认证过程也加密。也表示无论在网络使用明文密码进行数据传输都会是加密的。2、认证方法(pg_hba.conf-METHOD)trust--无需密码reject--拒绝认证,假设写的代码刚好匹配,就拒绝连接。md5--数据传输过程密码是加密的password—数据传输过程中密码是明文传输的,仅仅当认证类型为SSL,密码就会被全部加密。其他的认证方法GEEAPI,SSPI使用次数不多,都是使用其他的认证方法。如果整个环境中都是配置ldap服务认证,cost great也会支持,或者是radius服务认证。3、密码认证过程中的安全注意事项在密码认证传输过程中,不要使用password认证方法,因为这种方法是明文传输。密码认证过程中使用md5认证,因在传输过程中被截获,只是md5加short,一个随机产生的数据,为二次md5表示的一个值,要破解也是比较困难。密码认证过程中可能遭到暴力破解,类DDoS攻击。假如体育网里面有一个攻击者,攻击者可以不停的尝试密码,进行连接,暴力破解。加入auth-delay第三方插件进行防范,auth-delay表示当密码错误,不会立刻显示错误,延迟一秒钟,才会显示密码错误。要进行暴力破解,时间就会被拉长,就不会进行暴力破解和类DDoS攻击。连续输入十次,锁定用户。在cost great原来版本中作为没有这方面的支持,可能有第三方插件支持,可进行查找。4、pg_hba.conf的鉴权尽量将权限限制到最小,假设只有某一台服务器通过用户连接数据库,尽量避免开放所有用户,所有数据库,允许所有ID进行连接,尽量不要将范围扩大。可能会带来安全隐患,可能会导致外面网站有攻击者。前面所表示的都是一个认证过程。二、基于角色的权限管理基于角色的权限管理表示所有的对象权限都与角色挂钩。假设通过A用户连接,A用户有无访问对象的权限,需查看对象有没有将权限赋予给A用户。对象的控制级别:1、表级别权限控制假设整个SCHEMA都要赋予给某个用户,将会支持ALL TABLEA IN SCHEMA语法,表示在SCHEMA下所有表的权限都可以给某一用户或者PUBLIC,PUBLIC表示公用的意思。所有用户连接上后,都会先继承PUBLIC权限。2、列级别可以控制表假设做查询,查询A列时,赋予SELECT权限,可以允许查询。但查询B列没有给予权限就会报错,。假设UPDATE某一列,可以允许某些用户使用UPDATE列,有些用户不能进行UPDATE,所以这块权限控制做得很精细。如果没有权限控制,必须创建视图,或者某些操作隐藏权限。ALL cost没有列级别。3、序列权限控制查询序列权限时,只允许获得自己的序列,获得序列当前配置的最大值,但是不能使用该配置。假设取next vary时不允许,只有赋予UPDATE权限或者USAGE权限时,才会允许取序列的值。4、数据库权限控制数据库连接,允许连接或者在数据库中创建或者创建CREATE。5、域的权限控制相当于简单的数据类型,假设inter型创建一个域,指定inter类型是1到1000范围内,定义域。域就是一个类型,域允许使用或者是只有一个使用权限。6、ALL相当于USAGE。7、FDW权限控制对于外部数据,GRANT权限,这种权限默认超级用户才会拥有。普通用户要使用必须要赋予该权限。8、FS权限控制也是相当于外部数据访问的情形。9、函数权限控制函数就是执行权限,函数的创建权限与函数的语言有关,假设创建C语言的函数,有无创建该函数的权限,首先让该语言拥有USAGE权限。大对象有查询大对象,或者更新大对象,两中权限。10、SCHEMA权限控制可在SCHEMA中创建数据,给予CREATE权限,假设只是SCHEMA需查询,没有区分查询和创建,就创建USAGE。11、表空间的权限控制表空间的权限控制表示是否能在表空间中创建数据,必须要赋予CREATE权限。12、数据类型的权限控制数据类型的权限与SCHEMA权限类似。13、角色权限控制假设,某一角色其中的权限,当某一的角色的其中权限另一角色需使用,直接把角色赋予给另一角色。进而,该角色就能继承该权限。例子:在数据库中,在创建数据库和表空间时,数据库和表空间的owner需指定,假设将owner指定给一个普通用户,普通用户就能删除对象,假设在创建数据库时,将数据库指定给A用户,A用户就能drop数据库,所以一般在创建数据库和创建表空间时都是给予超级用户,在将数据库和表空间的权限给予普通用户,普通用户就不能进行drop database和 drop tablespace 操作,这种操作比较危险。14、对于schema也是一样尽量使用超级用户创建,将权限赋予给普通用户,对于比较大的数据类型,表空间,数据库,尽量使用超级用户创建,不使用普通用户去创建。对于PUBLIC默认的SCHEMA,因默认时是有PUBLIC SCHEMA存在的,默认就会将权限赋予给PUBLIC角色,总的说就是公有。创建完数据库后,只要用户能连接上,连接上后就能在SCHEMA PUBLIC创建对象,可以将PUBLIC从PUBLIC里回收,回收后普通用户就不能进行创建,或者连接数据库。默认完权限后就会将连接权限赋予给PUBLIC,数据库中就会默认PUBLIC SCHEMA,总的来说,一个数据库创建好后,普通用户可以连接,可以建表,删除表。三、事件触发器假设在执行 DDL,在执行DDL前可以出发该事件,或者在执行ddl_command_end时触发事件,这都是包含于一个事物里面。在结束时,有异常,那前面有DDL也会回滚。支持的语法为:ON event 表示事件,事件只有两种,一种是DDL命令开始时,另一种是DDL命令结束时。[WHEN filter_variable IN]表示一个事件,假设,其中含有trigger,目前来说,只支持trigger,filter_value是一个什么类型的 trigger。查看支持哪种 filter_value。支持ALTER AGGREGATE,CREATE AGGREGATE,CREATE CAST, CREATE DCMATN,CREATE INDEX。几乎都是 DDL 语句,SELETE INTO也是DDL语句。用 SELETE INTO 创建新表,DROP SCMENA,DROP SEQUEMCE。通过这种事件可以限制某些用户不能创建数据库或者某些用户不能在SCHEMA下创建表。观察例子9.3:在同一事件上创建多个事件触发器,触发器被触发顺序与触发名字有关,与触发器函数名字无关。是与 TRIGGER b有关,创建的两个触发器是触发A的TRIGGER函数,叫做 etge2,再触发 etge1。可以看到etge2先触发,etge1后触发。该函数语法简单,可用 plpgsql,或者sql去写都可以使用。只要返回类型是event_trigger 类型。数据库中有哪些事件触发器可通过pg_event_trigger进行查找,假设,创建两个事件触发器,对应的触发器函数和定义即可进行查找,利用其来创建安全限制。假设创建事件触发器函数,结果出现异常,显示是什么事件,执行什么命令,进行 sbort。将事件触发器创建到 ddl_command_end事件触发器,执行完ddl触发事件后就会触发函数,报出异常。就会使创建表时出现异常,不允许创建该表。就会限制整个库中不能执行 ddl。当执行ddl时,将事件触发器关掉,再去执行ddl,起到保护作用。特别是当数据库遭到攻击时,上来后也不能执行ddl语句。更精细的控制就是在函数里加入一些判断,假设,数据库中禁止postgres用户在数据库digoal中执行CREATE TABLE和DROP TABLE命令。在创建触发器函数中去限制,先判断curreat_user是否是postgres,如果是,就会出现异常。如果不是直接返回。事件触发器在创建完后,取postgreSQL中的CREATE TABLE,DSOP TABLE,将这两值放入,当事件被触发时,调用adert函数。假设,使用poetgres用户连接上连接,现删除或者创建一个表,出现报错。报错ddl_command_start或者是command CREATE TABLE,不允许CREATE TABLE,其他用户在其中建表不会报错,因函数名已明显判断,也起到保护作用。四、数据传输加密要支持ssl连接,数据库服务端和客户端都需要openssl包,其就是调用数据传输的库,观察配置,先安装两款,在两台服务器中已经安装好就会直接调用库里。假设另一台是客户机,也是安装好的。安装好后,配置通过ssl连接,需要ssl认证签名,因没有使用到公有的签名的服务器,即为自己签名,自己给自己颁发证书。首先看openssl对应的配置文件在哪,配置文件默认在etc/pki/tls,etc/pki/tls在数据库中配置,演示使用的是openssl.cnf里的,接着生成自签名的key文件,生成key需执行openssl req”nsr“test”out server.req” 命令 ,就会出现key文件。Key文件中需输入创建key文件的密文,这里已经密文创建好,重新演示,到cost great里的密文,也可将密文作为参数写入openssl req”nsr“test”out server.req”subj’/CuCN/ST=Zhejiang/LaHeagerhou/Onsbgmbi/Cm=db-172-16-3-33,sky-sobi.con’
文章
SQL  ·  安全  ·  关系型数据库  ·  数据库连接  ·  网络安全  ·  数据库  ·  数据安全/隐私保护  ·  C语言  ·  PostgreSQL  ·  开发者
2022-11-25
前端面试+学习笔记(HTML+CSS+JavaScript+ES6+Vue+NodeJs)
前端面试+学习笔记(HTML+CSS+JavaScript+ES6+Vue+NodeJs)一. HTML1. 盒子模型是什么:每个元素被表示为一个矩形的盒子,有四个部分组成:内容(content)、内边距(padding)、边框(border)、外边距(margin)。它在页面中所占的实际大小(宽高)是content+padding+border+margin之和。盒模型有两种:标准盒模型(W3C盒模型)、IE盒模型。两种盒模型的区别:标准盒模型内容大小就是content大小、而IE盒模型内容大小则是content+padding+border总的大小。**怎么设置两种盒模型:**通过设置box-sizing属性为content-box(默认值:标准盒模型)、border-box(IE盒模型)。JS怎么获取和设置box的宽高。box-sizing使用场景:若设置子元素的margin或border时可能会撑破父元素的尺寸,就需要使用box-sizing:border-box来将border包含进元素的尺寸中。2.页面导入样式时,使用link和@import有什么区别**link属于XHTML标签,**除了加载CSS外,还能用于定义RSS(简易信息聚合,是一种基于XML标准,在互联网上被广泛采用的内容包装和投递协议)rel连接属性等作用;@import是CSS提供的;只能用于加载CSS页面被加载时,link会同时被加载;而@import引用的CSS会等到页面被加载完成后再加载link是XHTML标签,没有兼容问题;而@import只有在IE5以上才能被识别link支持使用JavaScript控制DOM修改样式;而@import不支持。4.行内元素有哪些?块级元素有哪些?空元素(void)有哪些?**行内元素:**a,b,span,img,input,strong,label,button,select,textarea,em**块级元素:**div,ul(无序列表),ol,li,dl(自定义列表),dt(自定义列表项),dd(自定义列表项的定义),p,h1-h6,blockquote(块引用)空元素(void):即没有内容的HTML元素。br(换行),hr(水平分割线),meta,link,input,img5. src 和 herf 的区别href是指向网络资源所在位置,建立和当前(锚点)或当前文档(链接)之间的连接,用于超链接。src执行外部资源的位置,指向的内容会嵌入到文档中当前标签所在位置,在请求src资源时会将其指向的资源下载并应用到文档中。当浏览器解析到该元素时,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕。(性能优化)6. 为什么CSS样式放在头部,JS脚本放在底部浏览器为了更好的用户体验,渲染引擎会尝试尽快在屏幕上显示内容,不会等到所有的HTML元素解析之后在构建和布局DOM树,所以部分内容将被解析并显示。前端一般主要关心首屏的渲染速度,这也是为什么要提倡“图片懒加载”的原因。**其实外部的js和CSS文件时并行下载的。**随着JS技术的发展,JS也开始承担起页面的渲染工作了。如果JS加载需要很长时间,会影响用户体验。所以需要将JS区分为承担页面渲染工作的JS和承担事件处理的JS。渲染页面的JS放在前面,事务处理的JS放在后面。7.常用浏览器,内核Trident内核:(国产的绝大部分浏览器)IE,360,搜狗**Gecko内核:**Firefox,NetScape6及以上**Presto内核:**Opera7及以上Webkit内核:(国产大部分双核浏览器其中一核)Safari(苹果),Chrome浏览器内核:主要分成两部分:渲染引擎和JS引擎。最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎**渲染引擎:**负责取得网页内容(HTML,XML,图像等)、整理讯息(加入CSS等),以及计算网页的显示方式,后会输出至显示器或打印机。JS引擎:解析和执行JavaScript来实现网页的动态效果。8. DOCTYPE作用?严格模式与混杂模式 , 标准模式和怪异模式声明位于HTML文档中的第一行,处于标签之前,告知浏览器的解析器用什么文档标准解析这个文档。严格模式下,排版和JS以浏览器支持的最高标准运行;**混杂模式下,**页面以宽松向后兼容的方式显示**如何触发混杂模式:**DOCTYPE不存在或格式不正确,会导致文档以混合模式呈现**标准模式(standards mode)**是指浏览器按照W3C标准解析执行代码;**怪异模式(quirks mode)**则是使用浏览器自己的方式解析执行代码。浏览器解析时到底使用何种模式,与网页中的DTD声明(文档类型定义,DOCTYPE相关)有关,忽略DTD声明,将使网页进入怪异模式。9.优雅降级和渐进增强渐进增强(progressive enhancement):针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。优雅降级(graceful degradation):一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。区别:优雅降级是**从复杂的现状开始,并试图减少用户体验的供给;渐进增强则是从一个非常基础的,**能够起作用的版本开始,并不断扩充,以适应未来环境的需要。渐进增强观点认为应该关注于内容本身,这使得渐进增强成为一种更为合理的设计范例;优雅降级观点认为应该针对那些最高级、最完善的浏览器来设计网站。10. 对HTML语义化的理解用正确的标签做正确的事情HTML语义化让页面的内容结构化,结构更清晰,便于对浏览器、搜索引擎解析即使在没有样式CSS情况下也以一种文档格式显示,并且是易于阅读的搜索引擎的爬虫也依赖于HTML标记来确定上下文和各个关键字的权重,利于SEO使阅读源代码的人更容易将网站分块,便于阅读维护理解二. CSS1.CSS选择符,优先级**选择符:**id(ID);class(类);element(标签);element element(后代);element>element(子);element,element(群组);element+element(相邻同胞);伪类(:link,:visited,:active,:hover,:focus:first-child,:lang(language));伪元素(:first-letter,:first-line,:before,:after);属性选择器**可继承的选择符:**主要是文本方面的可继承,盒模型相关的属性基本没有继承特性。font-size,font-family,color,ul**不可继承的选择符:**border,padding,margin,width,height**优先级:**同权重下样式定义最近者高。!important>内联样式 即定义在HTML标签内的样式,(1000)>id(100)>class/伪类/属性(10)>伪元素/element(1)**CSS引入伪类和伪元素的原因:**用来修饰DOM树以外的部分。伪类用于当已有元素处于某个状态时,为其添加对应的样式,这个状态根据用户行为而动态变化。伪类的操作对象是DOM树中已有的元素。伪元素用于创建一些不在DOM树中的元素,并为其添加样式伪类和伪元素的区别在于有没有创建一个DOM树之外的元素2. 外边距重叠(collapsing margins)/margin坍塌**是什么:**相邻的两个或多个普通流中的块元素,如果它们设置了外边距,那么在垂直方向上,外边距会发生重叠,以绝对值大的那个为最终结果显示在页面上,即最终的外边距等于发生层叠的外边距中绝对值较大者。**最终外边距:**margin全为正(取最大值)、margin全为负(取绝对值最大的负数)、margin有正有负(分别取正数最大值a,负数的最大绝对值b,a-b)**外边距重叠的应用:**几个段落一起布局,第一个段落的上外边距正常显示,下外边距与第二个段落的上外边距重叠。防止外边距重叠:创建BFC元素。不会发生外边距重叠的情况:行内元素、浮动元素、绝对定位元素之间的外边距都不会叠加。3. BFC(Block Formatting Context,块级格式化上下文)**是什么:**决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。简言之,就是一个特殊的块,内部的元素和外部的元素不会相互影响。BFC内的盒子会在垂直方向上一个接一个地放置,垂直方向上也会发生外边距重叠。**应用场景:**自适应布局(BFC不与float box重叠)、清除浮动(计算BFC的高度时,内部的浮动元素也被计算在内)、防止外边距重叠如何触发BFC:float属性(不为none)、overflow属性(不为visible)、position属性(absolute,fixed)、display属性(inline-block,table-cell,table-caption,flex,inline-flex)。4.元素的position属性**定义:**规定元素的定位类型。**正常文档流:**指的是没有用CSS样式去控制的HTML文档结构,代码的顺序就是网页展示的顺序。**脱离文档流:**指的是元素所显示的位置和文档代码不一致。**static:**默认值。没有定位,元素出现在正常的文档流中。**relative:**生成相对定位的元素,相对于其在正常文档流中的位置进行定位(不脱离文档流)。**absolute:**生成绝对定位的元素,相对于static定位以外的最近父级元素进行定位,即相对于其直接父级元素(脱离文档流)。absolute较少直接单独使用在正常的文档流中,主要运行于进行了相对定位的元素框架层里面,相对该层的左上点进行偏移。**fixed:**生成固定定位元素,相对于浏览器窗口进行定位。**inherit:**从父元素继承position属性的值。**z-index属性:**使用了relative、absolute、fixed三种定位后,都会使正常的文档流发生一定程度的改变,造成元素出现重叠的情形。为了能让重叠的元素有序的显示出来,需要在定位的相关元素加上z-index属性。其值是一个整数值,默认为0,数值越大表示拥有的优先级越高,该属性只对使用了定位的元素有效。5.元素的display属性**定义:**规定元素应该生成的框的类型常用属性值:**inline:**默认值。元素会被显示为内联元素。**none:**元素不会被显示。**block:**元素将显示为块级元素。**inline-block:**行内块元素,即元素像行内元素一样显示,内容像块元素一样显示。**list-item:**元素像块元素一样显示,并添加样式列表标记。**table:**元素会作为块级表格来显示。**table-caption:**元素会作为一个表格标题显示。**inherit:**从父元素继承display属性。display属性值inline和block的区别:block元素会独占一行,默认情况下,block元素宽度自动填满父级元素的宽度;block元素可以设置width、height属性,即使设置了宽度,仍然是独占一行;block元素可以设置margin和padding属性;inline元素不会独占一行,多个相邻的行内元素会排列在同一行里面,其宽度随元素的内容而变化;inline元素设置width、height无效;inline元素的margin和padding属性在水平方向上能产生边距效果,垂直方向不会产生边距效果。display:inline-block元素显示间隙inline-block水平呈现的元素之间,HTML元素标签换行显示或标签之间有空格的情况下会有间距消除办法:移除标签之间的空格;使用margin-left或margin-right取负值;对父元素设置font-size为0,然后对元素的font-size初始化;对父元素设置letter-spacing(字符间距)为负值,然后设置元素的letter-spacing为0;对父元素设置word-spacing(单词间距)为负值,然后设置元素的word-spacing为0。7.overflow属性**定义:**规定当内容溢出元素框时发生的事情**visible:**默认值。内容不会被修剪,会呈现在元素框之外**hidden:**内容会被修剪,并且其余内容不可见**scroll:**内容被修剪,但浏览器会显示滚动条以便查看其余内容**auto:**如果内容被修剪,则浏览器会显示滚动条以便查看其余内容inherit:从父元素继承overflow属性的值8. 初始化CSS样式**为什么要初始化CSS样式:**因为浏览器的兼容问题,不同浏览器对有些标签的默认值时不同的,如果没有对CSS初始化往往会出现浏览器之间页面显示差异。最简单的方法:*{margin:0;padding:0;}**初始化CSS的缺点:**对SEO(搜索引擎优化)有一定的影响。SEO:Search Engine Optimization,搜索引擎的优化。SEO具体是指通过网站结构调整、网站内容建设、网站代码优化以及站外优化,使网站满足搜索引擎的收录排名需求,提高网站在搜索引擎中关键字的排名,从而吸引精准用户进入网站,获得免费流量,产生直接销售或品牌推广。**什么是CSS Hack:**一般来说针对不同的浏览器写不同的CSS,就是CSS Hack。9.CSS属性cursor?cursor属性规定要显示的鼠标的光标类型。常用取值:pointer(手),crosshair(十字线),default(箭头),auto(浏览器设置的光标)HTML5一. HTML5 新特性1. HTML5新特性:主要是关于图像、位置、存储、多任务等功能的增加。包括:绘画canvas(通过脚本实现绘画)用于媒介回放的video和audio元素本地离线存储localStorage、sessionStorage语义化更好的内容元素:article、footer、header、nav、section表单元素:datalist(规定输入域的选项列表)、output(用于不同元素的输出)、keygen(提供一种验证用户的可靠方法)input类型:color、date、month、week、number、email(检测是否为一个email格式的地址)、range(滑动条)、search、url、tel(输入电话号码,-time选择时间)2. HTML5新标签的浏览器兼容问题:当在页面中使用HTML5新标签时,可能会得到三种不同的结果:新标签被当做错误处理并被忽略,在DOM构建时会当做这个标签不存在新标签被当做错误处理,在DOM构建时,这个新标签会被构造成行内元素新标签被识别成HTML5标签,然后用DOM节点对齐进行替换3.解决兼容性问题:**实现标签被识别。**通过document.createElement(tagName)即可让浏览器识别新标签,浏览器支持新标签后,还可以为其添加CSS样式JavaScript解决方案:使用html5shim。在中调用以下代码(也可下载到本地后调用):<!--[if It IE 9]> <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> <![endif]-->使用kill IE6<!--[if It IE 6]> <script src="http://letskillie6.googlecode.com/svn/trunk/letskillie6.an_CN.pack.js"></script> <![endif]-->4. 如何区分HTML和HTML5:DOCTYPE声明新增的元素5. HTML5移除的元素:**纯表现的元素:**big,center,font,strike(删除线),u(下划线),s(删除线)**对可用性产生负面影响的元素:**frame,frameset,noframes6.iframe的缺点会阻塞主页面的onload事件搜索引擎的检索程序无法解读这种页面,不利于SEO二. cookie和localStorage的区别1.共同点:cookie、sessionStorage和localStorage都是由浏览器存储在本地的数据。区别:cookie是网站为了标识用户身份而存储在用户本地终端上的数据(通常经过加密),数据始终在同源的http请求中携带,即在浏览器和服务器之间来回传递;localStorage不会自动把数据发给服务器,尽在本地保存cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下,存储大小也不同,cookie数据不能超过4K,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据(如会话标识);localStorage也有存储大小的限制,但比cookie大很多,可以达到5M或更大。cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭;localStorage始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;sessionStorage在当前浏览器窗口关闭之后自动删除localStorage支持**事件通知机制,**可以将数据更新的通知发送给监听者,API接口使用更方便;cookie的原生接口不友好,需要程序员自己封装**localStorage如何删除数据:**localStorage对象可以将数据长期保存在客户端,除非人为清除,提供了以下几个方法:**存储:**localStorage.setItem(key,value) 如果key存在,更新value**获取:**localStorage.getItem(key) 如果key不存在,则返回null**删除:**localStorage.removeItem(key) 一旦删除,key对应的数据将会全部删除全部清除:localStorage.clear()使用removeItem逐个删除太麻烦,可以使用**clear,**执行的结果是清除所有的localStorage对象保存的数据localStorage存储的数据是不能跨浏览器共用的,一个浏览器只能读取各自浏览器的数据。CSS3一. CSS3新特性1. 新特性边框:border-radius(圆角)、box-shadow(阴影)、border-image(边框图片)背景:background-size(背景图片的尺寸)、background-origin(背景图片的定位区域)文本效果:text-shadow(文本阴影)、word-wrap(文本换行)转换和变形:transform(包括2D,3D转换,rotate(angle),translate(x,y),scale(x,y))过渡:transition动画:animation多列:column-count(元素被分隔的列数)、column-gap(列之间的间隔)、column-rule(洌之间的宽度,样式,颜色规则)用户界面:resize(规定是否可由用户调整元素尺寸)、box-sizing(以确切的方式适应某个区域的具体内容)、outline-offset(对轮廓进行偏移)2. 新增伪类:element:before(在元素之前添加内容) element:after(在元素之后添加内容)element:first-of-type、element:last-of-type、element:only-of-type、element:only-child、element:nth-child(n)(第n个):checked、:disabled、:enabled3. 四个锚点伪类的设置问题:**问题描述:**超链接访问后hover样式就不出现了,被点击访问过的超链接样式不再具有hover和active**解决办法:**爱恨原则LoVe/HAte。改变CSS属性的排列顺序,L-V-H-A 即a:link{} a:visited() a:hover{} a:active{}4.transition、transform和animation的区别transform是指转换,可以将元素移动、旋转、倾斜、拉伸。没有变化的过程。而transition和animation都加上了时间属性,所以能产生动画效果transition是指过渡,一般由行为(hover等)触发;而animation则是自动触发transition只能设置头尾,所有样式属性一起变化;animation可以设定每一帧的样式和时间,且可以循环播放。5.rgba和opacity的区别?rgba和opacity都能实现透明效果,但最大的不同在于opacity作用于元素本身以及元素内的所有内容,而rgba只作用于元素本身,子元素不会继承透明效果。**rgba是CSS3的属性,**用法说明:rgba(R,G,B,A),参数说明R(红色值。正整数|百分数),G(绿色值。正整数|百分数),B(蓝色值。正整数|百分比),A(Alpha透明度。0(透明)~1)。IE6-8不支持rgba模式,可以使用IE滤镜处理:filter:progid:DXImageTransform.Microsoft.Gradient(startColorstr=#AARRGGBBAA,endColorstr=#AARRGGBBAA);其中AA,RR,GG,BB分别表示Alpha,R,G,B,取值为00-FF。opacity也是CSS3的属性,用法说明:opacity:value 其中value取值0(透明)~1。对于IE6-8,可以用IE滤镜处理:filter:alpha(opacity=50); /对应于opacity:0.5;浮动一. 清除浮动父级div定义height结尾处加空div标签,样式clear:both父级div定义伪类:after和zoom通过CSS伪元素在容器的内部元素最后添加了一个看不见的空格"020"或点".",并且赋予clear属性来清除浮动。需要注意的是为了IE6和IE7浏览器,要给clearfix这个class添加一条zoom:1;触发haslayout。父级div定义overflow:hidden(同时还要定义width或zoom:1,不能定义height)父级div定义overflow:auto(同时还要定义width或zoom:1,不能定义height)父级也浮动,需要定义width(不推荐)父级div定义display:table(不推荐)结尾处加br标签,样式clear:both(父元素div定义zoom:1,不推荐)二. 属性clear取值1. 定义:规定元素的那一侧不允许其他浮动元素2. 取值none:(默认值)。允许浮动元素left:在左侧不允许浮动元素right:在右侧不允许浮动元素both:在左右侧均不允许浮动元素inherit:从父元素继承clear属性三. 属性zoom取值1. 定义:设置或检索对象的缩放比例2.取值normal:(默认值),使用对象的实际尺寸:用浮点数来定义缩放比例,不允许负值:用百分比来定义缩放比例,不允许负值新的注意点:一. 重排(reflow) 与重绘(repaint)浏览器从下载文档到显示页面的过程是个复杂的过程,这里包含了重绘和重排重绘是一个元素外观的改变所触发的浏览器行为(例如改变visibility,outline,background等属性),浏览器会根据元素的新属性重新绘制,是元素呈现新的外观。**重排时更明显的一种改变,可以理解为渲染树需要重新计算。**常见的触发重排的操作:DOM元素的几何属性变化DOM树的结构变化(例如节点的增减、移动)获取某些属性(例如offsetTop,offsetLeft,offsetHeight,offsetWidth,clientWidth,clientHeight等)改变元素的一些样式(例如调整浏览器窗口大小)重绘不会带来重新布局,并不一定伴随着重排。在实践中,应该尽量减少重排次数和缩小重排的影响范围。有以下几种方法:将多次改变样式属性的操作合并成一次操作将需要多次重排的元素,position属性设为absolute或fixed,使其脱离文档流,这样它的变化就不会影响到其他元素在内存中多次操作节点,完成后再添加到文档中去如果要对一个元素进行复杂的操作,可以将其display属性设置为none使其隐藏,待操作完成后再显示在需要经常获取那些引起浏览器重排的属性值时,要缓存到变量如何在网页中添加空格? 在HTML代码中输入 二. 如何在网页中显示代码?对于单行代码,使用标签<code>代码</code>对于多行代码,使用标签<pre></pre> (被包围在pre元素中的文本通常会保留空格和换行符)26.使用mailto在网页中链接Email地址?(1)a标签有一个作用是可以链接Email地址,使用mailto能让访问者便捷想网站管理者发送电子邮件(2)如果mailto后面同时又多个参数的话,第一个参数必须以?开头,后面的参数每一个都以&分隔三. form表单当前页面无刷新提交?使用target属性取值为iframe元素的name属性值。具体如下:在当前页面建一个iframe并隐藏(display:none)给这个iframe取名(name=“id_iframe”)设置form表单的target属性(target=“id_iframe”)提交表单,就是无刷新iframe标签一. 优点iframe能够把嵌入的页面展示出来,如果有多个网页引用iframe,只需要修改iframe的内容,就可以实现调用的每一个页面内容的更改,方便快捷网页如果为了统一风格,头部和版本都是一样的,就可以写成一个页面,用iframe来嵌套,可以增加代码的可重用重载页面时不需要重载整个页面,只需要重载页面中的一个框架页,减少了数据的传输,增加了网页的下载速度方便制作导航栏二. 缺点会产生很多页面,不利于管理浏览器的前进/后退按钮无效无法被一些搜索引擎索引到,现在搜索引擎爬虫还不能很好的处理iframe中的内容,所以不利于SEO多数小型的移动设备无法显示框架,兼容性差多框架的页面会增加服务器的http请求,对于大型网站是不可取的综上,目前框架中的所有优点完全可以使用Ajax实现,因此不推荐使用框架ES6一、问:ES6是什么,为什么要学习它,不学习ES6会怎么样?答: ES6是新一代的JS语言标准,对分JS语言核心内容做了升级优化,规范了JS使用标准,新增了JS原生方法,使得JS使用更加规范,更加优雅,更适合大型应用的开发。学习ES6是成为专业前端正规军的必经之路。不学习ES6也可以写代码打鬼子,但是最多只能当个游击队长。二、问:ES5、ES6和ES2015有什么区别?答: ES2015特指在2015年发布的新一代JS语言标准,ES6泛指下一代JS语言标准,包含ES2015、ES2016、ES2017、ES2018等。现阶段在绝大部分场景下,ES2015默认等同ES6。ES5泛指上一代语言标准。ES2015可以理解为ES5和ES6的时间分界线。三、问:babel是什么,有什么作用?答:babel是一个 ES6 转码器,可以将 ES6 代码转为 ES5 代码,以便兼容那些还没支持ES6的平台。四、问:let有什么用,有了var为什么还要用let?答: 在ES6之前,声明变量只能用var,var方式声明变量其实是很不合理的,准确的说,是因为ES5里面没有块级作用域是很不合理的,甚至可以说是一个语言层面的bug(这也是很多c++、java开发人员看不懂,也瞧不起JS语言的劣势之一)。没有块级作用域回来带很多难以理解的问题,比如for循环var变量泄露,变量覆盖等问题。let 声明的变量拥有自己的块级作用域,且修复了var声明变量带来的变量提升问题。五、问:举一些ES6对String字符串类型做的常用升级优化?答:1、优化部分:ES6新增了字符串模板,在拼接大段字符串时,用反斜杠(`)取代以往的字符串相加的形式,能保留所有空格和换行,使得字符串拼接看起来更加直观,更加优雅。2、升级部分:ES6在String原型上新增了includes()方法,用于取代传统的只能用indexOf查找包含字符的方法(indexOf返回-1表示没查到不如includes方法返回false更明确,语义更清晰), 此外还新增了startsWith(), endsWith(), padStart(),padEnd(),repeat()等方法,可方便的用于查找,补全字符串。六、问:举一些ES6对Array数组类型做的常用升级优化?答:1、优化部分:a. 数组解构赋值。ES6可以直接以let [a,b,c] = [1,2,3]形式进行变量赋值,在声明较多变量时,不用再写很多let(var),且映射关系清晰,且支持赋默认值。b. 扩展运算符。ES6新增的扩展运算符(…)(重要),可以轻松的实现数组和松散序列的相互转化,可以取代arguments对象和apply方法,轻松获取未知参数个数情况下的参数集合。(尤其是在ES5中,arguments并不是一个真正的数组,而是一个类数组的对象,但是扩展运算符的逆运算却可以返回一个真正的数组)。扩展运算符还可以轻松方便的实现数组的复制和解构赋值(let a = [2,3,4]; let b = [...a])。2、升级部分:ES6在Array原型上新增了find()方法,用于取代传统的只能用indexOf查找包含数组项目的方法,且修复了indexOf查找不到NaN的bug([NaN].indexOf(NaN) === -1).此外还新增了copyWithin(), includes(), fill(),flat()等方法,可方便的用于字符串的查找,补全,转换等。七、问:举一些ES6对Number数字类型做的常用升级优化?答:1、优化部分:ES6在Number原型上新增了isFinite(), isNaN()方法,用来取代传统的全局isFinite(), isNaN()方法检测数值是否有限、是否是NaN。ES5的isFinite(), isNaN()方法都会先将非数值类型的参数转化为Number类型再做判断,这其实是不合理的,最造成isNaN('NaN') === true的奇怪行为–'NaN’是一个字符串,但是isNaN却说这就是NaN。而Number.isFinite()和Number.isNaN()则不会有此类问题(Number.isNaN('NaN') === false)。(isFinite()同上)2、升级部分:ES6在Math对象上新增了Math.cbrt(),trunc(),hypot()等等较多的科学计数法运算方法,可以更加全面的进行立方根、求和立方根等等科学计算。八、问:举一些ES6对Object类型做的常用升级优化?(重要)答:1、优化部分:a. 对象属性变量式声明。ES6可以直接以变量形式声明对象属性或者方法,。比传统的键值对形式声明更加简洁,更加方便,语义更加清晰。let [apple, orange] = ['red appe', 'yellow orange']; let myFruits = {apple, orange}; // let myFruits = {apple: 'red appe', orange: 'yellow orange'}; 复制代码尤其在对象解构赋值(见优化部分b.)或者模块输出变量时,这种写法的好处体现的最为明显:let {keys, values, entries} = Object; let MyOwnMethods = {keys, values, entries}; // let MyOwnMethods = {keys: keys, values: values, entries: entries} 复制代码可以看到属性变量式声明属性看起来更加简洁明了。方法也可以采用简洁写法:let es5Fun = { method: function(){} }; let es6Fun = { method(){} } 复制代码b. 对象的解构赋值。 ES6对象也可以像数组解构赋值那样,进行变量的解构赋值:let {apple, orange} = {apple: 'red appe', orange: 'yellow orange'}; 复制代码c. 对象的扩展运算符(…)。 ES6对象的扩展运算符和数组扩展运算符用法本质上差别不大,毕竟数组也就是特殊的对象。对象的扩展运算符一个最常用也最好用的用处就在于可以轻松的取出一个目标对象内部全部或者部分的可遍历属性,从而进行对象的合并和分解。let {apple, orange, ...otherFruits} = {apple: 'red apple', orange: 'yellow orange', grape: 'purple grape', peach: 'sweet peach'}; // otherFruits {grape: 'purple grape', peach: 'sweet peach'} // 注意: 对象的扩展运算符用在解构赋值时,扩展运算符只能用在最有一个参数(otherFruits后面不能再跟其他参数) let moreFruits = {watermelon: 'nice watermelon'}; let allFruits = {apple, orange, ...otherFruits, ...moreFruits}; 复制代码d. super 关键字。ES6在Class类里新增了类似this的关键字super。同this总是指向当前函数所在的对象不同,super关键字总是指向当前函数所在对象的原型对象。2、升级部分:a. ES6在Object原型上新增了is()方法,做两个目标对象的相等比较,用来完善’=‘方法。’='方法中NaN === NaN //false其实是不合理的,Object.is修复了这个小bug。(Object.is(NaN, NaN) // true)b. ES6在Object原型上新增了assign()方法,用于对象新增属性或者多个对象合并。const target = { a: 1 }; const source1 = { b: 2 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3} 复制代码注意: assign合并的对象target只能合并source1、source2中的自身属性,并不会合并source1、source2中的继承属性,也不会合并不可枚举的属性,且无法正确复制get和set属性(会直接执行get/set函数,取return的值)。c. ES6在Object原型上新增了getOwnPropertyDescriptors()方法,此方法增强了ES5中getOwnPropertyDescriptor()方法,可以获取指定对象所有自身属性的描述对象。结合defineProperties()方法,可以完美复制对象,包括复制get和set属性。d. ES6在Object原型上新增了getPrototypeOf()和setPrototypeOf()方法,用来获取或设置当前对象的prototype对象。这个方法存在的意义在于,ES5中获取设置prototype对像是通过__proto__属性来实现的,然而__proto__属性并不是ES规范中的明文规定的属性,只是浏览器各大产商“私自”加上去的属性,只不过因为适用范围广而被默认使用了,再非浏览器环境中并不一定就可以使用,所以为了稳妥起见,获取或设置当前对象的prototype对象时,都应该采用ES6新增的标准用法。d. ES6在Object原型上还新增了Object.keys(),Object.values(),Object.entries()方法,用来获取对象的所有键、所有值和所有键值对数组。九、问:举一些ES6对Function函数类型做的常用升级优化?(重要)答:1、优化部分:a. 箭头函数**(核心)**。箭头函数是ES6核心的升级项之一,箭头函数里没有自己的this,这改变了以往JS函数中最让人难以理解的this运行机制。主要优化点:Ⅰ. 箭头函数内的this指向的是函数定义时所在的对象,而不是函数执行时所在的对象。ES5函数里的this总是指向函数执行时所在的对象,这使得在很多情况下this的指向变得很难理解,尤其是非严格模式情况下,this有时候会指向全局对象,这甚至也可以归结为语言层面的bug之一。ES6的箭头函数优化了这一点,它的内部没有自己的this,这也就导致了this总是指向上一层的this,如果上一层还是箭头函数,则继续向上指,直到指向到有自己this的函数为止,并作为自己的this。Ⅱ. 箭头函数不能用作构造函数,因为它没有自己的this,无法实例化。Ⅲ. 也是因为箭头函数没有自己的this,所以箭头函数 内也不存在arguments对象。(可以用扩展运算符代替)b. 函数默认赋值。ES6之前,函数的形参是无法给默认值得,只能在函数内部通过变通方法实现。ES6以更简洁更明确的方式进行函数默认赋值。function es6Fuc (x, y = 'default') { console.log(x, y); } es6Fuc(4) // 4, default 复制代码2、升级部分:ES6新增了双冒号运算符,用来取代以往的bind,call,和apply。(浏览器暂不支持,Babel已经支持转码)foo::bar; // 等同于 bar.bind(foo); foo::bar(...arguments); // 等同于 bar.apply(foo, arguments); 复制代码十、问:Symbol是什么,有什么作用?答: Symbol是ES6引入的第七种原始数据类型(说法不准确,应该是第七种数据类型,Object不是原始数据类型之一,已更正),所有Symbol()生成的值都是独一无二的,可以从根本上解决对象属性太多导致属性名冲突覆盖的问题。对象中Symbol()属性不能被for…in遍历,但是也不是私有属性。十一、问:Set是什么,有什么作用?答: Set是ES6引入的一种类似Array的新的数据结构,Set实例的成员类似于数组item成员,区别是Set实例的成员都是唯一,不重复的。这个特性可以轻松地实现数组去重。十二、问:Map是什么,有什么作用?答: Map是ES6引入的一种类似Object的新的数据结构,Map可以理解为是Object的超集,打破了以传统键值对形式定义对象,对象的key不再局限于字符串,也可以是Object。可以更加全面的描述对象的属性。十三、问:Proxy是什么,有什么作用?答: Proxy是ES6新增的一个构造函数,可以理解为JS语言的一个代理,用来改变JS默认的一些语言行为,包括拦截默认的get/set等底层方法,使得JS的使用自由度更高,可以最大限度的满足开发者的需求。比如通过拦截对象的get/set方法,可以轻松地定制自己想要的key或者value。下面的例子可以看到,随便定义一个myOwnObj的key,都可以变成自己想要的函数。function createMyOwnObj() { //想把所有的key都变成函数,或者Promise,或者anything return new Proxy({}, { get(target, propKey, receiver) { return new Promise((resolve, reject) => { setTimeout(() => { let randomBoolean = Math.random() > 0.5; let Message; if (randomBoolean) { Message = `你的${propKey}运气不错,成功了`; resolve(Message); } else { Message = `你的${propKey}运气不行,失败了`; reject(Message); } }, 1000); }); } }); } let myOwnObj = createMyOwnObj(); myOwnObj.hahaha.then(result => { console.log(result) //你的hahaha运气不错,成功了 }).catch(error => { console.log(error) //你的hahaha运气不行,失败了 }) myOwnObj.wuwuwu.then(result => { console.log(result) //你的wuwuwu运气不错,成功了 }).catch(error => { console.log(error) //你的wuwuwu运气不行,失败了 }) 复制代码十四、问:Reflect是什么,有什么作用?答: Reflect是ES6引入的一个新的对象,他的主要作用有两点,一是将原生的一些零散分布在Object、Function或者全局函数里的方法(如apply、delete、get、set等等),统一整合到Reflect上,这样可以更加方便更加统一的管理一些原生API。其次就是因为Proxy可以改写默认的原生API,如果一旦原生API别改写可能就找不到了,所以Reflect也可以起到备份原生API的作用,使得即使原生API被改写了之后,也可以在被改写之后的API用上默认的API。十五、问:Promise是什么,有什么作用?答: Promise是ES6引入的一个新的对象,他的主要作用是用来解决JS异步机制里,回调机制产生的“回调地狱”。它并不是什么突破性的API,只是封装了异步回调形式,使得异步回调可以写的更加优雅,可读性更高,而且可以链式调用。十六、问:Iterator是什么,有什么作用?(重要)答: Iterator是ES6中一个很重要概念,它并不是对象,也不是任何一种数据类型。因为ES6新增了Set、Map类型,他们和Array、Object类型很像,Array、Object都是可以遍历的,但是Set、Map都不能用for循环遍历,解决这个问题有两种方案,一种是为Set、Map单独新增一个用来遍历的API,另一种是为Set、Map、Array、Object新增一个统一的遍历API,显然,第二种更好,ES6也就顺其自然的需要一种设计标准,来统一所有可遍历类型的遍历方式。Iterator正是这样一种标准。或者说是一种规范理念。就好像JavaScript是ECMAScript标准的一种具体实现一样,Iterator标准的具体实现是Iterator遍历器。Iterator标准规定,所有部署了key值为[Symbol.iterator],且[Symbol.iterator]的value是标准的Iterator接口函数(标准的Iterator接口函数: 该函数必须返回一个对象,且对象中包含next方法,且执行next()能返回包含value/done属性的Iterator对象)的对象,都称之为可遍历对象,next()后返回的Iterator对象也就是Iterator遍历器。//obj就是可遍历的,因为它遵循了Iterator标准,且包含[Symbol.iterator]方法,方法函数也符合标准的Iterator接口规范。 //obj.[Symbol.iterator]() 就是Iterator遍历器 let obj = { data: [ 'hello', 'world' ], [Symbol.iterator]() { const self = this; let index = 0; return { next() { if (index < self.data.length) { return { value: self.data[index++], done: false }; } else { return { value: undefined, done: true }; } } }; } }; 复制代码ES6给Set、Map、Array、String都加上了[Symbol.iterator]方法,且[Symbol.iterator]方法函数也符合标准的Iterator接口规范,所以Set、Map、Array、String默认都是可以遍历的。//Array let array = ['red', 'green', 'blue']; array[Symbol.iterator]() //Iterator遍历器 array[Symbol.iterator]().next() //{value: "red", done: false} //String let string = '1122334455'; string[Symbol.iterator]() //Iterator遍历器 string[Symbol.iterator]().next() //{value: "1", done: false} //set let set = new Set(['red', 'green', 'blue']); set[Symbol.iterator]() //Iterator遍历器 set[Symbol.iterator]().next() //{value: "red", done: false} //Map let map = new Map(); let obj= {map: 'map'}; map.set(obj, 'mapValue'); map[Symbol.iterator]().next() {value: Array(2), done: false} 复制代码十七、问:for…in 和for…of有什么区别?答: 如果看到问题十六,那么就很好回答。问题十六提到了ES6统一了遍历标准,制定了可遍历对象,那么用什么方法去遍历呢?答案就是用for…of。ES6规定,有所部署了载了Iterator接口的对象(可遍历对象)都可以通过for…of去遍历,而for…in仅仅可以遍历对象。这也就意味着,数组也可以用for…of遍历,这极大地方便了数组的取值,且避免了很多程序用for…in去遍历数组的恶习。上面提到的扩展运算符本质上也就是for…of循环的一种实现。十八、Generator函数是什么,有什么作用?答: 如果说JavaScript是ECMAScript标准的一种具体实现、Iterator遍历器是Iterator的具体实现,那么Generator函数可以说是Iterator接口的具体实现方式。执行Generator函数会返回一个遍历器对象,每一次Generator函数里面的yield都相当一次遍历器对象的next()方法,并且可以通过next(value)方法传入自定义的value,来改变Generator函数的行为。Generator函数可以通过配合Thunk 函数更轻松更优雅的实现异步编程和控制流管理。十九、async函数是什么,有什么作用?答: async函数可以理解为内置自动执行器的Generator函数语法糖,它配合ES6的Promise近乎完美的实现了异步编程解决方案。二十、Class、extends是什么,有什么作用?答: ES6 的class可以看作只是一个ES5生成实例对象的构造函数的语法糖。它参考了java语言,定义了一个类的概念,让对象原型写法更加清晰,对象实例化更像是一种面向对象编程。Class类可以通过extends实现继承。它和ES5构造函数的不同点:a. 类的内部定义的所有方法,都是不可枚举的。///ES5 function ES5Fun (x, y) { this.x = x; this.y = y; } ES5Fun.prototype.toString = function () { return '(' + this.x + ', ' + this.y + ')'; } var p = new ES5Fun(1, 3); p.toString(); Object.keys(ES5Fun.prototype); //['toString'] //ES6 class ES6Fun { constructor (x, y) { this.x = x; this.y = y; } toString () { return '(' + this.x + ', ' + this.y + ')'; } } Object.keys(ES6Fun.prototype); //[] 复制代码b.ES6的class类必须用new命令操作,而ES5的构造函数不用new也可以执行。c.ES6的class类不存在变量提升,必须先定义class之后才能实例化,不像ES5中可以将构造函数写在实例化之后。d.ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。二十一、module、export、import是什么,有什么作用?答: module、export、import是ES6用来统一前端模块化方案的设计思路和实现方案。export、import的出现统一了前端模块化的实现方案,整合规范了浏览器/服务端的模块化方法,用来取代传统的AMD/CMD、requireJS、seaJS、commondJS等等一系列前端模块不同的实现方案,使前端模块化更加统一规范,JS也能更加能实现大型的应用程序开发。import引入的模块是静态加载(编译阶段加载)而不是动态加载(运行时加载)。import引入export导出的接口值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。二十二、日常前端代码开发中,有哪些值得用ES6去改进的编程优化或者规范?答:1、常用箭头函数来取代var self = this;的做法。2、常用let取代var命令。3、常用数组/对象的结构赋值来命名变量,结构更清晰,语义更明确,可读性更好。4、在长字符串多变量组合场合,用模板字符串来取代字符串累加,能取得更好地效果和阅读体验。5、用Class类取代传统的构造函数,来生成实例化对象。6、在大型应用开发中,要保持module模块化开发思维,分清模块之间的关系,常用import、export方法。VUE一、对于MVVM的理解?MVVM 是 Model-View-ViewModel 的缩写。Model代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。View 代表UI 组件,它负责将数据模型转化成UI 展现出来。ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步View 和 Model的对象,连接Model和View。在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。二、Vue的生命周期beforeCreate(创建前) 在数据观测和初始化事件还未开始created(创建后) 完成数据观测,属性和方法的运算,初始化事件,el属性还没有显示出来 **beforeMount**(载入前) 在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。 **mounted**(载入后) 在el 被新创建的 vm.el属性还没有显示出来∗∗beforeMount∗∗(载入前)在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。∗∗mounted∗∗(载入后)在el被新创建的vm.el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互。beforeUpdate(更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。updated(更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。beforeDestroy(销毁前) 在实例销毁之前调用。实例仍然完全可用。destroyed(销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。1.什么是vue生命周期?答: Vue 实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、销毁等一系列过程,称之为 Vue 的生命周期。2.vue生命周期的作用是什么?答:它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。3.vue生命周期总共有几个阶段?答:它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后。4.第一次页面加载会触发哪几个钩子?答:会触发 下面这几个beforeCreate, created, beforeMount, mounted 。5.DOM 渲染在 哪个周期中就已经完成?答:DOM 渲染在 mounted 中就已经完成了。三、 Vue实现数据双向绑定的原理:Object.defineProperty()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变更双向绑定效果。js实现简单的双向绑定<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>四、Vue组件间的参数传递1.父组件与子组件传值父组件传给子组件:子组件通过props方法接受数据;子组件传给父组件:$emit方法传递参数2.非父子组件间的数据传递,兄弟组件传值eventBus,就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。项目比较小时,用这个比较合适。(虽然也有不少人推荐直接用VUEX,具体来说看需求咯。技术只是手段,目的达到才是王道。)五、Vue的路由实现:hash模式 和 history模式**hash模式:**在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取;特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.xxx.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。**history模式:**history采用HTML5的新特性;且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.xxx.com/items/id。后端如果缺少对 /items/id 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“不过这种模式要玩好,还需要后台配置支持……所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。”六、Vue与Angular以及React的区别?(版本在不断更新,以下的区别有可能不是很正确。我工作中只用到vue,对angular和react不怎么熟)1.与AngularJS的区别相同点:都支持指令:内置指令和自定义指令;都支持过滤器:内置过滤器和自定义过滤器;都支持双向数据绑定;都不支持低端浏览器。不同点:AngularJS的学习成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比较简单、直观;在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢;Vue.js使用基于依赖追踪的观察并且使用异步队列更新,所有的数据都是独立触发的。2.与React的区别相同点:React采用特殊的JSX语法,Vue.js在组件开发中也推崇编写.vue特殊文件格式,对文件内容都有一些约定,两者都需要编译后使用;中心思想相同:一切都是组件,组件实例之间可以嵌套;都提供合理的钩子函数,可以让开发者定制化地去处理需求;都不内置列数AJAX,Route等功能到核心包,而是以插件的方式加载;在组件开发中都支持mixins的特性。不同点:React采用的Virtual DOM会对渲染出来的结果做脏检查;Vue.js在模板中提供了指令,过滤器等,可以非常方便,快捷地操作Virtual DOM。七、vue路由的钩子函数首页可以控制导航跳转,beforeEach,afterEach等,一般用于页面title的修改。一些需要登录才能调整页面的重定向功能。beforeEach主要有3个参数to,from,next:to:route即将进入的目标路由对象,from:route当前导航正要离开的路由next:function一定要调用该方法resolve这个钩子。执行效果依赖next方法的调用参数。可以控制网页的跳转。八、vuex是什么?怎么使用?哪种功能场景使用它?只用来读取的状态集中放在store中; 改变状态的方式是提交mutations,这是个同步的事物; 异步逻辑应该封装在action中。在main.js引入store,注入。新建了一个目录store,…… export 。场景有:单页应用中,组件之间的状态、音乐播放、登录状态、加入购物车[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-biCZCx5s-1611887935896)(C:\Users\zjx\Desktop\桌面文件\web面试\Vuepng.png)]stateVuex 使用单一状态树,即每个应用将仅仅包含一个store 实例,但单一状态树和模块化并不冲突。存放的数据状态,不可以直接修改里面的数据。mutationsmutations定义的方法动态修改Vuex 的 store 中的状态或数据。getters类似vue的计算属性,主要用来过滤一些数据。actionactions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据。view 层通过 store.dispath 来分发 action。const store = new Vuex.Store({ //store实例 state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })modules项目特别复杂的时候,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB })九、vue-cli如何新增自定义指令?1.创建局部指令var app = new Vue({ el: '#app', data: { }, // 创建指令(可以多个) directives: { // 指令名称 dir1: { inserted(el) { // 指令中第一个参数是当前使用指令的DOM console.log(el); console.log(arguments); // 对DOM进行操作 el.style.width = '200px'; el.style.height = '200px'; el.style.background = '#000'; } } } })2.全局指令Vue.directive('dir2', { inserted(el) { console.log(el); } })3.指令的使用<div id="app"> <div v-dir1></div> <div v-dir2></div> </div>十、vue如何自定义一个过滤器?html代码:<div id="app"> <input type="text" v-model="msg" /> {{msg| capitalize }} </div>JS代码:var vm=new Vue({ el:"#app", data:{ msg:'' }, filters: { capitalize: function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) } } })全局定义过滤器Vue.filter('capitalize', function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) })过滤器接收表达式的值 (msg) 作为第一个参数。capitalize 过滤器将会收到 msg的值作为第一个参数。十一、对keep-alive 的了解?keep-alive是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。在vue 2.1.0 版本之后,keep-alive新加入了两个属性: include(包含的组件缓存) 与 exclude(排除的组件不缓存,优先级大于include) 。使用方法<keep-alive include='include_components' exclude='exclude_components'> <component> <!-- 该组件是否缓存取决于include和exclude属性 --> </component> </keep-alive>参数解释include - 字符串或正则表达式,只有名称匹配的组件会被缓存exclude - 字符串或正则表达式,任何名称匹配的组件都不会被缓存include 和 exclude 的属性允许组件有条件地缓存。二者都可以用“,”分隔字符串、正则表达式、数组。当使用正则或者是数组时,要记得使用v-bind 。使用示例<!-- 逗号分隔字符串,只有组件a与b被缓存。 --> <keep-alive include="a,b"> <component></component> </keep-alive> <!-- 正则表达式 (需要使用 v-bind,符合匹配规则的都会被缓存) --> <keep-alive :include="/a|b/"> <component></component> </keep-alive> <!-- Array (需要使用 v-bind,被包含的都会被缓存) --> <keep-alive :include="['a', 'b']"> <component></component> </keep-alive>十二、一句话就能回答的面试题1.css只在当前组件起作用答:在style标签中写入scoped即可 例如:2.v-if 和 v-show 区别答:v-if按照条件是否渲染,v-show是display的block或none;3.route和route和router的区别答:$route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。而$router是“路由实例”对象包括了路由的跳转方法,钩子函数等。4.vue.js的两个核心是什么?答:数据驱动、组件系统5.vue几种常用的指令答:v-for 、 v-if 、v-bind、v-on、v-show、v-else6.vue常用的修饰符?答:.prevent: 提交事件不再重载页面;.stop: 阻止单击事件冒泡;.self: 当事件发生在该元素本身而不是子元素的时候会触发;.capture: 事件侦听,事件发生的时候会调用7.v-on 可以绑定多个方法吗?答:可以8.vue中 key 值的作用?答:当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。key的作用主要是为了高效的更新虚拟DOM。9.什么是vue的计算属性?答:在模板中放入太多的逻辑会让模板过重且难以维护,在需要对数据进行复杂处理,且可能多次使用的情况下,尽量采取计算属性的方式。好处:①使得数据处理结构清晰;②依赖于数据,数据更新,处理结果自动更新;③计算属性内部this指向vm实例;④在template调用时,直接写计算属性名即可;⑤常用的是getter方法,获取数据,也可以使用set方法改变数据;⑥相较于methods,不管依赖的数据变不变,methods都会重新计算,但是依赖数据不变的时候computed从缓存中获取,不会重新计算。10.vue等单页面应用及其优缺点答:优点:Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件,核心是一个响应的数据绑定系统。MVVM、数据驱动、组件化、轻量、简洁、高效、快速、模块友好。缺点:不支持低版本的浏览器,最低只支持到IE9;不利于SEO的优化(如果要支持SEO,建议通过服务端来进行渲染组件);第一次加载首页耗时相对长一些;不可以使用浏览器的导航按钮需要自行实现前进、后退。11.怎么定义 vue-router 的动态路由? 怎么获取传过来的值答:在 router 目录下的 index.js 文件中,对 path 属性加上 /:id,使用 router 对象的 params.id 获取。算法面试1. 字符串回文判断思路:回文是指把相同的词汇或句子,在下文中调换位置或颠倒过来,产生首尾回环的情景,叫做回文,也叫回环。将一个字符串首尾倒序排列,如果与原字符串相等,则这个字符串回文。<script type="text/javascript"> var str1 = 'abcdefgh'; var str2 = 'abcdcba'; function plalindrome(str){ return str == str.split('').reverse().join(''); } console.log(plalindrome(str1));//false console.log(plalindrome(str2));//true </script>2. 数组去重思路:利用indexOf()a方法,在遍历原数组,若里面的元素第一次出现,则放在数组arr1中,遍历完之后,arr1中存放的是无重复的新数组<script type="text/javascript"> var arr = [2,4,2,2,5,6,7,8,9,9,9]; function unique(arr){ var arr1 = []; for (var i = 0;i < arr.length;i ++){ if(arr1.indexOf(arr[i]) == -1){ arr1.push(arr[i]); } } return arr1; } console.log(unique(arr));//[2, 4, 5, 6, 7, 8, 9] </script>3. 统计一个字符串中出现最多的字母思路:在另外一个数组存放原数组每个元素出现的位置次数,且次数跟存放不重复数组的下标对应,然后取出最多的次数,对应的下标就是不重复数组里面那个出现次数最多的元素的下标<script type="text/javascript"> var str1 = "jhadfgskjfajhdewqe"; var arr1 = str1.split(''); console.log(arr1); function MostUnit(){ var arrA = []; var arrB = []; for(var i = 0 ;i <arr1.length; i ++){ if(arrA.indexOf(arr1[i])==-1){ arrA.push(arr1[i]); arrB.push(1); }else { arrB[arrA.indexOf(arr1[i])] ++; } } console.log(arrB) console.log(arrA[arrB.indexOf(Math.max.apply(Math,arrB))]); } MostUnit();//j </script>4. 冒泡排序:比较相邻的元素。如果第一个比第二个大,就交换他们两个。对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。针对所有的元素重复以上的步骤,除了最后一个。持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较<script type="text/javascript"> var arr1 = [2,3,45,64,321,3,21,321,31,999]; function bubbleSort(arr) { for(var i = 0 ;i < arr1.length-1 ;i ++){ for(var j = 0; j < arr1.length - i - 1 ;j ++){ if(arr[j]>arr[j+1]) { let tem = arr[j]; arr[j] = arr[j+1]; arr[j+1] = tem; } } } return arr; } console.log(bubbleSort(arr1));//[2, 3, 3, 21, 31, 45, 64, 321, 321, 999] </script>5. 快速排序:思路:算法参考某个元素值,将小于它的值,放到左数组中,大于它的值的元素就放到右数组中,然后递归进行上一次左右数组的操作,返回合并的数组就是已经排好顺序的数组了。<script type="text/javascript"> var arr1 = [1,4,765,86,53,87,53,32,6,64,2,3,767,34,1,4,35,6]; function quickSort(arr){ if(arr.length <= 1){ return arr; } var leftArr = []; var rightArr = []; var q = arr[0]; for(var i = 1;i < arr.length; i++) { if(arr[i]>q) { rightArr.push(arr[i]); }else{ leftArr.push(arr[i]); } } return [].concat(quickSort(leftArr),[q],quickSort(rightArr)); } console.log(quickSort(arr1));//[1,4,765,86,53,87,53,32,6,64,2,3,767,34,1,4,35,6] </script>6. 不利用第三方变量的情况下交换两个变量的值思路:利用两个元素的差值进行计算<script type="text/javascript"> var a = 10; var b = 12; function swap (a,b) { b = b - a; a = a + b; b = a - b; return [a,b] } console.log(swap(a,b)); </script>7. 求一个数组中最大数和最小数的差值<script type="text/javascript"> var arr1 = [2,44,3,-12,43,5,8,67,54,32,-211]; var max = Math.max.apply(Math,arr1); var min = Math.min.apply(Math,arr1); console.log(max-min);//278 </script>8. 生成指定长度的随机字符串思路:charAt()方法,获取元素下标<script type="text/javascript"> function randomString(n){ var str1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz9876543210" var str2 = ""; for (var i = 0; i < n ; i ++){ str2 += str1.charAt(Math.floor(Math.random()*str1.length)); } return str2; } console.log(randomString(5)); </script>9. 获取一个DOM节点下面包含某个class名的所有节点<div id="text"> <div class="cs"></div> <div class="as"></div> <p class="cs"></p> </div> <script type="text/javascript"> function getClass(node,classname) { if(node.getElementsByClassName) { return node.getElementsByClassName(classname); //如果存在该标签 就返回 } else { var elems = node.getElementsByTagName(node), defualt = []; for (var i = 0; i < elems.length; i++) { //遍历所有标签 if(elems[i].className.indexOf(classname) != -1) { //查找相应类名的标签 defualt[defualt.length] = elems[i]; } } return defualt; } } var text = document.getElementById('text'), cs = getClass(text,'cs'); console.log(cs);//[div.cs, p.cs] </script>10. 二叉树一说到二叉树我们肯定会问,什么是二叉树,二叉树是个啥子东东,拿来有啥子用嘛,我们为啥子要学习它嘛? 如果当初你在学习二叉树的时候你没有问过自己这些问题,那么你对它的了解也仅仅也只是了解。那我们现在来说说什么是二叉树,二叉树就是一种数据结构, 它的组织关系就像是自然界中的树一样。官方语言的定义是:是一个有限元素的集合,该集合或者为空、或者由一个称为根的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成。至于为啥子要学习它,妈妈总是说,孩子,等你长大了就明白了。11. 二叉树的性质性质1:二叉树第i层上的节点数目最多为2i-1(i≥1);性质2:深度为k的二叉树至多有2k-1个结点(k≥1)。性质3: 在任意-棵二叉树中,若叶子结点(即度为0的结点)的个数为n0,度为1的结点数为n1,度为2的结点数为n2,则no=n2+1。12. 二叉树的存储结构与构建二叉树的存储方式有两种,一种顺序存储,比如:var binaryTree = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘h’, ‘i’]; 这就是一颗二叉树,假设binaryTree[i]是二叉树的一个节点,那么它的左孩子节点 leftChild = binaryTree[i2+1]那  么相应的右孩子节点 rightChild = binaryTree[i2+2]; 一般情况下顺序存储的这种结构用的较少,另外一种存储方式就是链式存储,下面我会用代码来详细描述二叉树式  结构的构建与存储方式,构建二叉树也有两种方式一种是递归方式构建,这种很简单,另一种是非递归方法构建,这种呢相对于前一种复杂一点点,不过也不用担心,我在  代码中加上详细的注释,一步一步的走下去。我们现在就以26个英文字母来构建二叉树var charecters = [‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’, ‘H’, ‘I’, ‘J’, ‘K’, ‘L’, ‘M’, ‘N’, ‘O’, ‘P’, ‘Q’, ‘R’, ‘S’, ‘T’, ‘U’, ‘V’, ‘W’, ‘X’, ‘Y’, ‘Z’];在构建二叉树之前我们会用到一个节点对象,节点对象如下:(注意:关于javascript的面向对象,原型,语法特点我会放在javascript语言知识点这个系列)/* *二叉树的节点对象 */ function Node() { this.text = ''; //节点的文本 this.leftChild = null; //节点的左孩子引用 this.rightChild = null; //节点右孩子引用 }13. 递归构建二叉树在构建好二叉树节点之后我们紧接着用递归来构建二叉树var charecters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; function buildTree(node, i) { var leftIndex = 2*i+1, //左孩子节点的索引 rightIndex = 2*i+2; //右孩子节点的索引 if(leftIndex < charecters.length) { //判断索引的长度是否超过了charecters数组的大小 var childNode = new Node(); //创建一个新的节点对象 childNode.text = charecters[leftIndex]; //给节点赋值 node.leftChild = childNode; //给当前节点node加入左孩子节点 buildTree(childNode, leftIndex); //递归创建左孩子 } if(rightIndex < charecters.length) { //下面注释参照上面的构建左孩子的节点 var childNode = new Node(); childNode.text = charecters[rightIndex]; node.rightChild = childNode; buildTree(childNode, rightIndex); } } //下面构造二叉树 var node = new Node(); node.text = charecters[0]; buildTree(node, 0); //索引i是从0开始构建14. 非递归构建二叉树下面是以非递归方式构建二叉树:var root; function createBinaryTree() { var len = charecters.length, //数组的长度 index = 0, //索引从0开始 nodes = new Array(); //创建一个临时数组,用于存放二叉树节点 //循环创建二叉树节点存放到数组中 for (var i = 0 ; i < charecters.length ; i++) { var node = new Node(); node.text = charecters[i]; nodes.push(node); } //循环建立二叉树子节点的引用 while(index < len) { var leftIndex = 2*index+1, //当前节点左孩子索引 rightIndex = 2*index+2; //当前节点右孩子索引 //给当前节点添加左孩子 nodes[index].leftChild = nodes[leftIndex]; //给当前节点添加右孩子 nodes[index].rightChild = nodes[rightIndex]; index++; } root = nodes[0]; }15.二叉树的三种遍历好了,现在我们已经成功构建了二叉树的链式结构,在构建了二叉树的链式结构后我们进入二叉树的最基本的遍历了,遍历有三种最基本的遍历,我不说想必大家都知道,先序遍历,中序遍历和后续遍历。虽然这三种遍历递归方式都比较简单,但非递归方式就不是那么容易了,当时我在实现的时候都卡了半天,真的是说起来容易做起来难啊,在实现遍历前我们首先要来实现的是栈,因为在非递归遍历的时候会用到栈,那到底什么是栈呢,这里我就简单介绍下吧,有兴趣的朋友可以去维基百科有权威的定义,栈和队列也是一种数据结构,栈存放数据的时候是先进先出,而队列是先进后出。16.实现栈的对象下面用javascript来实现栈的对象function Stack() { var stack = new Array(); //存放栈的数组 //压栈 this.push = function(o) { stack.push(o); }; //出栈 this.pop = function() { var o = stack[stack.length-1]; stack.splice(stack.length-1, 1); return o; }; //检查栈是否为空 this.isEmpty = function() { if(stack.length <= 0) { return true; } else { return false; } }; } //使用方式如下 var stack = new Stack(); stack.push(1); //现在栈中有一个元素 stack.isEmpty(); //false , 栈不为空 alert(stack.pop()); //出栈, 打印1 stack.isEmpty(); //true, 此时栈为空,因为在调用了stack.pop()之后元素出栈了,所以为空17. 先序遍历在实现了栈对象以后我们首先来进行先序遍历的递归方式function firstIteration(node) { if(node.leftChild) { //判断当前节点是否有左孩子 firstIteration(node.leftChild); //递归左孩子 } if(node.rightChild) { //判断当前节点是否有右孩子 firstIteration(node.rightChild); //递归右孩子 } } //递归遍历二叉树 firstIteration(root);18. 先序遍历的非递归方式上面的代码大家可以在firstIteration()方法中加个alert()函数来验证是否正确。那么下面就要说说先序遍历的非递归方式,遍历思想是这样的:先访问根节点在访问左节   点, 最后访问右节点。从根节点一直往下访问找左孩子节点,直到最后一个左孩子节点(将这条路径保存到栈中),然后再访问最后一个左孩子的兄弟节点(右孩子节点),之后回溯到上一层(将栈中的元素取出 就是出栈),又开始从该节点(回溯到上一层的节点)一直往下访问找左孩子节点… 直到栈中的元素为空,循环结束。function notFirstIteration(node) { var stack = new Stack(), //开辟一个新的栈对象 resultText = ''; //存放非递归遍历之后的字母顺序 stack.push(root); //这个root在上面非递归方式构建二叉树的时候已经构建好的 var node = root; resultText += node.text; while(!stack.isEmpty()) { while(node.leftChild) { //判断当前节点是否有左孩子节点 node = node.leftChild; //取当前节点的左孩子节点 resultText += node.text; //访问当前节点 stack.push(node); //将当前节点压入栈中 } stack.pop(); //出栈 node = stack.pop().rightChild; //访问当前节点的兄弟节点(右孩子节点) if(node) { //当前节点的兄弟节点不为空 resultText += node.text; //访问当前节点 stack.push(node); //将当前节点压入栈中 } else { //当前节点的兄弟节点为空 node = stack.pop(); //在回溯到上一层 } } } //非递归先序遍历 notFirstIteration(root);19.中序遍历只要把思路理清楚了现实起来其实还是挺容易的,只要我们熟悉了一种二叉树的非递归遍历方式,其他几种非递归方式就容易多了,照着葫芦画瓢,下面是中序遍历的递归  方式,中序遍历的思想是:先访问左孩子节点,在访问根节点,最后访问右节点var strText = ""; function secondIteration(node) { //访问左节点 if(node.leftChild) { if(node.leftChild.leftChild) { secondIteration(node.leftChild); } else { strText += node.leftChild.text; } } //访问根节点 strText += node.text; //访问右节点 if(node.rightChild) { if(node.rightChild.leftChild) { secondIteration(node.rightChild); } else { strText += node.rightChild.text; } } } secondIteration(root); alert(strText);20. 中序遍历的非递归方式思想是:1. 从根节点一直往下找左孩子节点,直到找到最后一个左孩子节点(用栈将此路径保存,但不访问)2.访问最后一个左孩子节点,然后再  访问根节点(要先弹出栈,就是在栈中取上一层节点)3.在访问当前节点(最后一个左孩子节点)的兄弟节点(右孩子节点),这里要注意如果兄弟节点是一个叶节点就直  接访问,否则是兄弟节点是一颗子树的话不能马上访问,要先来重复 1, 2,3步骤, 直到栈为空,循环结束function notSecondIteration() { var resultText = '', stack = new Stack(), node = root; stack.push(node); while(!stack.isEmpty()) { //从根节点一直往下找左孩子节点直到最后一个左孩子节点,然后保存在栈中 while(node.leftChild) { node = node.leftChild; stack.push(node); } //弹出栈 var tempNode = stack.pop(); //访问临时节点 resultText += tempNode.text; if(tempNode.rightChild) { node = tempNode.rightChild; stack.push(node); } } alert(resultText); }21. 后续遍历最后就还剩下一种遍历方式,二叉树的后续遍历,后续遍历的思想是:先访问左孩子节点,然后在访问右孩子节点,最后访问根节点22. 后续遍历的递归方式var strText = ''; function lastIteration(node) { //首先访问左孩子节点 if(node.leftChild) { if(node.leftChild.leftChild) { lastIteration(node.leftChild); } else { strText += node.leftChild.text; } } //然后再访问右孩子节点 if(node.rightChild) { if(node.rightChild.rightChild) { lastIteration(node.rightChild); } else { strText += node.rightChild.text; } } //最后访问根节点 strText += node.text; } //中序递归遍历 lastIteration(root); alert(strText);23.后续非递归遍历后续非递归遍历的思想是:1.从根节点一直往下找左孩子节点,直到最后一个左孩子节点(将路径保存到栈中,但不访问)2.弹出栈访问最后一个左孩子节点 3.进入最后一  个左孩子节点的兄弟节点,如果兄弟节点是叶节点就访问它,否则将该节点重复 1, 2步骤, 直到栈中的元素为空,循环结束。3.访问根节点function notLastIteration() { var strText = '', stack = new Stack(); nodo = root; stack.push(node); while(!stack.isEmpty()) { while(node.leftChild) { node = node.leftChild; stack.push(node); } //弹出栈 var tempNode = stack.pop(); //访问左孩子节点 strText += tempNode.text; //访问右孩子节点 if(tempNode.rightChild) { if(tempNode.rightChild.leftChild || tempNode.rightChild.rightChild) { //判断最后一个左孩子节点的兄弟节点是否为页节点 stack.push(tempNode.rightChild); } else { strText += tempNode.rightChild.text; } } } alert(strText); }24. 已知前序和中序构建二叉树<script> let qianxu = [ 1,2,4,7,3,5,6,8 ]; let zhongxu = [ 4,7,2,1,5,3,8,6 ]; function TreeNode( val ){ this.val = val; this.left = null; this.right = null; } function rebuildTree(qianxu,zhongxu){ if (qianxu[0]){ // 1. 根据找到的根节点( 前序序列的第一个元素一定是根节点 ) let rootVal = qianxu[0]; // 2. 找到根节点和中序序列,找到树的左子树和右子树 // 根节点在中序序列中的位置 let index = zhongxu.indexOf( rootVal ); // 前序序列:左子树 qianxu(1,index),右子树qianxu(index+1,最后) // 中序序列:左子树 zhongxu(0,index-1),右子树 zhongxu(index+1,最后) let leftTree = rebuildTree(qianxu.slice(1,index+1),zhongxu.slice(0,index)); let rightTree = rebuildTree(qianxu.slice(index+1),zhongxu.slice(index+1)); let root = new TreeNode(rootVal); root.right = rightTree; root.left = leftTree; return root; } } console.log(rebuildTree(qianxu,zhongxu)); </script>25. 栈转化成队列<script> let stack1 = []; let stack2 = []; function push(node){ stack1.push(node); } function pop (){ while(stack1.length){ stack2.push(stack1.pop()); } let popVal = stack2.pop(); while(stack2.length){ stack1.push(stack2.pop()); } return popVal; } /** * 1,2,3,4,5 入队 * 出队操作 1 * 入队 6 * 出队操作2 * 出队操作3 */ push(1); push(2); push(3); push(4); push(5); console.log(pop()); </script>26.跳台阶(典型递归)一只青蛙一次可以跳上一级台阶,也可以跳上两级求该青蛙上一个n级的台阶总共有多少中跳法(向后次序不同算不同结果)<script> function jumpFloor(n){ if(n==1) return 1; else if(n==2) return 2; return jumpFloor(n-1)+jumpFloor(n-2); } console.log(jumpFloor(3)); </script>算法优化用空间换时间;(加缓存)(记忆化递归)<script> // 记忆化递归 let cache = [,1,2]; function jumpFloor2(n){ if(cache[n] !==undefined) return cache[n]; return cache[n] = jumpFloor(n-1)+jumpFloor(n-2); } console.log(jumpFloor2(3)); </script>一只青蛙一次可以跳上一级台阶,也可以跳上两级…它也可以跳上n级;求该青蛙上一个n级的台阶总共有多少中跳法(向后次序不同算不同结果)f(n)=f(n-1)+f(n-2)+…+f(2)+f(1)+1<script> let cache = [,1,2]; function jumpFloor(n){ if(cache[n] !== undefined) return cache[n]; cache[n] = 1; for(let i = n-1;i >=1;i--){ cache[n] += jumpFloor(i); } return cache[n]; } console.log(jumpFloor(10)); </script>27. 反转链表写一个函数,输入一个链表,反转练表后,输出新链表的表头。<script> function Node(val){ this.val = val; this.next = null; } function creatList(arr){ let head = new Node(arr[0]); let tail = head; for(let i =1;i<=arr.length-1;i++){ tail.next = new Node(arr[i]); tail = tail.next; } return head; } let list = creatList([1,2,3,4,5]); // console.log(list); function reverseList (head){ let arr = []; let p = head; while(p){ arr.push(p.val); p = p.next; } p = head; while(p){ p.val = arr.pop(p.val); p = p.next; } return head; } console.log(reverseList(list)); </script>28. 字典树需求:10 创建一个字典树,在字典树中查找是否包含某个单词1112 单词序列:13 and14 about15 as16 boy17 by18 because19 as2021 查找:22 close false23 an false24 as true25 boy true2627 字典树是什么28 字典树又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。30 字典树的作用31 统计,排序和保存大量的字符串33 字典树的特点34 1、字典树的节点存储的是单词的字符(字母)35 2、为了表示一个单词是否出现,我们可以给单词的最后的字符加上标记36 3、字典树中表示一个单词用的是一条链37 4、字典树的根节点没有什么意义39 字典树的操作40 1、把单词插入到字典树里面去41 2、在字典树中查找单词45 1、把单词插入到字典树里面去46 算法步骤:47 去跟节点下面去找这个单词的第一个字符是否出现,48 如果没出现,就创建,然后走这条路,49 如果出现了,就直接走这条路50 (在这个过程里面,单词的第一个字符就被消耗掉了)52 算法:53 递归56 2、在字典树中查找单词57 算法:58 递归60 算法步骤:61 查找单词的第一个字符是否在根节点的子节点中,如果出现了,就接着往下找62 如果没出现,直接return false63 在单词找完后,如果标记大于1,表示单词出现过,就return true,64 否则return falseNodeJS一:Node 好处: 处理高并发 事件驱动 轻量 要用于搭建高性能的web服务器,1. 它是一个Javascript运行环境2. 依赖于Chrome V8引擎进行代码解释3. 事件驱动4. 非阻塞I/O5. 轻量、可伸缩,适于实时数据交互应用6. 单进程,单线程二:Express 和 koa的区别?异步 摆脱回调地域对response 和request进行了封装 contentExpress主要基于Connect中间件框架,功能丰富,随取随用,并且框架自身封装了大量便利的功能,比如路由、视图处理等等。而koa主要基于co中间件框架,框架自身并没集成太多功能,大部分功能需要用户自行require中间件去解决,但是由于其基于ES6 generator特性的中间件机制,解决了长期诟病的“callback hell”和麻烦的错误处理的问题,大受开发者欢迎。三:事件驱动模型和事件循环:事件驱动模型:当服务端收到请求时,就把它关闭 然后处理下一个请求 当第一个请求处理完毕后 就放回处理队列 当达到队列开头 将结果返回给用户 好处:高效 扩展性强 因为服务端一直接受请求 不等待任何读写操作事件循环:查看队列里面是否有队列里面有待处理的 如果有 交给主线程执行四:Redis:使用场景:支持string、list、set、zset和hash类型数据。配合关系型数据库做高速缓存缓存高频次访问的数据,降低数据库io分布式架构,做session共享可以持久化特定数据。利用zset类型可以存储排行榜利用list的自然时间排序存储最新n个数据五:mysql 和mongodb的区别mysql 关系型数据库 mongodb是非关系数据库(主要)六:MySQL索引七:闭包应该注意的地方八:进程和线程进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位进程是线程的容器十:mysql存储引擎 和区别InnoDB存储引擎:事务型数据库首选,支持事务安全表(ACID),支持行锁定和外键 是mysql 5.5之后的默认引擎MyISAM 存储引擎:不支持事务和外键,访问速度较快,是mysql5.5 之前的默认引擎MEMORY: 保存在内存中的数据表 ,每个memory表对应一个磁盘文件。格式是.frm 访问速度很快 缺点是:mysql服务关闭,数据丢失,另外对数据表大小有限制。十一:如何判断一个字符串是另一个字符串的子串indexof es6:include startWith endWith十二:单点登录十三:oauth2.0十四:type of 和instance of 区别十五:pm2 restart 和reload的区别(配置文件的重载 重启)十六:MySQL 读写分离十七:pm2如何查看指定三个项目的日志十八:深拷贝 浅拷贝十九:路由机制二十:MySQL 批量更新二十一:登录流程二十二:cookie 和session二十三:基本数据类型 引用数据类型 区别二十四:防止sql 注入1.使用escape() 对传入参数进行编码2.使用connection.query ()的查询参数占位符3.使用escapeId()编码SQL查询标识符4.使用mysql.format()转义参数:二十五:require()模块加载机制先判断是否存在文件缓存区中,存在直接导入,没有的话,在判断是否是原生模块,如果是原生模块,再看是否在原生模块缓存区中,如果有直接导入,没有的话加载原生模块,缓存原生模块,在导入如果不是原生模块,先查找文件模块,根据扩展名载入文件模块,缓存文件模块,在导入[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rujkgYx7-1611887935898)(C:\Users\zjx\Desktop\桌面文件\web面试\1.jpg)]第1题, 什么是nodejs?我们在哪里使用它?Nodejs是服务器端的一门技术。它是基于Google V8 JavaScript引擎而开发的。用来开发可扩展的服务端程序。第2题,为什么要使用node js?nodejs会让我们的编程工作变得简单,它主要包含如下几点几个好处:执行快速。永远不会阻滞。JavaScript是通用的编程语言。异步处理机制。避免并行所带来的问题。第3题,nodejs有哪些特点?是单线程的,但是有很高的可扩展性,使用JavaScript作为主流编程语言。使用的是异步处理机制和事件驱动。处理高效。第4题, Set immediate和set time out 区别在哪里?Set immediate就是马上执行的意思。Set time out, 时间参数传为0,也想获得同样的功能。只不过前者要快一些。第5题,如何更新nodejs的版本?npm install npm -g第6题,为什么nodejs是单线程的?Nodejs使用的是单线程没错,但是通过异步处理的方式,可以处理大量的数据吞吐量,从而有更好的性能和扩可扩展性。第7题,什么是回调函数?回调函数是指用一个函数作为参数传入另一个函数,这个函数会被在某个时机调用。第8题, 什么叫做回调地狱?回调地狱是由嵌套的回调函数导致的。这样的机制会导致有些函数无法到达,并且很难维护。第9题,如何阻止回调地狱?有三种方法, 对每个错误都要处理到, 保证代码的贯通, 程序代码模块化。第10题,解释一下repl的作用?Read evaluate print loop, 用于测试,调试和实验用。第11题,API函数的类型有哪些?有两种,一种是阻滞型函数。阻滞型函数会等待操作完成以后再进行下一步。另外一种是非阻滞型函数。这种函数使用回调函数来处理当前函数获取的结果。第12题,回调函数的第1个参数是什么?通常是错误对象。如果这个参数为空,表示没有错误。第13题,NPM的作用是什么?Node package manager, 主要有两个功能。它是一个网端模块的存储介质。它的另一个作用是安装程序依赖和版本管理。第14题,nodejs和ajax的区别是什么?Nodejs和ajax也就是asynchronous JavaScript and xml,都是通过JavaScript来表现的,但是他们的目的截然不同。Ajax是设计用来动态的更新页面的某个区域,从而不需要更新整个页面。Nodejs是用来开发客户服务器类型应用的。第15题,解释一下nodejs中chaining.Chaining是指从一个数据流到另一个数据流的链接,从而实现多个流操作。第16题,什么是streams?解释一下有哪些类型?流的概念是不间断的,它可以不间断的从某个地方读取数据,或者向某个地方写入数据。有4种类型的流数据。可读,可写。既可读,又可写,转化。第17题,退出代码是什么?有哪些退出代码?退出代码是指中断nodejs运行时返回的代码。有这么几种unused, uncaught fatal exception, fatal error, non function internal exception handler, internal exception handler run time failure,internal JavaScript evaluation failure.第18题, 什么是globals?有三个global的关键字。Global代表的是最上层的命名空间,用来管理所有其他的全局对象。Process 是一个全局对象,可以把异步函数转化成异步回调, 它可以在任何地方被访问,它主要是用来返回系统的应用信息和环境信息.Buffer, 是用来处理二进制数据的类.第19题, Angular js和node js的区别是什么?Angular js是网络应用开发框架,而nodejs是一个实时系统。第20题, 为什么统一的风格儿非常重要,有什么工具可以保证这一点?统一的风格可以让所有的组成员按照一种规矩来写代码。工具有Standard和eslint.第21题, 用什么方法来处理没有被处理的异常?在应用和node js之间使用domain来处理这样的异常。第22题, Node js是如何支持多处理器平台的?Cluster模块是用来支持这方面的。它可以允许多个nodejs工作进程运行在相同的端口上。第23题, 如何配置开发模式和生产模式的环境?首先有一个配置文件,然后通过环境变量参数来获取对应的配置内容。第24题, nodejs中跟时间相关的函数有哪些?Set time out, clear time out.Set interval, clear interval.Set immediate, clear immediate.Process.nextTick.第25题, 解释一下什么是reactor pattern。Reactor pattern主要是非阻滞的i/o操作。提供一个回调函数来关联io操作。io请求完成以后会不会提交给demultiplexer, 这是一个通知接口用来处理并发性的非阻滞的io操作,这个功能是通过查询一个event loop来实现的.第26题,lts版本是什么意思?也就是long term support版本。至少会被支持18个月。使用的是偶数来标识。这种版本有稳定性和安全性的保证。第27题,你为什么需要把express APP和server分开?分开以后方便维护以及测试,在测试某个模块的时候,尤其是APP模块的时候,你不需要去对网络方面的连接配置做工作。第28题,next tick和setImmediate的区别是什么?Next tick会等待当前的event执行完成或者下一轮儿事件循环到达再执行。Set immediate, 会在下一轮的事件循环中,执行回调并且返回当前的循环来做读写操作.第29题,apply, call和bind有什么区别?参考答案:三者都可以把一个函数应用到其他对象上,注意不是自身对象.apply,call是直接执行函数调用,bind是绑定,执行需要再次调用.apply和call的区别是apply接受数组作为参数,而call是接受逗号分隔的无限多个参数列表,代码演示function Person() { } Person.prototype.sayName() { alert(this.name); } var obj = {name: 'michaelqin'}; // 注意这是一个普通对象,它不是Person的实例 1) apply Person.prototype.sayName.apply(obj, [param1, param2, param3]); 2) call Person.prototype.sayName.call(obj, param1, param2, param3); 3) bind var sn = Person.prototype.sayName.bind(obj); sn([param1, param2, param3]); // bind需要先绑定,再执行 sn(param1, param2, param3); // bind需要先绑定,再执行二)、node全局对象3. node有哪些核心模块?参考答案: EventEmitter, Stream, FS, Net和全局对象1. node有哪些全局对象?参考答案: process, console, Buffer2. process有哪些常用方法?参考答案: process.stdin, process.stdout, process.stderr, process.on, process.env, process.argv, process.arch, process.platform, process.exit3. console有哪些常用方法?参考答案: console.log/console.info, console.error/console.warning, console.time/console.timeEnd, console.trace, console.table4. node有哪些定时功能?参考答案: setTimeout/clearTimeout, setInterval/clearInterval, setImmediate/clearImmediate, process.nextTick5. node中的事件循环是什么样子的?总体上执行顺序是:process.nextTick >> setImmidate >> setTimeout/SetInterval 看官网吧:[https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/](https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/)6. node中的Buffer如何应用?参考答案: Buffer是用来处理二进制数据的,比如图片,mp3,数据库文件等.Buffer支持各种编码解码,二进制字符串互转.三)、EventEmitter1. 什么是EventEmitter?参考答案: EventEmitter是node中一个实现观察者模式的类,主要功能是监听和发射消息,用于处理多模块交互问题.2. 如何实现一个EventEmitter?参考答案: 主要分三步:定义一个子类,调用构造函数,继承EventEmitter代码演示var util = require('util'); var EventEmitter = require('events').EventEmitter; function MyEmitter() { EventEmitter.call(this); } // 构造函数 util.inherits(MyEmitter, EventEmitter); // 继承 var em = new MyEmitter(); em.on('hello', function(data) { console.log('收到事件hello的数据:', data); }); // 接收事件,并打印到控制台 em.emit('hello', 'EventEmitter传递消息真方便!');3. EventEmitter有哪些典型应用?参考答案:模块间传递消息回调函数内外传递消息处理流数据,因为流是在EventEmitter基础上实现的.观察者模式发射触发机制相关应用4. 怎么捕获EventEmitter的错误事件?参考答案: 监听error事件即可.如果有多个EventEmitter,也可以用domain来统一处理错误事件.代码演示var domain = require('domain'); var myDomain = domain.create(); myDomain.on('error', function(err){ console.log('domain接收到的错误事件:', err); }); // 接收事件并打印 myDomain.run(function(){ var emitter1 = new MyEmitter(); emitter1.emit('error', '错误事件来自emitter1'); emitter2 = new MyEmitter(); emitter2.emit('error', '错误事件来自emitter2'); });5. EventEmitter中的newListenser事件有什么用处?参考答案: newListener可以用来做事件机制的反射,特殊应用,事件管理等.当任何on事件添加到EventEmitter时,就会触发newListener事件,基于这种模式,我们可以做很多自定义处理.代码演示var emitter3 = new MyEmitter(); emitter3.on('newListener', function(name, listener) { console.log("新事件的名字:", name); console.log("新事件的代码:", listener); setTimeout(function(){ console.log("我是自定义延时处理机制"); }, 1000); }); emitter3.on('hello', function(){ console.log('hello node'); });四)、Stream1. 什么是Stream?参考答案: stream是基于事件EventEmitter的数据管理模式.由各种不同的抽象接口组成,主要包括可写,可读,可读写,可转换等几种类型.2. Stream有什么好处?参考答案: 非阻塞式数据处理提升效率,片断处理节省内存,管道处理方便可扩展等.3. Stream有哪些典型应用?参考答案: 文件,网络,数据转换,音频视频等.4. 怎么捕获Stream的错误事件?参考答案: 监听error事件,方法同EventEmitter.5. 有哪些常用Stream,分别什么时候使用?参考答案: Readable为可被读流,在作为输入数据源时使用;Writable为可被写流,在作为输出源时使用;Duplex为可读写流,它作为输出源接受被写入,同时又作为输入源被后面的流读出.Transform机制和Duplex一样,都是双向流,区别时Transfrom只需要实现一个函数_transfrom(chunk, encoding, callback);而Duplex需要分别实现_read(size)函数和_write(chunk, encoding, callback)函数.6. 实现一个Writable Stream?参考答案: 三步走:1)构造函数call Writable 2) 继承Writable 3) 实现_write(chunk, encoding, callback)函数代码演示var Writable = require('stream').Writable; var util = require('util'); function MyWritable(options) { Writable.call(this, options); } // 构造函数 util.inherits(MyWritable, Writable); // 继承自Writable MyWritable.prototype._write = function(chunk, encoding, callback) { console.log("被写入的数据是:", chunk.toString()); // 此处可对写入的数据进行处理 callback(); }; process.stdin.pipe(new MyWritable()); // stdin作为输入源,MyWritable作为输出源五)、文件系统1. 内置的fs模块架构是什么样子的?参考答案: fs模块主要由下面几部分组成: 1) POSIX文件Wrapper,对应于操作系统的原生文件操作 2) 文件流 fs.createReadStream和fs.createWriteStream 3) 同步文件读写,fs.readFileSync和fs.writeFileSync 4) 异步文件读写, fs.readFile和fs.writeFile2. 读写一个文件有多少种方法?参考答案: 总体来说有四种: 1) POSIX式低层读写 2) 流式读写 3) 同步文件读写 4) 异步文件读写3. 怎么读取json配置文件?参考答案: 主要有两种方式,第一种是利用node内置的require(‘data.json’)机制,直接得到js对象; 第二种是读入文件入内容,然后用JSON.parse(content)转换成js对象.二者的区别是require机制情况下,如果多个模块都加载了同一个json文件,那么其中一个改变了js对象,其它跟着改变,这是由node模块的缓存机制造成的,只有一个js模块对象; 第二种方式则可以随意改变加载后的js变量,而且各模块互不影响,因为他们都是独立的,是多个js对象.4. fs.watch和fs.watchFile有什么区别,怎么应用?参考答案: 二者主要用来监听文件变动.fs.watch利用操作系统原生机制来监听,可能不适用网络文件系统; fs.watchFile则是定期检查文件状态变更,适用于网络文件系统,但是相比fs.watch有些慢,因为不是实时机制.六)、网络1. node的网络模块架构是什么样子的?参考答案: node全面支持各种网络服务器和客户端,包括tcp, http/https, tcp, udp, dns, tls/ssl等.2. node是怎样支持https,tls的?参考答案: 主要实现以下几个步骤即可: 1) openssl生成公钥私钥 2) 服务器或客户端使用https替代http 3) 服务器或客户端加载公钥私钥证书3. 实现一个简单的http服务器?参考答案: 经典又很没毛意义的一个题目.思路是加载http模块,创建服务器,监听端口.代码演示var http = require('http'); // 加载http模块 http.createServer(function(req, res) { res.writeHead(200, {'Content-Type': 'text/html'}); // 200代表状态成功, 文档类型是给浏览器识别用的 res.write('<meta charset="UTF-8"> <h1>我是标题啊!</h1> <font color="red">这么原生,初级的服务器,下辈子能用着吗?!</font>'); // 返回给客户端的html数据 res.end(); // 结束输出流 }).listen(3000); // 绑定3ooo, 查看效果请访问 http://localhost:3000七)、child-process1. 为什么需要child-process?参考答案: node是异步非阻塞的,这对高并发非常有效.可是我们还有其它一些常用需求,比如和操作系统shell命令交互,调用可执行文件,创建子进程进行阻塞式访问或高CPU计算等,child-process就是为满足这些需求而生的.child-process顾名思义,就是把node阻塞的工作交给子进程去做.2. exec,execFile,spawn和fork都是做什么用的?参考答案: exec可以用操作系统原生的方式执行各种命令,如管道 cat ab.txt | grep hello; execFile是执行一个文件; spawn是流式和操作系统进行交互; fork是两个node程序(javascript)之间时行交互.3. 实现一个简单的命令行交互程序?参考答案: 那就用spawn吧.代码演示var cp = require('child_process'); var child = cp.spawn('echo', ['你好', "钩子"]); // 执行命令 child.stdout.pipe(process.stdout); // child.stdout是输入流,process.stdout是输出流 // 这句的意思是将子进程的输出作为当前程序的输入流,然后重定向到当前程序的标准输出,即控制台4. 两个node程序之间怎样交互?参考答案: 用fork嘛,上面讲过了.原理是子程序用process.on, process.send,父程序里用child.on,child.send进行交互.代码演示1) fork-parent.js var cp = require('child_process'); var child = cp.fork('./fork-child.js'); child.on('message', function(msg){ console.log('老爸从儿子接受到数据:', msg); }); child.send('我是你爸爸,送关怀来了!'); 2) fork-child.js process.on('message', function(msg){ console.log("儿子从老爸接收到的数据:", msg); process.send("我不要关怀,我要银民币!"); });5. 怎样让一个js文件变得像linux命令一样可执行?参考答案: 1) 在myCommand.js文件头部加入 #!/usr/bin/env node 2) chmod命令把js文件改为可执行即可 3) 进入文件目录,命令行输入myComand就是相当于node myComand.js了6. child-process和process的stdin,stdout,stderror是一样的吗?参考答案: 概念都是一样的,输入,输出,错误,都是流.区别是在父程序眼里,子程序的stdout是输入流,stdin是输出流.九、node高级话题(异步,部署,性能调优,异常调试等)1. node中的异步和同步怎么理解参考答案: node是单线程的,异步是通过一次次的循环事件队列来实现的.同步则是说阻塞式的IO,这在高并发环境会是一个很大的性能问题,所以同步一般只在基础框架的启动时使用,用来加载配置文件,初始化程序什么的.2. 有哪些方法可以进行异步流程的控制?参考答案: 1) 多层嵌套回调 2) 为每一个回调写单独的函数,函数里边再回调 3) 用第三方框架比方async, q, promise等3. 怎样绑定node程序到80端口?参考答案: 多种方式 1) sudo 2) apache/nginx代理 3) 用操作系统的firewall iptables进行端口重定向4. 有哪些方法可以让node程序遇到错误后自动重启?参考答案: 1) runit 2) forever 3) nohup npm start &5. 怎样充分利用多个CPU?参考答案: 一个CPU运行一个node实例6. 怎样调节node执行单元的内存大小?参考答案: 用–max-old-space-size 和 --max-new-space-size 来设置 v8 使用内存的上限7. 程序总是崩溃,怎样找出问题在哪里?参考答案: 1) node --prof 查看哪些函数调用次数多 2) memwatch和heapdump获得内存快照进行对比,查找内存溢出8. 有哪些常用方法可以防止程序崩溃?参考答案: 1) try-catch-finally 2) EventEmitter/Stream error事件处理 3) domain统一控制 4) jshint静态检查 5) jasmine/mocha进行单元测试9. 怎样调试node程序?参考答案: node --debug app.js 和node-inspector10. 如何捕获NodeJS中的错误,有几种方法? 参考答案: 1) 监听错误事件req.on(‘error’, function(){}), 适用EventEmitter存在的情况; 2) Promise.then.catch(error),适用Promise存在的情况 3) try-catch,适用async-await和js运行时异常,比如undefined object十、 常用知名第三方类库(Async, Express等)1. async都有哪些常用方法,分别是怎么用?参考答案: async是一个js类库,它的目的是解决js中异常流程难以控制的问题.async不仅适用在node.js里,浏览器中也可以使用.1). async.parallel并行执行完多个函数后,调用结束函数async.parallel([ function(){ ... }, function(){ ... } ], callback);2). async.series串行执行完多个函数后,调用结束函数async.series([ function(){ ... }, function(){ ... } ]);3). async.waterfall依次执行多个函数,后一个函数以前面函数的结果作为输入参数async.waterfall([ function(callback) { callback(null, 'one', 'two'); }, function(arg1, arg2, callback) { // arg1 now equals 'one' and arg2 now equals 'two' callback(null, 'three'); }, function(arg1, callback) { // arg1 now equals 'three' callback(null, 'done'); } ], function (err, result) { // result now equals 'done' });4). async.map异步执行多个数组,返回结果数组async.map(['file1','file2','file3'], fs.stat, function(err, results){ // results is now an array of stats for each file });5). async.filter异步过滤多个数组,返回结果数组async.filter(['file1','file2','file3'], fs.exists, function(results){ // results now equals an array of the existing files });2. express项目的目录大致是什么样子的参考答案: app.js, package.json, bin/www, public, routes, views.3. express常用函数参考答案: express.Router路由组件,app.get路由定向,app.configure配置,app.set设定参数,app.use使用中间件4. express中如何获取路由的参数参考答案: /users/:name使用req.params.name来获取; req.body.username则是获得表单传入参数username; express路由支持常用通配符 ?, +, *, and ()5. express response有哪些常用方法参考答案: res.download() 弹出文件下载res.end() 结束responseres.json() 返回jsonres.jsonp() 返回jsonpres.redirect() 重定向请求res.render() 渲染模板res.send() 返回多种形式数据res.sendFile 返回文件res.sendStatus() 返回状态十一、其它相关后端常用技术(MongoDB, Redis, Apache, Nginx等)1. mongodb有哪些常用优化措施参考答案: 类似传统数据库,索引和分区.2. mongoose是什么?有支持哪些特性?参考答案: mongoose是mongodb的文档映射模型.主要由Schema, Model和Instance三个方面组成.Schema就是定义数据类型,Model就是把Schema和js类绑定到一起,Instance就是一个对象实例.常见mongoose操作有,save, update, find. findOne, findById, static方法等.3. redis支持哪些功能参考答案: set/get, mset/hset/hmset/hmget/hgetall/hkeys, sadd/smembers, publish/subscribe, expire4. redis最简单的应用参考答案:var redis = require("redis"), client = redis.createClient(); client.set("foo_rand000000000000", "some fantastic value"); client.get("foo_rand000000000000", function (err, reply) { console.log(reply.toString()); }); client.end();5. apache,nginx有什么区别?参考答案: 二者都是代理服务器,功能类似.apache应用简单,相当广泛.nginx在分布式,静态转发方面比较有优势.HTTP状态码200 - 请求成功301 - 资源(网页等)被永久转移到其它URL404 - 请求的资源(网页等)不存在500 - 内部服务器错误
文章
存储  ·  缓存  ·  移动开发  ·  JavaScript  ·  前端开发  ·  搜索推荐  ·  NoSQL  ·  关系型数据库  ·  API  ·  HTML5
2022-05-23
金鱼哥RHCA回忆录:CL210集成身份管理--管理身份服务令牌
个人简介:大家好,我是 金鱼哥,CSDN运维领域新星创作者,华为云·云享专家,阿里云社区·专家博主个人资质:CCNA、HCNP、CSNA(网络分析师),软考初级、中级网络工程师、RHCSA、RHCE、RHCA、RHCI、ITIL格言:努力不一定成功,但要想成功就必须努力支持我:可点赞、可收藏⭐️、可留言身份验证令牌身份服务通过插件配置指定的身份验证过程以确认用户的身份,然后向该用户提供表示用户身份的令牌。典型的用户令牌是有范围的,这意味着它列出了可能使用它的资源和访问权限。令牌的生命周期有限,允许用户在令牌过期或被撤销之前执行服务请求,而无需进行进一步的身份验证。限定范围的令牌列出用户的权限和特权,就像在与当前项目相关的角色中定义的那样。当用户向OpenStack服务发出请求时,服务根据用户提供的角色验证所请求的资源访问,然后允许或拒绝所请求的服务。 任何用户都可以使用openstack token issue命令来请求当前限定范围的令牌,并在输出中显示用户id、项目和新令牌过期时间。此令牌类型实际上是三种授权范围类型中的一种:未限定作用域、项目限定作用域和域限定作用域。因为域是Identity Service v3中支持的新特性,所以早期的文档可能只引用限定作用域和未限定作用域的令牌,其中作用域是基于项目的。(token:确认用户的身份之后,会给用户提供一个核实身份并且可以用于后续资源请求的令牌,token服务则验证并管理用于验证身份的令牌。keystone会颁发给通过认证服务的用户两种类型的令牌,一类是无明确访问范围的令牌(unscoped token),此种类型的令牌存在的主要目的是用来保存用户的credential,可以基于此令牌获取有确定访问范围的令牌(scoped token)。虽然意义不大,但是keystone还是保留了基于unscoped token查询project列表的功能,用户选择要访问的project,继而可以获取与project或者域绑定的令牌,只有通过与某个特定项目或者域相绑定的令牌,才可以访问此项目或者域内的资源。令牌只在有限的时间内有效。)未限定作用域未限定作用域的令牌是仅用于身份验证的令牌,不包含项目、角色或服务信息有效负载。例如, 未限定作用域令牌可以使用身份验证身份提供商提供的其他服务,如LDAP,RADIUS,或AD服务器的令牌是用于验证身份服务,然后交流未限定作用域令牌认证用户的适当范围的令牌。未限定范围的令牌也可以称为身份服务默认令牌,它与项目或域没有关联,可以交换限定范围的令牌。项目限定作用域项目范围的令牌提供使用单个项目的资源在服务端点上执行操作的授权,允许由该项目中的用户角色指定的活动。这些令牌包含相关的服务目录、角色和作为有效负载的项目信息,并被认为与特定的项目相关联。域限定作用域域范围的令牌应用于发生在域级别的服务。而不是在项目或用户层面。这种类型的令牌具有包含域服务目录的有效负载,并且仅限于不需要每个项目端点的服务。令牌有效负载还包含指定域中用户的特性和角色信息。提供令牌令牌提供程序有四种类型:UUID、PKI、PKIZ和最新的提供程序Fernet。所有令牌都由一个有效负载组成,以JSON或随机生成的UUID格式。包含在传输格式中,例如url友好的十六进制或加密消息语法(CMS)打包。OpenStack的默认令牌提供程序更改了几次,因为OpenStack开发人员试图解决令牌大小、安全性和性能问题。UUID令牌UUID令牌是原始和默认令牌提供者直到Red Hat OpenStack 2。它们是随机生成的32字节的UUID,必须持久地存储在身份服务的配置后端中,以允许身份服务在每次用户向任何服务端点发出服务请求时验证UUID。尽管uuid是轻量级的,并且易于通过简单的查找进行验证,但它们有两个缺点首先,因为UUID令牌必须由身份服务后端保留以进行重复查找,所以所使用的存储空间随着新令牌的生成而增长。直到最近,过期的令牌还没有从后端存储中清除,导致服务性能随时间下降。其次,每个单独的服务API调用必须将请求和令牌捆绑在一起发送到服务组件,在服务组件中,服务解包UUID并向身份服务发送验证请求。身份服务查找令牌的身份以确定用户的角色和授权,然后将信息发送回资源服务,以确定服务组件是否将处理用户请求。这将产生大量的网络流量和来往于身份服务的活动,这就造成了伸缩性限制。PKI 和 PKIZ 令牌Public Key Infrastructure (PKI)令牌是在Red Hat OpenStack 3中引入的,作为一种解决方案,它可以减少身份服务后端上的规模限制开销,并通过使用证书和密钥签名和验证令牌来提高令牌的安全性。PKI使用JSON有效负载、非对称密钥和加密消息语法(CMS)传输格式。PKIZ令牌在JSON有效负载签名后应用zlib压缩以缩小总令牌大小,通常超过1600字节。有效负载包含服务目录,其大小通常与目录中服务条目的数量成比例由于使用公钥方法,PKI令牌的优点是请求资源服务组件能够验证和读取有效负载授权,而无需为每个请求将令牌发送回身份服务。要处理请求令牌,所请求的服务只需要获得身份服务的签名证书、当前的撤销列表和验证签名证书的CA公共证书。经过验证和未编码的令牌和有效负载使用Memcached存储和共享,消除了一些重复的令牌处理开销。PKI令牌提供者方法的缺点是由于过大的共享缓存,身份服务后端增加的负载以及与处理大型负载令牌相关的其他问题而导致无法接受的性能。PKI令牌需要更长的时间来创建和验证UUID令牌。因此,UUID令牌取代了PKI和PKIZ令牌,再次成为推荐的令牌提供程序。PKI和PKIZ令牌支持在Mitaka版本中被弃用,在Ocata版本中被删除。Fernet令牌Fernet令牌是一种对称密钥加密认证方法的实现,使用相同的密钥进行加密和解密,专为处理服务APl请求令牌而设计。Fernet支持使用多个密钥,始终使用列表中的第一个密钥(当前密钥)来执行加密,然后尝试使用早期密钥和暂存密钥(计划成为当前)来执行解密。这种技术允许周期性地轮转Fernet密钥以提高安全性,同时仍然允许用以前密钥创建的令牌被解密。 Fernet令牌不超过250字节,并且不会持久存在于身份服务后端。Fernet令牌有效负载使用MessagePack二进制序列化格式有效地进行身份验证和授权的元数据,然后再进行加密和签名。Fernet令牌不需要持久性,也不需要维护。因为它们是在任何能够访问Fernet对称密钥的身份服务节点上即时创建和验证的。对称的密钥在密钥存储库中的所有身份服务节点上存储和共享,该密钥存储库默认位于/etc/keystone/fernet-keys/。在Kilo版本中引入了Fernet令牌提供程序,并成为Ocata版本中的默认令牌提供程序。在早期的OpenStack开发人员文档中,这些令牌被称为已验证加密(AE)令牌。注意:所有这些令牌提供程序(UUID、PKI、PKIZ和Fernet)被称为承载令牌,这意味着持有令牌的任何人都可以模拟该令牌中表示的用户,而不必提供任何身份验证凭证。持有者令牌必须受到保护,避免不必要的披露,以防止未经授权的访问。令牌管理令牌提供程序在正确安装和配置之后,通常需要最少的管理任务。UUID令牌需要按要求刷新过期令牌。PKI令牌提供者需要维护证书,过期、撤消以及持久存储的管理。为了安全起见,Fernet令牌需要按规定轮转密钥。在多节点HA部署中,将密钥存储库分配到所有身份服务节点。因为Fernet令牌现在是默认的令牌提供程序,所以本节只讨论Fernet令牌管理任务。Fernet密钥Fernet令牌不需要持久性,但是为了验证Fernet令牌,所有身份服务节点必须能够访问Fernet对称密钥。因为记号应该被替换为了最小化创建模拟的Fernet令牌的能力,Fernet令牌提供程序使用一个轮转方法来使用新的对称密钥,而不破坏解密使用前一个密钥创建的Fernet令牌的能力。 Fernet根据轮转中每个键的索引数字来命名它的密钥。它将这些密钥存储在一个密钥库中,这个库默认是控制节点上的/var/lib/config-data/puppet-generated/keystone/etc/keystone/fernet-keys目录。Fernet在轮转过程中使用了三种类型的密钥。主密钥主密钥被认为是当前密钥。在一个身份服务节点上只能识别一个主键,因为它的文件名总是具有最高的索引号。主密钥用于加密和解密Fernet令牌。次要密钥次要密钥是一种密钥,以前是主密钥,已经被替换(轮转),它只用于解密Fernet令牌:具体地说,就是对原先加密过的任何剩余的Fernet令牌进行解密。一个副密钥的文件用一个比最高密钥低的索引来命名,但是它的索引从不为0次密钥次密钥是一个新添加的密钥,当这些密钥下一次轮转时,它将成为下一个主密钥。与次要密钥类似,它只用于解密令牌,这似乎是不必要的,因为它没有审查为主密钥,而且从来没有在身份服务节点上加密令牌。然而,在一个多码身份服务配置中,在密钥存储库用一个新的次密钥更新并分发到所有身份服务节点之后,这些节点将一次执行一个密钥轮转。可能需要一个节点上的暂存密钥来解密另一个节点创建的令牌(该密钥已经成为主密钥)。暂存密钥总是通过索引为0的文件名重新编码可参考别人文章的分享:https://www.cnblogs.com/dhplxf/p/7966890.html轮转Fernet密钥默认情况下,overcloud的Fernet管理由Director使用Mistral来执行。管理员应该使用Mistral来启动Fernet键的轮转。当以这种方式初始化时,Mistral将存储Fernet 密钥,并且这些密钥将跨堆栈更新持久化。 要启动Fernet键轮转,执行相关的Mistral工作流tripleo.fernet_keys.v1.rotate_fernet_keys,作为控制器上的stack用户。使用工作流执行输出中显示的ID,查询工作流执行的状态。当工作流执行完成时,工作流执行的状态将显示为成功。完成Fernet密钥轮转后,检查控制节点上/var/lib/confiq-data/puppet -generated/keystone/etc/keystone/Fernet -keys目录的内容。您将看到从0开始的编号文件列表。编号的文件名表示每个文件中包含的密钥的索引。以0索引命名的文件包含新的暂存密钥。以最高索引作为文件名的文件包含新的主密钥。所有其他名称在最高和最低索引之间的文件都包含次要密钥。Fernet密钥轮转频率对Fernet 密钥的强制轮转限制了攻击者使用折衷密钥获得对OpenStack环境的非授权访问的风险。但是,如果密钥轮转得太频繁。有可能无意中删除了解密有效令牌所需的次要密钥。为了将密钥的移除限制为不再用于令牌加密和解密的密钥,管理员需要在身份服务确认文件中正确确认Fernet令牌参数:第二个重要参数是max_active_keys,它位于身份服务配置文件的fernet_tokens内容之下。这个参数决定了在任何给定的时间有多少fernet密钥可以同时活动。您可以使用以下命令来显示它的值:Fernet密钥轮转的时间间隔不能超过令牌到期时间除以小于max_active_keys值的2。因此,在我们的示例中,当令牌过期时间为57600秒,且最多有5个活动的Fernet密钥时,我们不应该比每19200秒或者5小时20分钟轮转Fernet密钥更频繁。如果需要更频繁的轮换。然后,需要依次修改令牌过期参数、max_active_keys参数或两者,以确保对未过期的Fernet令牌进行加密或解密时,不会无意间删除所需的密钥。课本练习启动Fernet密钥轮转。验证Fernet密钥轮转。[student@workstation ~]$ lab identity-tokens setup Setting up environment for the exercise: • Verifying environment....................................... SUCCESS1. 使用crudini命令来确定overcloud是否使用Fernet令牌。[root@controller0 ~]# crudini --get /var/lib/config-data/puppet-generated/keystone/etc/keystone/keystone.conf token provider fernet [root@controller0 ~]# [root@controller0 ~]# crudini --get /var/lib/config-data/puppet-generated/keystone/etc/keystone/keystone.conf token driver sql2. 使用crudini命令确定Fernet密钥存储库的位置,以及活动的Fernet密钥的最大数量。[root@controller0 ~]# crudini --get /var/lib/config-data/puppet-generated/keystone/etc/keystone/keystone.conf fernet_tokens key_repository /etc/keystone/fernet-keys [root@controller0 ~]# crudini --get /var/lib/config-data/puppet-generated/keystone/etc/keystone/keystone.conf fernet_tokens max_active_keys 53.显示激活的Fernet密钥的列表。[root@controller0 ~]# ll /var/lib/config-data/puppet-generated/keystone/etc/keystone/fernet-keys/ total 8 -rw-------. 1 42425 42425 44 Oct 23 2018 0 -rw-------. 1 42425 42425 44 Oct 23 2018 14. 显示活动的Fernet密钥文件的内容。该文件不以换行符结束,因此使用cat命令和echo命令可以更容易地查看关键文件的内容。[root@controller0 ~]# cat /var/lib/config-data/puppet-generated/keystone/etc/keystone/fernet-keys/0; echo y9f0YApLj1Z7BGBQyxjgF58RMga78y-DBNMR-cd9r2w= [root@controller0 ~]# [root@controller0 ~]# cat /var/lib/config-data/puppet-generated/keystone/etc/keystone/fernet-keys/1; echo d9w1tgQhBMWxHOVZ12fB1l2imFcris4UHB-ToPOG4aM=5. 轮转Fernet密钥。执行Mistral工作流以启动Fernet密钥的轮转。(undercloud) [stack@director ~]$ openstack workflow execution create tripleo.fernet_keys.v1.rotate_fernet_keys '{"container": "overcloud"}' +--------------------+-------------------------------------------+ | Field | Value | +--------------------+-------------------------------------------+ | ID | 8b5dd66e-fcc7-4e94-8c35-47572fe509ee | | Workflow ID | c00289f9-612a-4744-b94a-a24d8e89736b | | Workflow name | tripleo.fernet_keys.v1.rotate_fernet_keys | | Workflow namespace | | | Description | | | Task Execution ID | <none> | | State | RUNNING | | State info | None | | Created at | 2020-10-19 07:30:42 | | Updated at | 2020-10-19 07:30:42 | +--------------------+-------------------------------------------+等待两分钟左右,然后查看工作流执行的状态。使用前一个命令输出中显示的工作流执行ID。当状态显示成功时继续。(undercloud) [stack@director ~]$ openstack workflow execution show 8b5dd66e-fcc7-4e94-8c35-47572fe509ee +--------------------+-------------------------------------------+ | Field | Value | +--------------------+-------------------------------------------+ | ID | 8b5dd66e-fcc7-4e94-8c35-47572fe509ee | | Workflow ID | c00289f9-612a-4744-b94a-a24d8e89736b | | Workflow name | tripleo.fernet_keys.v1.rotate_fernet_keys | | Workflow namespace | | | Description | | | Task Execution ID | <none> | | State | SUCCESS | | State info | None | | Created at | 2020-10-19 07:30:42 | | Updated at | 2020-10-19 07:33:35 | +--------------------+-------------------------------------------+6. 返回到controllero系统并在repository目录中列出活动的Fernet密钥。[root@controller0 ~]# ll /var/lib/config-data/puppet-generated/keystone/etc/keystone/fernet-keys/ total 12 -rw-------. 1 42425 42425 44 Oct 19 07:32 0 -rw-------. 1 42425 42425 44 Oct 19 07:32 1 -rw-------. 1 42425 42425 44 Oct 19 07:33 27. 显示活动的Fernet密钥文件的内容。[root@controller0 ~]# cat /var/lib/config-data/puppet-generated/keystone/etc/keystone/fernet-keys/0; echo _OeHKlsDRYpiG9Gf0RqRxePa7ZIWolSEr1tns7dsfS8= [root@controller0 ~]# cat /var/lib/config-data/puppet-generated/keystone/etc/keystone/fernet-keys/1; echo d9w1tgQhBMWxHOVZ12fB1l2imFcris4UHB-ToPOG4aM= [root@controller0 ~]# cat /var/lib/config-data/puppet-generated/keystone/etc/keystone/fernet-keys/2; echo y9f0YApLj1Z7BGBQyxjgF58RMga78y-DBNMR-cd9r2w=8. 观察密钥文件注意,上一个分段密钥文件0的内容现在已经轮转到索引最高的密钥文件2中。现在是主密钥。还要注意,上一个主密钥文件1的内容现在位于索引第二高的密钥文件1中,并且现在是次密钥。最后,请注意,暂存密钥文件0现在包含一个新的暂存密钥。清除实验[student@workstation ~]$ lab identity-tokens cleanup总结RHCA认证需要经历5门的学习与考试,还是需要花不少时间去学习与备考的,好好加油,可以噶。以上就是【金鱼哥】对 第三章 集成身份管理--管理身份服务令牌 的简述和讲解。希望能对看到此文章的小伙伴有所帮助。红帽认证专栏系列:RHCSA专栏:戏说 RHCSA 认证RHCE专栏:戏说 RHCE 认证此文章收录在RHCA专栏:RHCA 回忆录如果这篇【文章】有帮助到你,希望可以给【金鱼哥】点个赞,创作不易,相比官方的陈述,我更喜欢用【通俗易懂】的文笔去讲解每一个知识点。如果有对【运维技术】感兴趣,也欢迎关注❤️❤️❤️ 【金鱼哥】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】!
文章
存储  ·  JSON  ·  缓存  ·  运维  ·  安全  ·  Linux  ·  API  ·  数据安全/隐私保护  ·  数据格式  ·  索引
2022-07-18
前端面试+学习笔记(HTML+CSS+JavaScript+ES6+Vue+NodeJs)
前端面试+学习笔记(HTML+CSS+JavaScript+ES6+Vue+NodeJs)一. HTML1. 盒子模型是什么:每个元素被表示为一个矩形的盒子,有四个部分组成:内容(content)、内边距(padding)、边框(border)、外边距(margin)。它在页面中所占的实际大小(宽高)是content+padding+border+margin之和。盒模型有两种:标准盒模型(W3C盒模型)、IE盒模型。两种盒模型的区别:标准盒模型内容大小就是content大小、而IE盒模型内容大小则是content+padding+border总的大小。**怎么设置两种盒模型:**通过设置box-sizing属性为content-box(默认值:标准盒模型)、border-box(IE盒模型)。JS怎么获取和设置box的宽高。box-sizing使用场景:若设置子元素的margin或border时可能会撑破父元素的尺寸,就需要使用box-sizing:border-box来将border包含进元素的尺寸中。2.页面导入样式时,使用link和@import有什么区别**link属于XHTML标签,**除了加载CSS外,还能用于定义RSS(简易信息聚合,是一种基于XML标准,在互联网上被广泛采用的内容包装和投递协议)rel连接属性等作用;@import是CSS提供的;只能用于加载CSS页面被加载时,link会同时被加载;而@import引用的CSS会等到页面被加载完成后再加载link是XHTML标签,没有兼容问题;而@import只有在IE5以上才能被识别link支持使用JavaScript控制DOM修改样式;而@import不支持。4.行内元素有哪些?块级元素有哪些?空元素(void)有哪些?**行内元素:**a,b,span,img,input,strong,label,button,select,textarea,em**块级元素:**div,ul(无序列表),ol,li,dl(自定义列表),dt(自定义列表项),dd(自定义列表项的定义),p,h1-h6,blockquote(块引用)空元素(void):即没有内容的HTML元素。br(换行),hr(水平分割线),meta,link,input,img5. src 和 herf 的区别href是指向网络资源所在位置,建立和当前(锚点)或当前文档(链接)之间的连接,用于超链接。src执行外部资源的位置,指向的内容会嵌入到文档中当前标签所在位置,在请求src资源时会将其指向的资源下载并应用到文档中。当浏览器解析到该元素时,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕。(性能优化)6. 为什么CSS样式放在头部,JS脚本放在底部浏览器为了更好的用户体验,渲染引擎会尝试尽快在屏幕上显示内容,不会等到所有的HTML元素解析之后在构建和布局DOM树,所以部分内容将被解析并显示。前端一般主要关心首屏的渲染速度,这也是为什么要提倡“图片懒加载”的原因。**其实外部的js和CSS文件时并行下载的。**随着JS技术的发展,JS也开始承担起页面的渲染工作了。如果JS加载需要很长时间,会影响用户体验。所以需要将JS区分为承担页面渲染工作的JS和承担事件处理的JS。渲染页面的JS放在前面,事务处理的JS放在后面。7.常用浏览器,内核Trident内核:(国产的绝大部分浏览器)IE,360,搜狗**Gecko内核:**Firefox,NetScape6及以上**Presto内核:**Opera7及以上Webkit内核:(国产大部分双核浏览器其中一核)Safari(苹果),Chrome浏览器内核:主要分成两部分:渲染引擎和JS引擎。最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎**渲染引擎:**负责取得网页内容(HTML,XML,图像等)、整理讯息(加入CSS等),以及计算网页的显示方式,后会输出至显示器或打印机。JS引擎:解析和执行JavaScript来实现网页的动态效果。8. DOCTYPE作用?严格模式与混杂模式 , 标准模式和怪异模式声明位于HTML文档中的第一行,处于标签之前,告知浏览器的解析器用什么文档标准解析这个文档。严格模式下,排版和JS以浏览器支持的最高标准运行;**混杂模式下,**页面以宽松向后兼容的方式显示**如何触发混杂模式:**DOCTYPE不存在或格式不正确,会导致文档以混合模式呈现**标准模式(standards mode)**是指浏览器按照W3C标准解析执行代码;**怪异模式(quirks mode)**则是使用浏览器自己的方式解析执行代码。浏览器解析时到底使用何种模式,与网页中的DTD声明(文档类型定义,DOCTYPE相关)有关,忽略DTD声明,将使网页进入怪异模式。9.优雅降级和渐进增强渐进增强(progressive enhancement):针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。优雅降级(graceful degradation):一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。区别:优雅降级是**从复杂的现状开始,并试图减少用户体验的供给;渐进增强则是从一个非常基础的,**能够起作用的版本开始,并不断扩充,以适应未来环境的需要。渐进增强观点认为应该关注于内容本身,这使得渐进增强成为一种更为合理的设计范例;优雅降级观点认为应该针对那些最高级、最完善的浏览器来设计网站。10. 对HTML语义化的理解用正确的标签做正确的事情HTML语义化让页面的内容结构化,结构更清晰,便于对浏览器、搜索引擎解析即使在没有样式CSS情况下也以一种文档格式显示,并且是易于阅读的搜索引擎的爬虫也依赖于HTML标记来确定上下文和各个关键字的权重,利于SEO使阅读源代码的人更容易将网站分块,便于阅读维护理解二. CSS1.CSS选择符,优先级**选择符:**id(ID);class(类);element(标签);element element(后代);element>element(子);element,element(群组);element+element(相邻同胞);伪类(:link,:visited,:active,:hover,:focus:first-child,:lang(language));伪元素(:first-letter,:first-line,:before,:after);属性选择器**可继承的选择符:**主要是文本方面的可继承,盒模型相关的属性基本没有继承特性。font-size,font-family,color,ul**不可继承的选择符:**border,padding,margin,width,height**优先级:**同权重下样式定义最近者高。!important>内联样式 即定义在HTML标签内的样式,(1000)>id(100)>class/伪类/属性(10)>伪元素/element(1)**CSS引入伪类和伪元素的原因:**用来修饰DOM树以外的部分。伪类用于当已有元素处于某个状态时,为其添加对应的样式,这个状态根据用户行为而动态变化。伪类的操作对象是DOM树中已有的元素。伪元素用于创建一些不在DOM树中的元素,并为其添加样式伪类和伪元素的区别在于有没有创建一个DOM树之外的元素2. 外边距重叠(collapsing margins)/margin坍塌**是什么:**相邻的两个或多个普通流中的块元素,如果它们设置了外边距,那么在垂直方向上,外边距会发生重叠,以绝对值大的那个为最终结果显示在页面上,即最终的外边距等于发生层叠的外边距中绝对值较大者。**最终外边距:**margin全为正(取最大值)、margin全为负(取绝对值最大的负数)、margin有正有负(分别取正数最大值a,负数的最大绝对值b,a-b)**外边距重叠的应用:**几个段落一起布局,第一个段落的上外边距正常显示,下外边距与第二个段落的上外边距重叠。防止外边距重叠:创建BFC元素。不会发生外边距重叠的情况:行内元素、浮动元素、绝对定位元素之间的外边距都不会叠加。3. BFC(Block Formatting Context,块级格式化上下文)**是什么:**决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。简言之,就是一个特殊的块,内部的元素和外部的元素不会相互影响。BFC内的盒子会在垂直方向上一个接一个地放置,垂直方向上也会发生外边距重叠。**应用场景:**自适应布局(BFC不与float box重叠)、清除浮动(计算BFC的高度时,内部的浮动元素也被计算在内)、防止外边距重叠如何触发BFC:float属性(不为none)、overflow属性(不为visible)、position属性(absolute,fixed)、display属性(inline-block,table-cell,table-caption,flex,inline-flex)。4.元素的position属性**定义:**规定元素的定位类型。**正常文档流:**指的是没有用CSS样式去控制的HTML文档结构,代码的顺序就是网页展示的顺序。**脱离文档流:**指的是元素所显示的位置和文档代码不一致。**static:**默认值。没有定位,元素出现在正常的文档流中。**relative:**生成相对定位的元素,相对于其在正常文档流中的位置进行定位(不脱离文档流)。**absolute:**生成绝对定位的元素,相对于static定位以外的最近父级元素进行定位,即相对于其直接父级元素(脱离文档流)。absolute较少直接单独使用在正常的文档流中,主要运行于进行了相对定位的元素框架层里面,相对该层的左上点进行偏移。**fixed:**生成固定定位元素,相对于浏览器窗口进行定位。**inherit:**从父元素继承position属性的值。**z-index属性:**使用了relative、absolute、fixed三种定位后,都会使正常的文档流发生一定程度的改变,造成元素出现重叠的情形。为了能让重叠的元素有序的显示出来,需要在定位的相关元素加上z-index属性。其值是一个整数值,默认为0,数值越大表示拥有的优先级越高,该属性只对使用了定位的元素有效。5.元素的display属性**定义:**规定元素应该生成的框的类型常用属性值:**inline:**默认值。元素会被显示为内联元素。**none:**元素不会被显示。**block:**元素将显示为块级元素。**inline-block:**行内块元素,即元素像行内元素一样显示,内容像块元素一样显示。**list-item:**元素像块元素一样显示,并添加样式列表标记。**table:**元素会作为块级表格来显示。**table-caption:**元素会作为一个表格标题显示。**inherit:**从父元素继承display属性。display属性值inline和block的区别:block元素会独占一行,默认情况下,block元素宽度自动填满父级元素的宽度;block元素可以设置width、height属性,即使设置了宽度,仍然是独占一行;block元素可以设置margin和padding属性;inline元素不会独占一行,多个相邻的行内元素会排列在同一行里面,其宽度随元素的内容而变化;inline元素设置width、height无效;inline元素的margin和padding属性在水平方向上能产生边距效果,垂直方向不会产生边距效果。display:inline-block元素显示间隙inline-block水平呈现的元素之间,HTML元素标签换行显示或标签之间有空格的情况下会有间距消除办法:移除标签之间的空格;使用margin-left或margin-right取负值;对父元素设置font-size为0,然后对元素的font-size初始化;对父元素设置letter-spacing(字符间距)为负值,然后设置元素的letter-spacing为0;对父元素设置word-spacing(单词间距)为负值,然后设置元素的word-spacing为0。7.overflow属性**定义:**规定当内容溢出元素框时发生的事情**visible:**默认值。内容不会被修剪,会呈现在元素框之外**hidden:**内容会被修剪,并且其余内容不可见**scroll:**内容被修剪,但浏览器会显示滚动条以便查看其余内容**auto:**如果内容被修剪,则浏览器会显示滚动条以便查看其余内容inherit:从父元素继承overflow属性的值8. 初始化CSS样式**为什么要初始化CSS样式:**因为浏览器的兼容问题,不同浏览器对有些标签的默认值时不同的,如果没有对CSS初始化往往会出现浏览器之间页面显示差异。最简单的方法:*{margin:0;padding:0;}**初始化CSS的缺点:**对SEO(搜索引擎优化)有一定的影响。SEO:Search Engine Optimization,搜索引擎的优化。SEO具体是指通过网站结构调整、网站内容建设、网站代码优化以及站外优化,使网站满足搜索引擎的收录排名需求,提高网站在搜索引擎中关键字的排名,从而吸引精准用户进入网站,获得免费流量,产生直接销售或品牌推广。**什么是CSS Hack:**一般来说针对不同的浏览器写不同的CSS,就是CSS Hack。9.CSS属性cursor?cursor属性规定要显示的鼠标的光标类型。常用取值:pointer(手),crosshair(十字线),default(箭头),auto(浏览器设置的光标)HTML5一. HTML5 新特性1. HTML5新特性:主要是关于图像、位置、存储、多任务等功能的增加。包括:绘画canvas(通过脚本实现绘画)用于媒介回放的video和audio元素本地离线存储localStorage、sessionStorage语义化更好的内容元素:article、footer、header、nav、section表单元素:datalist(规定输入域的选项列表)、output(用于不同元素的输出)、keygen(提供一种验证用户的可靠方法)input类型:color、date、month、week、number、email(检测是否为一个email格式的地址)、range(滑动条)、search、url、tel(输入电话号码,-time选择时间)2. HTML5新标签的浏览器兼容问题:当在页面中使用HTML5新标签时,可能会得到三种不同的结果:新标签被当做错误处理并被忽略,在DOM构建时会当做这个标签不存在新标签被当做错误处理,在DOM构建时,这个新标签会被构造成行内元素新标签被识别成HTML5标签,然后用DOM节点对齐进行替换3.解决兼容性问题:**实现标签被识别。**通过document.createElement(tagName)即可让浏览器识别新标签,浏览器支持新标签后,还可以为其添加CSS样式JavaScript解决方案:使用html5shim。在中调用以下代码(也可下载到本地后调用):<!--[if It IE 9]> <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> <![endif]-->使用kill IE6<!--[if It IE 6]> <script src="http://letskillie6.googlecode.com/svn/trunk/letskillie6.an_CN.pack.js"></script> <![endif]-->4. 如何区分HTML和HTML5:DOCTYPE声明新增的元素5. HTML5移除的元素:**纯表现的元素:**big,center,font,strike(删除线),u(下划线),s(删除线)**对可用性产生负面影响的元素:**frame,frameset,noframes6.iframe的缺点会阻塞主页面的onload事件搜索引擎的检索程序无法解读这种页面,不利于SEO二. cookie和localStorage的区别1.共同点:cookie、sessionStorage和localStorage都是由浏览器存储在本地的数据。区别:cookie是网站为了标识用户身份而存储在用户本地终端上的数据(通常经过加密),数据始终在同源的http请求中携带,即在浏览器和服务器之间来回传递;localStorage不会自动把数据发给服务器,尽在本地保存cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下,存储大小也不同,cookie数据不能超过4K,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据(如会话标识);localStorage也有存储大小的限制,但比cookie大很多,可以达到5M或更大。cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭;localStorage始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;sessionStorage在当前浏览器窗口关闭之后自动删除localStorage支持**事件通知机制,**可以将数据更新的通知发送给监听者,API接口使用更方便;cookie的原生接口不友好,需要程序员自己封装**localStorage如何删除数据:**localStorage对象可以将数据长期保存在客户端,除非人为清除,提供了以下几个方法:**存储:**localStorage.setItem(key,value) 如果key存在,更新value**获取:**localStorage.getItem(key) 如果key不存在,则返回null**删除:**localStorage.removeItem(key) 一旦删除,key对应的数据将会全部删除全部清除:localStorage.clear()使用removeItem逐个删除太麻烦,可以使用**clear,**执行的结果是清除所有的localStorage对象保存的数据localStorage存储的数据是不能跨浏览器共用的,一个浏览器只能读取各自浏览器的数据。CSS3一. CSS3新特性1. 新特性边框:border-radius(圆角)、box-shadow(阴影)、border-image(边框图片)背景:background-size(背景图片的尺寸)、background-origin(背景图片的定位区域)文本效果:text-shadow(文本阴影)、word-wrap(文本换行)转换和变形:transform(包括2D,3D转换,rotate(angle),translate(x,y),scale(x,y))过渡:transition动画:animation多列:column-count(元素被分隔的列数)、column-gap(列之间的间隔)、column-rule(洌之间的宽度,样式,颜色规则)用户界面:resize(规定是否可由用户调整元素尺寸)、box-sizing(以确切的方式适应某个区域的具体内容)、outline-offset(对轮廓进行偏移)2. 新增伪类:element:before(在元素之前添加内容) element:after(在元素之后添加内容)element:first-of-type、element:last-of-type、element:only-of-type、element:only-child、element:nth-child(n)(第n个):checked、:disabled、:enabled3. 四个锚点伪类的设置问题:**问题描述:**超链接访问后hover样式就不出现了,被点击访问过的超链接样式不再具有hover和active**解决办法:**爱恨原则LoVe/HAte。改变CSS属性的排列顺序,L-V-H-A 即a:link{} a:visited() a:hover{} a:active{}4.transition、transform和animation的区别transform是指转换,可以将元素移动、旋转、倾斜、拉伸。没有变化的过程。而transition和animation都加上了时间属性,所以能产生动画效果transition是指过渡,一般由行为(hover等)触发;而animation则是自动触发transition只能设置头尾,所有样式属性一起变化;animation可以设定每一帧的样式和时间,且可以循环播放。5.rgba和opacity的区别?rgba和opacity都能实现透明效果,但最大的不同在于opacity作用于元素本身以及元素内的所有内容,而rgba只作用于元素本身,子元素不会继承透明效果。**rgba是CSS3的属性,**用法说明:rgba(R,G,B,A),参数说明R(红色值。正整数|百分数),G(绿色值。正整数|百分数),B(蓝色值。正整数|百分比),A(Alpha透明度。0(透明)~1)。IE6-8不支持rgba模式,可以使用IE滤镜处理:filter:progid:DXImageTransform.Microsoft.Gradient(startColorstr=#AARRGGBBAA,endColorstr=#AARRGGBBAA);其中AA,RR,GG,BB分别表示Alpha,R,G,B,取值为00-FF。opacity也是CSS3的属性,用法说明:opacity:value 其中value取值0(透明)~1。对于IE6-8,可以用IE滤镜处理:filter:alpha(opacity=50); /对应于opacity:0.5;浮动一. 清除浮动父级div定义height结尾处加空div标签,样式clear:both父级div定义伪类:after和zoom通过CSS伪元素在容器的内部元素最后添加了一个看不见的空格"020"或点".",并且赋予clear属性来清除浮动。需要注意的是为了IE6和IE7浏览器,要给clearfix这个class添加一条zoom:1;触发haslayout。父级div定义overflow:hidden(同时还要定义width或zoom:1,不能定义height)父级div定义overflow:auto(同时还要定义width或zoom:1,不能定义height)父级也浮动,需要定义width(不推荐)父级div定义display:table(不推荐)结尾处加br标签,样式clear:both(父元素div定义zoom:1,不推荐)二. 属性clear取值1. 定义:规定元素的那一侧不允许其他浮动元素2. 取值none:(默认值)。允许浮动元素left:在左侧不允许浮动元素right:在右侧不允许浮动元素both:在左右侧均不允许浮动元素inherit:从父元素继承clear属性三. 属性zoom取值1. 定义:设置或检索对象的缩放比例2.取值normal:(默认值),使用对象的实际尺寸:用浮点数来定义缩放比例,不允许负值:用百分比来定义缩放比例,不允许负值新的注意点:一. 重排(reflow) 与重绘(repaint)浏览器从下载文档到显示页面的过程是个复杂的过程,这里包含了重绘和重排重绘是一个元素外观的改变所触发的浏览器行为(例如改变visibility,outline,background等属性),浏览器会根据元素的新属性重新绘制,是元素呈现新的外观。**重排时更明显的一种改变,可以理解为渲染树需要重新计算。**常见的触发重排的操作:DOM元素的几何属性变化DOM树的结构变化(例如节点的增减、移动)获取某些属性(例如offsetTop,offsetLeft,offsetHeight,offsetWidth,clientWidth,clientHeight等)改变元素的一些样式(例如调整浏览器窗口大小)重绘不会带来重新布局,并不一定伴随着重排。在实践中,应该尽量减少重排次数和缩小重排的影响范围。有以下几种方法:将多次改变样式属性的操作合并成一次操作将需要多次重排的元素,position属性设为absolute或fixed,使其脱离文档流,这样它的变化就不会影响到其他元素在内存中多次操作节点,完成后再添加到文档中去如果要对一个元素进行复杂的操作,可以将其display属性设置为none使其隐藏,待操作完成后再显示在需要经常获取那些引起浏览器重排的属性值时,要缓存到变量如何在网页中添加空格? 在HTML代码中输入 二. 如何在网页中显示代码?对于单行代码,使用标签<code>代码</code>对于多行代码,使用标签<pre></pre> (被包围在pre元素中的文本通常会保留空格和换行符)26.使用mailto在网页中链接Email地址?(1)a标签有一个作用是可以链接Email地址,使用mailto能让访问者便捷想网站管理者发送电子邮件(2)如果mailto后面同时又多个参数的话,第一个参数必须以?开头,后面的参数每一个都以&分隔三. form表单当前页面无刷新提交?使用target属性取值为iframe元素的name属性值。具体如下:在当前页面建一个iframe并隐藏(display:none)给这个iframe取名(name=“id_iframe”)设置form表单的target属性(target=“id_iframe”)提交表单,就是无刷新iframe标签一. 优点iframe能够把嵌入的页面展示出来,如果有多个网页引用iframe,只需要修改iframe的内容,就可以实现调用的每一个页面内容的更改,方便快捷网页如果为了统一风格,头部和版本都是一样的,就可以写成一个页面,用iframe来嵌套,可以增加代码的可重用重载页面时不需要重载整个页面,只需要重载页面中的一个框架页,减少了数据的传输,增加了网页的下载速度方便制作导航栏二. 缺点会产生很多页面,不利于管理浏览器的前进/后退按钮无效无法被一些搜索引擎索引到,现在搜索引擎爬虫还不能很好的处理iframe中的内容,所以不利于SEO多数小型的移动设备无法显示框架,兼容性差多框架的页面会增加服务器的http请求,对于大型网站是不可取的综上,目前框架中的所有优点完全可以使用Ajax实现,因此不推荐使用框架ES6一、问:ES6是什么,为什么要学习它,不学习ES6会怎么样?答: ES6是新一代的JS语言标准,对分JS语言核心内容做了升级优化,规范了JS使用标准,新增了JS原生方法,使得JS使用更加规范,更加优雅,更适合大型应用的开发。学习ES6是成为专业前端正规军的必经之路。不学习ES6也可以写代码打鬼子,但是最多只能当个游击队长。二、问:ES5、ES6和ES2015有什么区别?答: ES2015特指在2015年发布的新一代JS语言标准,ES6泛指下一代JS语言标准,包含ES2015、ES2016、ES2017、ES2018等。现阶段在绝大部分场景下,ES2015默认等同ES6。ES5泛指上一代语言标准。ES2015可以理解为ES5和ES6的时间分界线。三、问:babel是什么,有什么作用?答:babel是一个 ES6 转码器,可以将 ES6 代码转为 ES5 代码,以便兼容那些还没支持ES6的平台。四、问:let有什么用,有了var为什么还要用let?答: 在ES6之前,声明变量只能用var,var方式声明变量其实是很不合理的,准确的说,是因为ES5里面没有块级作用域是很不合理的,甚至可以说是一个语言层面的bug(这也是很多c++、java开发人员看不懂,也瞧不起JS语言的劣势之一)。没有块级作用域回来带很多难以理解的问题,比如for循环var变量泄露,变量覆盖等问题。let 声明的变量拥有自己的块级作用域,且修复了var声明变量带来的变量提升问题。五、问:举一些ES6对String字符串类型做的常用升级优化?答:1、优化部分:ES6新增了字符串模板,在拼接大段字符串时,用反斜杠(`)取代以往的字符串相加的形式,能保留所有空格和换行,使得字符串拼接看起来更加直观,更加优雅。2、升级部分:ES6在String原型上新增了includes()方法,用于取代传统的只能用indexOf查找包含字符的方法(indexOf返回-1表示没查到不如includes方法返回false更明确,语义更清晰), 此外还新增了startsWith(), endsWith(), padStart(),padEnd(),repeat()等方法,可方便的用于查找,补全字符串。六、问:举一些ES6对Array数组类型做的常用升级优化?答:1、优化部分:a. 数组解构赋值。ES6可以直接以let [a,b,c] = [1,2,3]形式进行变量赋值,在声明较多变量时,不用再写很多let(var),且映射关系清晰,且支持赋默认值。b. 扩展运算符。ES6新增的扩展运算符(…)(重要),可以轻松的实现数组和松散序列的相互转化,可以取代arguments对象和apply方法,轻松获取未知参数个数情况下的参数集合。(尤其是在ES5中,arguments并不是一个真正的数组,而是一个类数组的对象,但是扩展运算符的逆运算却可以返回一个真正的数组)。扩展运算符还可以轻松方便的实现数组的复制和解构赋值(let a = [2,3,4]; let b = [...a])。2、升级部分:ES6在Array原型上新增了find()方法,用于取代传统的只能用indexOf查找包含数组项目的方法,且修复了indexOf查找不到NaN的bug([NaN].indexOf(NaN) === -1).此外还新增了copyWithin(), includes(), fill(),flat()等方法,可方便的用于字符串的查找,补全,转换等。七、问:举一些ES6对Number数字类型做的常用升级优化?答:1、优化部分:ES6在Number原型上新增了isFinite(), isNaN()方法,用来取代传统的全局isFinite(), isNaN()方法检测数值是否有限、是否是NaN。ES5的isFinite(), isNaN()方法都会先将非数值类型的参数转化为Number类型再做判断,这其实是不合理的,最造成isNaN('NaN') === true的奇怪行为–'NaN’是一个字符串,但是isNaN却说这就是NaN。而Number.isFinite()和Number.isNaN()则不会有此类问题(Number.isNaN('NaN') === false)。(isFinite()同上)2、升级部分:ES6在Math对象上新增了Math.cbrt(),trunc(),hypot()等等较多的科学计数法运算方法,可以更加全面的进行立方根、求和立方根等等科学计算。八、问:举一些ES6对Object类型做的常用升级优化?(重要)答:1、优化部分:a. 对象属性变量式声明。ES6可以直接以变量形式声明对象属性或者方法,。比传统的键值对形式声明更加简洁,更加方便,语义更加清晰。let [apple, orange] = ['red appe', 'yellow orange']; let myFruits = {apple, orange}; // let myFruits = {apple: 'red appe', orange: 'yellow orange'}; 复制代码尤其在对象解构赋值(见优化部分b.)或者模块输出变量时,这种写法的好处体现的最为明显:let {keys, values, entries} = Object; let MyOwnMethods = {keys, values, entries}; // let MyOwnMethods = {keys: keys, values: values, entries: entries} 复制代码可以看到属性变量式声明属性看起来更加简洁明了。方法也可以采用简洁写法:let es5Fun = { method: function(){} }; let es6Fun = { method(){} } 复制代码b. 对象的解构赋值。 ES6对象也可以像数组解构赋值那样,进行变量的解构赋值:let {apple, orange} = {apple: 'red appe', orange: 'yellow orange'}; 复制代码c. 对象的扩展运算符(…)。 ES6对象的扩展运算符和数组扩展运算符用法本质上差别不大,毕竟数组也就是特殊的对象。对象的扩展运算符一个最常用也最好用的用处就在于可以轻松的取出一个目标对象内部全部或者部分的可遍历属性,从而进行对象的合并和分解。let {apple, orange, ...otherFruits} = {apple: 'red apple', orange: 'yellow orange', grape: 'purple grape', peach: 'sweet peach'}; // otherFruits {grape: 'purple grape', peach: 'sweet peach'} // 注意: 对象的扩展运算符用在解构赋值时,扩展运算符只能用在最有一个参数(otherFruits后面不能再跟其他参数) let moreFruits = {watermelon: 'nice watermelon'}; let allFruits = {apple, orange, ...otherFruits, ...moreFruits}; 复制代码d. super 关键字。ES6在Class类里新增了类似this的关键字super。同this总是指向当前函数所在的对象不同,super关键字总是指向当前函数所在对象的原型对象。2、升级部分:a. ES6在Object原型上新增了is()方法,做两个目标对象的相等比较,用来完善’=‘方法。’='方法中NaN === NaN //false其实是不合理的,Object.is修复了这个小bug。(Object.is(NaN, NaN) // true)b. ES6在Object原型上新增了assign()方法,用于对象新增属性或者多个对象合并。const target = { a: 1 }; const source1 = { b: 2 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3} 复制代码注意: assign合并的对象target只能合并source1、source2中的自身属性,并不会合并source1、source2中的继承属性,也不会合并不可枚举的属性,且无法正确复制get和set属性(会直接执行get/set函数,取return的值)。c. ES6在Object原型上新增了getOwnPropertyDescriptors()方法,此方法增强了ES5中getOwnPropertyDescriptor()方法,可以获取指定对象所有自身属性的描述对象。结合defineProperties()方法,可以完美复制对象,包括复制get和set属性。d. ES6在Object原型上新增了getPrototypeOf()和setPrototypeOf()方法,用来获取或设置当前对象的prototype对象。这个方法存在的意义在于,ES5中获取设置prototype对像是通过__proto__属性来实现的,然而__proto__属性并不是ES规范中的明文规定的属性,只是浏览器各大产商“私自”加上去的属性,只不过因为适用范围广而被默认使用了,再非浏览器环境中并不一定就可以使用,所以为了稳妥起见,获取或设置当前对象的prototype对象时,都应该采用ES6新增的标准用法。d. ES6在Object原型上还新增了Object.keys(),Object.values(),Object.entries()方法,用来获取对象的所有键、所有值和所有键值对数组。九、问:举一些ES6对Function函数类型做的常用升级优化?(重要)答:1、优化部分:a. 箭头函数**(核心)**。箭头函数是ES6核心的升级项之一,箭头函数里没有自己的this,这改变了以往JS函数中最让人难以理解的this运行机制。主要优化点:Ⅰ. 箭头函数内的this指向的是函数定义时所在的对象,而不是函数执行时所在的对象。ES5函数里的this总是指向函数执行时所在的对象,这使得在很多情况下this的指向变得很难理解,尤其是非严格模式情况下,this有时候会指向全局对象,这甚至也可以归结为语言层面的bug之一。ES6的箭头函数优化了这一点,它的内部没有自己的this,这也就导致了this总是指向上一层的this,如果上一层还是箭头函数,则继续向上指,直到指向到有自己this的函数为止,并作为自己的this。Ⅱ. 箭头函数不能用作构造函数,因为它没有自己的this,无法实例化。Ⅲ. 也是因为箭头函数没有自己的this,所以箭头函数 内也不存在arguments对象。(可以用扩展运算符代替)b. 函数默认赋值。ES6之前,函数的形参是无法给默认值得,只能在函数内部通过变通方法实现。ES6以更简洁更明确的方式进行函数默认赋值。function es6Fuc (x, y = 'default') { console.log(x, y); } es6Fuc(4) // 4, default 复制代码2、升级部分:ES6新增了双冒号运算符,用来取代以往的bind,call,和apply。(浏览器暂不支持,Babel已经支持转码)foo::bar; // 等同于 bar.bind(foo); foo::bar(...arguments); // 等同于 bar.apply(foo, arguments); 复制代码十、问:Symbol是什么,有什么作用?答: Symbol是ES6引入的第七种原始数据类型(说法不准确,应该是第七种数据类型,Object不是原始数据类型之一,已更正),所有Symbol()生成的值都是独一无二的,可以从根本上解决对象属性太多导致属性名冲突覆盖的问题。对象中Symbol()属性不能被for…in遍历,但是也不是私有属性。十一、问:Set是什么,有什么作用?答: Set是ES6引入的一种类似Array的新的数据结构,Set实例的成员类似于数组item成员,区别是Set实例的成员都是唯一,不重复的。这个特性可以轻松地实现数组去重。十二、问:Map是什么,有什么作用?答: Map是ES6引入的一种类似Object的新的数据结构,Map可以理解为是Object的超集,打破了以传统键值对形式定义对象,对象的key不再局限于字符串,也可以是Object。可以更加全面的描述对象的属性。十三、问:Proxy是什么,有什么作用?答: Proxy是ES6新增的一个构造函数,可以理解为JS语言的一个代理,用来改变JS默认的一些语言行为,包括拦截默认的get/set等底层方法,使得JS的使用自由度更高,可以最大限度的满足开发者的需求。比如通过拦截对象的get/set方法,可以轻松地定制自己想要的key或者value。下面的例子可以看到,随便定义一个myOwnObj的key,都可以变成自己想要的函数。function createMyOwnObj() { //想把所有的key都变成函数,或者Promise,或者anything return new Proxy({}, { get(target, propKey, receiver) { return new Promise((resolve, reject) => { setTimeout(() => { let randomBoolean = Math.random() > 0.5; let Message; if (randomBoolean) { Message = `你的${propKey}运气不错,成功了`; resolve(Message); } else { Message = `你的${propKey}运气不行,失败了`; reject(Message); } }, 1000); }); } }); } let myOwnObj = createMyOwnObj(); myOwnObj.hahaha.then(result => { console.log(result) //你的hahaha运气不错,成功了 }).catch(error => { console.log(error) //你的hahaha运气不行,失败了 }) myOwnObj.wuwuwu.then(result => { console.log(result) //你的wuwuwu运气不错,成功了 }).catch(error => { console.log(error) //你的wuwuwu运气不行,失败了 }) 复制代码十四、问:Reflect是什么,有什么作用?答: Reflect是ES6引入的一个新的对象,他的主要作用有两点,一是将原生的一些零散分布在Object、Function或者全局函数里的方法(如apply、delete、get、set等等),统一整合到Reflect上,这样可以更加方便更加统一的管理一些原生API。其次就是因为Proxy可以改写默认的原生API,如果一旦原生API别改写可能就找不到了,所以Reflect也可以起到备份原生API的作用,使得即使原生API被改写了之后,也可以在被改写之后的API用上默认的API。十五、问:Promise是什么,有什么作用?答: Promise是ES6引入的一个新的对象,他的主要作用是用来解决JS异步机制里,回调机制产生的“回调地狱”。它并不是什么突破性的API,只是封装了异步回调形式,使得异步回调可以写的更加优雅,可读性更高,而且可以链式调用。十六、问:Iterator是什么,有什么作用?(重要)答: Iterator是ES6中一个很重要概念,它并不是对象,也不是任何一种数据类型。因为ES6新增了Set、Map类型,他们和Array、Object类型很像,Array、Object都是可以遍历的,但是Set、Map都不能用for循环遍历,解决这个问题有两种方案,一种是为Set、Map单独新增一个用来遍历的API,另一种是为Set、Map、Array、Object新增一个统一的遍历API,显然,第二种更好,ES6也就顺其自然的需要一种设计标准,来统一所有可遍历类型的遍历方式。Iterator正是这样一种标准。或者说是一种规范理念。就好像JavaScript是ECMAScript标准的一种具体实现一样,Iterator标准的具体实现是Iterator遍历器。Iterator标准规定,所有部署了key值为[Symbol.iterator],且[Symbol.iterator]的value是标准的Iterator接口函数(标准的Iterator接口函数: 该函数必须返回一个对象,且对象中包含next方法,且执行next()能返回包含value/done属性的Iterator对象)的对象,都称之为可遍历对象,next()后返回的Iterator对象也就是Iterator遍历器。//obj就是可遍历的,因为它遵循了Iterator标准,且包含[Symbol.iterator]方法,方法函数也符合标准的Iterator接口规范。 //obj.[Symbol.iterator]() 就是Iterator遍历器 let obj = { data: [ 'hello', 'world' ], [Symbol.iterator]() { const self = this; let index = 0; return { next() { if (index < self.data.length) { return { value: self.data[index++], done: false }; } else { return { value: undefined, done: true }; } } }; } }; 复制代码ES6给Set、Map、Array、String都加上了[Symbol.iterator]方法,且[Symbol.iterator]方法函数也符合标准的Iterator接口规范,所以Set、Map、Array、String默认都是可以遍历的。//Array let array = ['red', 'green', 'blue']; array[Symbol.iterator]() //Iterator遍历器 array[Symbol.iterator]().next() //{value: "red", done: false} //String let string = '1122334455'; string[Symbol.iterator]() //Iterator遍历器 string[Symbol.iterator]().next() //{value: "1", done: false} //set let set = new Set(['red', 'green', 'blue']); set[Symbol.iterator]() //Iterator遍历器 set[Symbol.iterator]().next() //{value: "red", done: false} //Map let map = new Map(); let obj= {map: 'map'}; map.set(obj, 'mapValue'); map[Symbol.iterator]().next() {value: Array(2), done: false} 复制代码十七、问:for…in 和for…of有什么区别?答: 如果看到问题十六,那么就很好回答。问题十六提到了ES6统一了遍历标准,制定了可遍历对象,那么用什么方法去遍历呢?答案就是用for…of。ES6规定,有所部署了载了Iterator接口的对象(可遍历对象)都可以通过for…of去遍历,而for…in仅仅可以遍历对象。这也就意味着,数组也可以用for…of遍历,这极大地方便了数组的取值,且避免了很多程序用for…in去遍历数组的恶习。上面提到的扩展运算符本质上也就是for…of循环的一种实现。十八、Generator函数是什么,有什么作用?答: 如果说JavaScript是ECMAScript标准的一种具体实现、Iterator遍历器是Iterator的具体实现,那么Generator函数可以说是Iterator接口的具体实现方式。执行Generator函数会返回一个遍历器对象,每一次Generator函数里面的yield都相当一次遍历器对象的next()方法,并且可以通过next(value)方法传入自定义的value,来改变Generator函数的行为。Generator函数可以通过配合Thunk 函数更轻松更优雅的实现异步编程和控制流管理。十九、async函数是什么,有什么作用?答: async函数可以理解为内置自动执行器的Generator函数语法糖,它配合ES6的Promise近乎完美的实现了异步编程解决方案。二十、Class、extends是什么,有什么作用?答: ES6 的class可以看作只是一个ES5生成实例对象的构造函数的语法糖。它参考了java语言,定义了一个类的概念,让对象原型写法更加清晰,对象实例化更像是一种面向对象编程。Class类可以通过extends实现继承。它和ES5构造函数的不同点:a. 类的内部定义的所有方法,都是不可枚举的。///ES5 function ES5Fun (x, y) { this.x = x; this.y = y; } ES5Fun.prototype.toString = function () { return '(' + this.x + ', ' + this.y + ')'; } var p = new ES5Fun(1, 3); p.toString(); Object.keys(ES5Fun.prototype); //['toString'] //ES6 class ES6Fun { constructor (x, y) { this.x = x; this.y = y; } toString () { return '(' + this.x + ', ' + this.y + ')'; } } Object.keys(ES6Fun.prototype); //[] 复制代码b.ES6的class类必须用new命令操作,而ES5的构造函数不用new也可以执行。c.ES6的class类不存在变量提升,必须先定义class之后才能实例化,不像ES5中可以将构造函数写在实例化之后。d.ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。二十一、module、export、import是什么,有什么作用?答: module、export、import是ES6用来统一前端模块化方案的设计思路和实现方案。export、import的出现统一了前端模块化的实现方案,整合规范了浏览器/服务端的模块化方法,用来取代传统的AMD/CMD、requireJS、seaJS、commondJS等等一系列前端模块不同的实现方案,使前端模块化更加统一规范,JS也能更加能实现大型的应用程序开发。import引入的模块是静态加载(编译阶段加载)而不是动态加载(运行时加载)。import引入export导出的接口值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。二十二、日常前端代码开发中,有哪些值得用ES6去改进的编程优化或者规范?答:1、常用箭头函数来取代var self = this;的做法。2、常用let取代var命令。3、常用数组/对象的结构赋值来命名变量,结构更清晰,语义更明确,可读性更好。4、在长字符串多变量组合场合,用模板字符串来取代字符串累加,能取得更好地效果和阅读体验。5、用Class类取代传统的构造函数,来生成实例化对象。6、在大型应用开发中,要保持module模块化开发思维,分清模块之间的关系,常用import、export方法。VUE一、对于MVVM的理解?MVVM 是 Model-View-ViewModel 的缩写。Model代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑。View 代表UI 组件,它负责将数据模型转化成UI 展现出来。ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步View 和 Model的对象,连接Model和View。在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。二、Vue的生命周期beforeCreate(创建前) 在数据观测和初始化事件还未开始created(创建后) 完成数据观测,属性和方法的运算,初始化事件,el属性还没有显示出来 **beforeMount**(载入前) 在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。 **mounted**(载入后) 在el 被新创建的 vm.el属性还没有显示出来∗∗beforeMount∗∗(载入前)在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。∗∗mounted∗∗(载入后)在el被新创建的vm.el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互。beforeUpdate(更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。updated(更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。beforeDestroy(销毁前) 在实例销毁之前调用。实例仍然完全可用。destroyed(销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。1.什么是vue生命周期?答: Vue 实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、销毁等一系列过程,称之为 Vue 的生命周期。2.vue生命周期的作用是什么?答:它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。3.vue生命周期总共有几个阶段?答:它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后。4.第一次页面加载会触发哪几个钩子?答:会触发 下面这几个beforeCreate, created, beforeMount, mounted 。5.DOM 渲染在 哪个周期中就已经完成?答:DOM 渲染在 mounted 中就已经完成了。三、 Vue实现数据双向绑定的原理:Object.defineProperty()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变更双向绑定效果。js实现简单的双向绑定<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>四、Vue组件间的参数传递1.父组件与子组件传值父组件传给子组件:子组件通过props方法接受数据;子组件传给父组件:$emit方法传递参数2.非父子组件间的数据传递,兄弟组件传值eventBus,就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。项目比较小时,用这个比较合适。(虽然也有不少人推荐直接用VUEX,具体来说看需求咯。技术只是手段,目的达到才是王道。)五、Vue的路由实现:hash模式 和 history模式**hash模式:**在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取;特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.xxx.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。**history模式:**history采用HTML5的新特性;且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.xxx.com/items/id。后端如果缺少对 /items/id 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“不过这种模式要玩好,还需要后台配置支持……所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。”六、Vue与Angular以及React的区别?(版本在不断更新,以下的区别有可能不是很正确。我工作中只用到vue,对angular和react不怎么熟)1.与AngularJS的区别相同点:都支持指令:内置指令和自定义指令;都支持过滤器:内置过滤器和自定义过滤器;都支持双向数据绑定;都不支持低端浏览器。不同点:AngularJS的学习成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比较简单、直观;在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢;Vue.js使用基于依赖追踪的观察并且使用异步队列更新,所有的数据都是独立触发的。2.与React的区别相同点:React采用特殊的JSX语法,Vue.js在组件开发中也推崇编写.vue特殊文件格式,对文件内容都有一些约定,两者都需要编译后使用;中心思想相同:一切都是组件,组件实例之间可以嵌套;都提供合理的钩子函数,可以让开发者定制化地去处理需求;都不内置列数AJAX,Route等功能到核心包,而是以插件的方式加载;在组件开发中都支持mixins的特性。不同点:React采用的Virtual DOM会对渲染出来的结果做脏检查;Vue.js在模板中提供了指令,过滤器等,可以非常方便,快捷地操作Virtual DOM。七、vue路由的钩子函数首页可以控制导航跳转,beforeEach,afterEach等,一般用于页面title的修改。一些需要登录才能调整页面的重定向功能。beforeEach主要有3个参数to,from,next:to:route即将进入的目标路由对象,from:route当前导航正要离开的路由next:function一定要调用该方法resolve这个钩子。执行效果依赖next方法的调用参数。可以控制网页的跳转。八、vuex是什么?怎么使用?哪种功能场景使用它?只用来读取的状态集中放在store中; 改变状态的方式是提交mutations,这是个同步的事物; 异步逻辑应该封装在action中。在main.js引入store,注入。新建了一个目录store,…… export 。场景有:单页应用中,组件之间的状态、音乐播放、登录状态、加入购物车[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-biCZCx5s-1611887935896)(C:\Users\zjx\Desktop\桌面文件\web面试\Vuepng.png)]stateVuex 使用单一状态树,即每个应用将仅仅包含一个store 实例,但单一状态树和模块化并不冲突。存放的数据状态,不可以直接修改里面的数据。mutationsmutations定义的方法动态修改Vuex 的 store 中的状态或数据。getters类似vue的计算属性,主要用来过滤一些数据。actionactions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据。view 层通过 store.dispath 来分发 action。const store = new Vuex.Store({ //store实例 state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })modules项目特别复杂的时候,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB })九、vue-cli如何新增自定义指令?1.创建局部指令var app = new Vue({ el: '#app', data: { }, // 创建指令(可以多个) directives: { // 指令名称 dir1: { inserted(el) { // 指令中第一个参数是当前使用指令的DOM console.log(el); console.log(arguments); // 对DOM进行操作 el.style.width = '200px'; el.style.height = '200px'; el.style.background = '#000'; } } } })2.全局指令Vue.directive('dir2', { inserted(el) { console.log(el); } })3.指令的使用<div id="app"> <div v-dir1></div> <div v-dir2></div> </div>十、vue如何自定义一个过滤器?html代码:<div id="app"> <input type="text" v-model="msg" /> {{msg| capitalize }} </div>JS代码:var vm=new Vue({ el:"#app", data:{ msg:'' }, filters: { capitalize: function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) } } })全局定义过滤器Vue.filter('capitalize', function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) })过滤器接收表达式的值 (msg) 作为第一个参数。capitalize 过滤器将会收到 msg的值作为第一个参数。十一、对keep-alive 的了解?keep-alive是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。在vue 2.1.0 版本之后,keep-alive新加入了两个属性: include(包含的组件缓存) 与 exclude(排除的组件不缓存,优先级大于include) 。使用方法<keep-alive include='include_components' exclude='exclude_components'> <component> <!-- 该组件是否缓存取决于include和exclude属性 --> </component> </keep-alive>参数解释include - 字符串或正则表达式,只有名称匹配的组件会被缓存exclude - 字符串或正则表达式,任何名称匹配的组件都不会被缓存include 和 exclude 的属性允许组件有条件地缓存。二者都可以用“,”分隔字符串、正则表达式、数组。当使用正则或者是数组时,要记得使用v-bind 。使用示例<!-- 逗号分隔字符串,只有组件a与b被缓存。 --> <keep-alive include="a,b"> <component></component> </keep-alive> <!-- 正则表达式 (需要使用 v-bind,符合匹配规则的都会被缓存) --> <keep-alive :include="/a|b/"> <component></component> </keep-alive> <!-- Array (需要使用 v-bind,被包含的都会被缓存) --> <keep-alive :include="['a', 'b']"> <component></component> </keep-alive>十二、一句话就能回答的面试题1.css只在当前组件起作用答:在style标签中写入scoped即可 例如:2.v-if 和 v-show 区别答:v-if按照条件是否渲染,v-show是display的block或none;3.route和route和router的区别答:$route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。而$router是“路由实例”对象包括了路由的跳转方法,钩子函数等。4.vue.js的两个核心是什么?答:数据驱动、组件系统5.vue几种常用的指令答:v-for 、 v-if 、v-bind、v-on、v-show、v-else6.vue常用的修饰符?答:.prevent: 提交事件不再重载页面;.stop: 阻止单击事件冒泡;.self: 当事件发生在该元素本身而不是子元素的时候会触发;.capture: 事件侦听,事件发生的时候会调用7.v-on 可以绑定多个方法吗?答:可以8.vue中 key 值的作用?答:当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。key的作用主要是为了高效的更新虚拟DOM。9.什么是vue的计算属性?答:在模板中放入太多的逻辑会让模板过重且难以维护,在需要对数据进行复杂处理,且可能多次使用的情况下,尽量采取计算属性的方式。好处:①使得数据处理结构清晰;②依赖于数据,数据更新,处理结果自动更新;③计算属性内部this指向vm实例;④在template调用时,直接写计算属性名即可;⑤常用的是getter方法,获取数据,也可以使用set方法改变数据;⑥相较于methods,不管依赖的数据变不变,methods都会重新计算,但是依赖数据不变的时候computed从缓存中获取,不会重新计算。10.vue等单页面应用及其优缺点答:优点:Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件,核心是一个响应的数据绑定系统。MVVM、数据驱动、组件化、轻量、简洁、高效、快速、模块友好。缺点:不支持低版本的浏览器,最低只支持到IE9;不利于SEO的优化(如果要支持SEO,建议通过服务端来进行渲染组件);第一次加载首页耗时相对长一些;不可以使用浏览器的导航按钮需要自行实现前进、后退。11.怎么定义 vue-router 的动态路由? 怎么获取传过来的值答:在 router 目录下的 index.js 文件中,对 path 属性加上 /:id,使用 router 对象的 params.id 获取。算法面试1. 字符串回文判断思路:回文是指把相同的词汇或句子,在下文中调换位置或颠倒过来,产生首尾回环的情景,叫做回文,也叫回环。将一个字符串首尾倒序排列,如果与原字符串相等,则这个字符串回文。<script type="text/javascript"> var str1 = 'abcdefgh'; var str2 = 'abcdcba'; function plalindrome(str){ return str == str.split('').reverse().join(''); } console.log(plalindrome(str1));//false console.log(plalindrome(str2));//true </script>2. 数组去重思路:利用indexOf()a方法,在遍历原数组,若里面的元素第一次出现,则放在数组arr1中,遍历完之后,arr1中存放的是无重复的新数组<script type="text/javascript"> var arr = [2,4,2,2,5,6,7,8,9,9,9]; function unique(arr){ var arr1 = []; for (var i = 0;i < arr.length;i ++){ if(arr1.indexOf(arr[i]) == -1){ arr1.push(arr[i]); } } return arr1; } console.log(unique(arr));//[2, 4, 5, 6, 7, 8, 9] </script>3. 统计一个字符串中出现最多的字母思路:在另外一个数组存放原数组每个元素出现的位置次数,且次数跟存放不重复数组的下标对应,然后取出最多的次数,对应的下标就是不重复数组里面那个出现次数最多的元素的下标<script type="text/javascript"> var str1 = "jhadfgskjfajhdewqe"; var arr1 = str1.split(''); console.log(arr1); function MostUnit(){ var arrA = []; var arrB = []; for(var i = 0 ;i <arr1.length; i ++){ if(arrA.indexOf(arr1[i])==-1){ arrA.push(arr1[i]); arrB.push(1); }else { arrB[arrA.indexOf(arr1[i])] ++; } } console.log(arrB) console.log(arrA[arrB.indexOf(Math.max.apply(Math,arrB))]); } MostUnit();//j </script>4. 冒泡排序:比较相邻的元素。如果第一个比第二个大,就交换他们两个。对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。针对所有的元素重复以上的步骤,除了最后一个。持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较<script type="text/javascript"> var arr1 = [2,3,45,64,321,3,21,321,31,999]; function bubbleSort(arr) { for(var i = 0 ;i < arr1.length-1 ;i ++){ for(var j = 0; j < arr1.length - i - 1 ;j ++){ if(arr[j]>arr[j+1]) { let tem = arr[j]; arr[j] = arr[j+1]; arr[j+1] = tem; } } } return arr; } console.log(bubbleSort(arr1));//[2, 3, 3, 21, 31, 45, 64, 321, 321, 999] </script>5. 快速排序:思路:算法参考某个元素值,将小于它的值,放到左数组中,大于它的值的元素就放到右数组中,然后递归进行上一次左右数组的操作,返回合并的数组就是已经排好顺序的数组了。<script type="text/javascript"> var arr1 = [1,4,765,86,53,87,53,32,6,64,2,3,767,34,1,4,35,6]; function quickSort(arr){ if(arr.length <= 1){ return arr; } var leftArr = []; var rightArr = []; var q = arr[0]; for(var i = 1;i < arr.length; i++) { if(arr[i]>q) { rightArr.push(arr[i]); }else{ leftArr.push(arr[i]); } } return [].concat(quickSort(leftArr),[q],quickSort(rightArr)); } console.log(quickSort(arr1));//[1,4,765,86,53,87,53,32,6,64,2,3,767,34,1,4,35,6] </script>6. 不利用第三方变量的情况下交换两个变量的值思路:利用两个元素的差值进行计算<script type="text/javascript"> var a = 10; var b = 12; function swap (a,b) { b = b - a; a = a + b; b = a - b; return [a,b] } console.log(swap(a,b)); </script>7. 求一个数组中最大数和最小数的差值<script type="text/javascript"> var arr1 = [2,44,3,-12,43,5,8,67,54,32,-211]; var max = Math.max.apply(Math,arr1); var min = Math.min.apply(Math,arr1); console.log(max-min);//278 </script>8. 生成指定长度的随机字符串思路:charAt()方法,获取元素下标<script type="text/javascript"> function randomString(n){ var str1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz9876543210" var str2 = ""; for (var i = 0; i < n ; i ++){ str2 += str1.charAt(Math.floor(Math.random()*str1.length)); } return str2; } console.log(randomString(5)); </script>9. 获取一个DOM节点下面包含某个class名的所有节点<div id="text"> <div class="cs"></div> <div class="as"></div> <p class="cs"></p> </div> <script type="text/javascript"> function getClass(node,classname) { if(node.getElementsByClassName) { return node.getElementsByClassName(classname); //如果存在该标签 就返回 } else { var elems = node.getElementsByTagName(node), defualt = []; for (var i = 0; i < elems.length; i++) { //遍历所有标签 if(elems[i].className.indexOf(classname) != -1) { //查找相应类名的标签 defualt[defualt.length] = elems[i]; } } return defualt; } } var text = document.getElementById('text'), cs = getClass(text,'cs'); console.log(cs);//[div.cs, p.cs] </script>10. 二叉树一说到二叉树我们肯定会问,什么是二叉树,二叉树是个啥子东东,拿来有啥子用嘛,我们为啥子要学习它嘛? 如果当初你在学习二叉树的时候你没有问过自己这些问题,那么你对它的了解也仅仅也只是了解。那我们现在来说说什么是二叉树,二叉树就是一种数据结构, 它的组织关系就像是自然界中的树一样。官方语言的定义是:是一个有限元素的集合,该集合或者为空、或者由一个称为根的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成。至于为啥子要学习它,妈妈总是说,孩子,等你长大了就明白了。11. 二叉树的性质性质1:二叉树第i层上的节点数目最多为2i-1(i≥1);性质2:深度为k的二叉树至多有2k-1个结点(k≥1)。性质3: 在任意-棵二叉树中,若叶子结点(即度为0的结点)的个数为n0,度为1的结点数为n1,度为2的结点数为n2,则no=n2+1。12. 二叉树的存储结构与构建二叉树的存储方式有两种,一种顺序存储,比如:var binaryTree = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘h’, ‘i’]; 这就是一颗二叉树,假设binaryTree[i]是二叉树的一个节点,那么它的左孩子节点 leftChild = binaryTree[i2+1]那  么相应的右孩子节点 rightChild = binaryTree[i2+2]; 一般情况下顺序存储的这种结构用的较少,另外一种存储方式就是链式存储,下面我会用代码来详细描述二叉树式  结构的构建与存储方式,构建二叉树也有两种方式一种是递归方式构建,这种很简单,另一种是非递归方法构建,这种呢相对于前一种复杂一点点,不过也不用担心,我在  代码中加上详细的注释,一步一步的走下去。我们现在就以26个英文字母来构建二叉树var charecters = [‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’, ‘H’, ‘I’, ‘J’, ‘K’, ‘L’, ‘M’, ‘N’, ‘O’, ‘P’, ‘Q’, ‘R’, ‘S’, ‘T’, ‘U’, ‘V’, ‘W’, ‘X’, ‘Y’, ‘Z’];在构建二叉树之前我们会用到一个节点对象,节点对象如下:(注意:关于javascript的面向对象,原型,语法特点我会放在javascript语言知识点这个系列)/* *二叉树的节点对象 */ function Node() { this.text = ''; //节点的文本 this.leftChild = null; //节点的左孩子引用 this.rightChild = null; //节点右孩子引用 }13. 递归构建二叉树在构建好二叉树节点之后我们紧接着用递归来构建二叉树var charecters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; function buildTree(node, i) { var leftIndex = 2*i+1, //左孩子节点的索引 rightIndex = 2*i+2; //右孩子节点的索引 if(leftIndex < charecters.length) { //判断索引的长度是否超过了charecters数组的大小 var childNode = new Node(); //创建一个新的节点对象 childNode.text = charecters[leftIndex]; //给节点赋值 node.leftChild = childNode; //给当前节点node加入左孩子节点 buildTree(childNode, leftIndex); //递归创建左孩子 } if(rightIndex < charecters.length) { //下面注释参照上面的构建左孩子的节点 var childNode = new Node(); childNode.text = charecters[rightIndex]; node.rightChild = childNode; buildTree(childNode, rightIndex); } } //下面构造二叉树 var node = new Node(); node.text = charecters[0]; buildTree(node, 0); //索引i是从0开始构建14. 非递归构建二叉树下面是以非递归方式构建二叉树:var root; function createBinaryTree() { var len = charecters.length, //数组的长度 index = 0, //索引从0开始 nodes = new Array(); //创建一个临时数组,用于存放二叉树节点 //循环创建二叉树节点存放到数组中 for (var i = 0 ; i < charecters.length ; i++) { var node = new Node(); node.text = charecters[i]; nodes.push(node); } //循环建立二叉树子节点的引用 while(index < len) { var leftIndex = 2*index+1, //当前节点左孩子索引 rightIndex = 2*index+2; //当前节点右孩子索引 //给当前节点添加左孩子 nodes[index].leftChild = nodes[leftIndex]; //给当前节点添加右孩子 nodes[index].rightChild = nodes[rightIndex]; index++; } root = nodes[0]; }15.二叉树的三种遍历好了,现在我们已经成功构建了二叉树的链式结构,在构建了二叉树的链式结构后我们进入二叉树的最基本的遍历了,遍历有三种最基本的遍历,我不说想必大家都知道,先序遍历,中序遍历和后续遍历。虽然这三种遍历递归方式都比较简单,但非递归方式就不是那么容易了,当时我在实现的时候都卡了半天,真的是说起来容易做起来难啊,在实现遍历前我们首先要来实现的是栈,因为在非递归遍历的时候会用到栈,那到底什么是栈呢,这里我就简单介绍下吧,有兴趣的朋友可以去维基百科有权威的定义,栈和队列也是一种数据结构,栈存放数据的时候是先进先出,而队列是先进后出。16.实现栈的对象下面用javascript来实现栈的对象function Stack() { var stack = new Array(); //存放栈的数组 //压栈 this.push = function(o) { stack.push(o); }; //出栈 this.pop = function() { var o = stack[stack.length-1]; stack.splice(stack.length-1, 1); return o; }; //检查栈是否为空 this.isEmpty = function() { if(stack.length <= 0) { return true; } else { return false; } }; } //使用方式如下 var stack = new Stack(); stack.push(1); //现在栈中有一个元素 stack.isEmpty(); //false , 栈不为空 alert(stack.pop()); //出栈, 打印1 stack.isEmpty(); //true, 此时栈为空,因为在调用了stack.pop()之后元素出栈了,所以为空17. 先序遍历在实现了栈对象以后我们首先来进行先序遍历的递归方式function firstIteration(node) { if(node.leftChild) { //判断当前节点是否有左孩子 firstIteration(node.leftChild); //递归左孩子 } if(node.rightChild) { //判断当前节点是否有右孩子 firstIteration(node.rightChild); //递归右孩子 } } //递归遍历二叉树 firstIteration(root);18. 先序遍历的非递归方式上面的代码大家可以在firstIteration()方法中加个alert()函数来验证是否正确。那么下面就要说说先序遍历的非递归方式,遍历思想是这样的:先访问根节点在访问左节   点, 最后访问右节点。从根节点一直往下访问找左孩子节点,直到最后一个左孩子节点(将这条路径保存到栈中),然后再访问最后一个左孩子的兄弟节点(右孩子节点),之后回溯到上一层(将栈中的元素取出 就是出栈),又开始从该节点(回溯到上一层的节点)一直往下访问找左孩子节点… 直到栈中的元素为空,循环结束。function notFirstIteration(node) { var stack = new Stack(), //开辟一个新的栈对象 resultText = ''; //存放非递归遍历之后的字母顺序 stack.push(root); //这个root在上面非递归方式构建二叉树的时候已经构建好的 var node = root; resultText += node.text; while(!stack.isEmpty()) { while(node.leftChild) { //判断当前节点是否有左孩子节点 node = node.leftChild; //取当前节点的左孩子节点 resultText += node.text; //访问当前节点 stack.push(node); //将当前节点压入栈中 } stack.pop(); //出栈 node = stack.pop().rightChild; //访问当前节点的兄弟节点(右孩子节点) if(node) { //当前节点的兄弟节点不为空 resultText += node.text; //访问当前节点 stack.push(node); //将当前节点压入栈中 } else { //当前节点的兄弟节点为空 node = stack.pop(); //在回溯到上一层 } } } //非递归先序遍历 notFirstIteration(root);19.中序遍历只要把思路理清楚了现实起来其实还是挺容易的,只要我们熟悉了一种二叉树的非递归遍历方式,其他几种非递归方式就容易多了,照着葫芦画瓢,下面是中序遍历的递归  方式,中序遍历的思想是:先访问左孩子节点,在访问根节点,最后访问右节点var strText = ""; function secondIteration(node) { //访问左节点 if(node.leftChild) { if(node.leftChild.leftChild) { secondIteration(node.leftChild); } else { strText += node.leftChild.text; } } //访问根节点 strText += node.text; //访问右节点 if(node.rightChild) { if(node.rightChild.leftChild) { secondIteration(node.rightChild); } else { strText += node.rightChild.text; } } } secondIteration(root); alert(strText);20. 中序遍历的非递归方式思想是:1. 从根节点一直往下找左孩子节点,直到找到最后一个左孩子节点(用栈将此路径保存,但不访问)2.访问最后一个左孩子节点,然后再  访问根节点(要先弹出栈,就是在栈中取上一层节点)3.在访问当前节点(最后一个左孩子节点)的兄弟节点(右孩子节点),这里要注意如果兄弟节点是一个叶节点就直  接访问,否则是兄弟节点是一颗子树的话不能马上访问,要先来重复 1, 2,3步骤, 直到栈为空,循环结束function notSecondIteration() { var resultText = '', stack = new Stack(), node = root; stack.push(node); while(!stack.isEmpty()) { //从根节点一直往下找左孩子节点直到最后一个左孩子节点,然后保存在栈中 while(node.leftChild) { node = node.leftChild; stack.push(node); } //弹出栈 var tempNode = stack.pop(); //访问临时节点 resultText += tempNode.text; if(tempNode.rightChild) { node = tempNode.rightChild; stack.push(node); } } alert(resultText); }21. 后续遍历最后就还剩下一种遍历方式,二叉树的后续遍历,后续遍历的思想是:先访问左孩子节点,然后在访问右孩子节点,最后访问根节点22. 后续遍历的递归方式var strText = ''; function lastIteration(node) { //首先访问左孩子节点 if(node.leftChild) { if(node.leftChild.leftChild) { lastIteration(node.leftChild); } else { strText += node.leftChild.text; } } //然后再访问右孩子节点 if(node.rightChild) { if(node.rightChild.rightChild) { lastIteration(node.rightChild); } else { strText += node.rightChild.text; } } //最后访问根节点 strText += node.text; } //中序递归遍历 lastIteration(root); alert(strText);23.后续非递归遍历后续非递归遍历的思想是:1.从根节点一直往下找左孩子节点,直到最后一个左孩子节点(将路径保存到栈中,但不访问)2.弹出栈访问最后一个左孩子节点 3.进入最后一  个左孩子节点的兄弟节点,如果兄弟节点是叶节点就访问它,否则将该节点重复 1, 2步骤, 直到栈中的元素为空,循环结束。3.访问根节点function notLastIteration() { var strText = '', stack = new Stack(); nodo = root; stack.push(node); while(!stack.isEmpty()) { while(node.leftChild) { node = node.leftChild; stack.push(node); } //弹出栈 var tempNode = stack.pop(); //访问左孩子节点 strText += tempNode.text; //访问右孩子节点 if(tempNode.rightChild) { if(tempNode.rightChild.leftChild || tempNode.rightChild.rightChild) { //判断最后一个左孩子节点的兄弟节点是否为页节点 stack.push(tempNode.rightChild); } else { strText += tempNode.rightChild.text; } } } alert(strText); }24. 已知前序和中序构建二叉树<script> let qianxu = [ 1,2,4,7,3,5,6,8 ]; let zhongxu = [ 4,7,2,1,5,3,8,6 ]; function TreeNode( val ){ this.val = val; this.left = null; this.right = null; } function rebuildTree(qianxu,zhongxu){ if (qianxu[0]){ // 1. 根据找到的根节点( 前序序列的第一个元素一定是根节点 ) let rootVal = qianxu[0]; // 2. 找到根节点和中序序列,找到树的左子树和右子树 // 根节点在中序序列中的位置 let index = zhongxu.indexOf( rootVal ); // 前序序列:左子树 qianxu(1,index),右子树qianxu(index+1,最后) // 中序序列:左子树 zhongxu(0,index-1),右子树 zhongxu(index+1,最后) let leftTree = rebuildTree(qianxu.slice(1,index+1),zhongxu.slice(0,index)); let rightTree = rebuildTree(qianxu.slice(index+1),zhongxu.slice(index+1)); let root = new TreeNode(rootVal); root.right = rightTree; root.left = leftTree; return root; } } console.log(rebuildTree(qianxu,zhongxu)); </script>25. 栈转化成队列<script> let stack1 = []; let stack2 = []; function push(node){ stack1.push(node); } function pop (){ while(stack1.length){ stack2.push(stack1.pop()); } let popVal = stack2.pop(); while(stack2.length){ stack1.push(stack2.pop()); } return popVal; } /** * 1,2,3,4,5 入队 * 出队操作 1 * 入队 6 * 出队操作2 * 出队操作3 */ push(1); push(2); push(3); push(4); push(5); console.log(pop()); </script>26.跳台阶(典型递归)一只青蛙一次可以跳上一级台阶,也可以跳上两级求该青蛙上一个n级的台阶总共有多少中跳法(向后次序不同算不同结果)<script> function jumpFloor(n){ if(n==1) return 1; else if(n==2) return 2; return jumpFloor(n-1)+jumpFloor(n-2); } console.log(jumpFloor(3)); </script>算法优化用空间换时间;(加缓存)(记忆化递归)<script> // 记忆化递归 let cache = [,1,2]; function jumpFloor2(n){ if(cache[n] !==undefined) return cache[n]; return cache[n] = jumpFloor(n-1)+jumpFloor(n-2); } console.log(jumpFloor2(3)); </script>一只青蛙一次可以跳上一级台阶,也可以跳上两级…它也可以跳上n级;求该青蛙上一个n级的台阶总共有多少中跳法(向后次序不同算不同结果)f(n)=f(n-1)+f(n-2)+…+f(2)+f(1)+1<script> let cache = [,1,2]; function jumpFloor(n){ if(cache[n] !== undefined) return cache[n]; cache[n] = 1; for(let i = n-1;i >=1;i--){ cache[n] += jumpFloor(i); } return cache[n]; } console.log(jumpFloor(10)); </script>27. 反转链表写一个函数,输入一个链表,反转练表后,输出新链表的表头。<script> function Node(val){ this.val = val; this.next = null; } function creatList(arr){ let head = new Node(arr[0]); let tail = head; for(let i =1;i<=arr.length-1;i++){ tail.next = new Node(arr[i]); tail = tail.next; } return head; } let list = creatList([1,2,3,4,5]); // console.log(list); function reverseList (head){ let arr = []; let p = head; while(p){ arr.push(p.val); p = p.next; } p = head; while(p){ p.val = arr.pop(p.val); p = p.next; } return head; } console.log(reverseList(list)); </script>28. 字典树需求:10 创建一个字典树,在字典树中查找是否包含某个单词1112 单词序列:13 and14 about15 as16 boy17 by18 because19 as2021 查找:22 close false23 an false24 as true25 boy true2627 字典树是什么28 字典树又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。30 字典树的作用31 统计,排序和保存大量的字符串33 字典树的特点34 1、字典树的节点存储的是单词的字符(字母)35 2、为了表示一个单词是否出现,我们可以给单词的最后的字符加上标记36 3、字典树中表示一个单词用的是一条链37 4、字典树的根节点没有什么意义39 字典树的操作40 1、把单词插入到字典树里面去41 2、在字典树中查找单词45 1、把单词插入到字典树里面去46 算法步骤:47 去跟节点下面去找这个单词的第一个字符是否出现,48 如果没出现,就创建,然后走这条路,49 如果出现了,就直接走这条路50 (在这个过程里面,单词的第一个字符就被消耗掉了)52 算法:53 递归56 2、在字典树中查找单词57 算法:58 递归60 算法步骤:61 查找单词的第一个字符是否在根节点的子节点中,如果出现了,就接着往下找62 如果没出现,直接return false63 在单词找完后,如果标记大于1,表示单词出现过,就return true,64 否则return falseNodeJS一:Node 好处: 处理高并发 事件驱动 轻量 要用于搭建高性能的web服务器,1. 它是一个Javascript运行环境2. 依赖于Chrome V8引擎进行代码解释3. 事件驱动4. 非阻塞I/O5. 轻量、可伸缩,适于实时数据交互应用6. 单进程,单线程二:Express 和 koa的区别?异步 摆脱回调地域对response 和request进行了封装 contentExpress主要基于Connect中间件框架,功能丰富,随取随用,并且框架自身封装了大量便利的功能,比如路由、视图处理等等。而koa主要基于co中间件框架,框架自身并没集成太多功能,大部分功能需要用户自行require中间件去解决,但是由于其基于ES6 generator特性的中间件机制,解决了长期诟病的“callback hell”和麻烦的错误处理的问题,大受开发者欢迎。三:事件驱动模型和事件循环:事件驱动模型:当服务端收到请求时,就把它关闭 然后处理下一个请求 当第一个请求处理完毕后 就放回处理队列 当达到队列开头 将结果返回给用户 好处:高效 扩展性强 因为服务端一直接受请求 不等待任何读写操作事件循环:查看队列里面是否有队列里面有待处理的 如果有 交给主线程执行四:Redis:使用场景:支持string、list、set、zset和hash类型数据。配合关系型数据库做高速缓存缓存高频次访问的数据,降低数据库io分布式架构,做session共享可以持久化特定数据。利用zset类型可以存储排行榜利用list的自然时间排序存储最新n个数据五:mysql 和mongodb的区别mysql 关系型数据库 mongodb是非关系数据库(主要)六:MySQL索引七:闭包应该注意的地方八:进程和线程进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位进程是线程的容器十:mysql存储引擎 和区别InnoDB存储引擎:事务型数据库首选,支持事务安全表(ACID),支持行锁定和外键 是mysql 5.5之后的默认引擎MyISAM 存储引擎:不支持事务和外键,访问速度较快,是mysql5.5 之前的默认引擎MEMORY: 保存在内存中的数据表 ,每个memory表对应一个磁盘文件。格式是.frm 访问速度很快 缺点是:mysql服务关闭,数据丢失,另外对数据表大小有限制。十一:如何判断一个字符串是另一个字符串的子串indexof es6:include startWith endWith十二:单点登录十三:oauth2.0十四:type of 和instance of 区别十五:pm2 restart 和reload的区别(配置文件的重载 重启)十六:MySQL 读写分离十七:pm2如何查看指定三个项目的日志十八:深拷贝 浅拷贝十九:路由机制二十:MySQL 批量更新二十一:登录流程二十二:cookie 和session二十三:基本数据类型 引用数据类型 区别二十四:防止sql 注入1.使用escape() 对传入参数进行编码2.使用connection.query ()的查询参数占位符3.使用escapeId()编码SQL查询标识符4.使用mysql.format()转义参数:二十五:require()模块加载机制先判断是否存在文件缓存区中,存在直接导入,没有的话,在判断是否是原生模块,如果是原生模块,再看是否在原生模块缓存区中,如果有直接导入,没有的话加载原生模块,缓存原生模块,在导入如果不是原生模块,先查找文件模块,根据扩展名载入文件模块,缓存文件模块,在导入[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rujkgYx7-1611887935898)(C:\Users\zjx\Desktop\桌面文件\web面试\1.jpg)]第1题, 什么是nodejs?我们在哪里使用它?Nodejs是服务器端的一门技术。它是基于Google V8 JavaScript引擎而开发的。用来开发可扩展的服务端程序。第2题,为什么要使用node js?nodejs会让我们的编程工作变得简单,它主要包含如下几点几个好处:执行快速。永远不会阻滞。JavaScript是通用的编程语言。异步处理机制。避免并行所带来的问题。第3题,nodejs有哪些特点?是单线程的,但是有很高的可扩展性,使用JavaScript作为主流编程语言。使用的是异步处理机制和事件驱动。处理高效。第4题, Set immediate和set time out 区别在哪里?Set immediate就是马上执行的意思。Set time out, 时间参数传为0,也想获得同样的功能。只不过前者要快一些。第5题,如何更新nodejs的版本?npm install npm -g第6题,为什么nodejs是单线程的?Nodejs使用的是单线程没错,但是通过异步处理的方式,可以处理大量的数据吞吐量,从而有更好的性能和扩可扩展性。第7题,什么是回调函数?回调函数是指用一个函数作为参数传入另一个函数,这个函数会被在某个时机调用。第8题, 什么叫做回调地狱?回调地狱是由嵌套的回调函数导致的。这样的机制会导致有些函数无法到达,并且很难维护。第9题,如何阻止回调地狱?有三种方法, 对每个错误都要处理到, 保证代码的贯通, 程序代码模块化。第10题,解释一下repl的作用?Read evaluate print loop, 用于测试,调试和实验用。第11题,API函数的类型有哪些?有两种,一种是阻滞型函数。阻滞型函数会等待操作完成以后再进行下一步。另外一种是非阻滞型函数。这种函数使用回调函数来处理当前函数获取的结果。第12题,回调函数的第1个参数是什么?通常是错误对象。如果这个参数为空,表示没有错误。第13题,NPM的作用是什么?Node package manager, 主要有两个功能。它是一个网端模块的存储介质。它的另一个作用是安装程序依赖和版本管理。第14题,nodejs和ajax的区别是什么?Nodejs和ajax也就是asynchronous JavaScript and xml,都是通过JavaScript来表现的,但是他们的目的截然不同。Ajax是设计用来动态的更新页面的某个区域,从而不需要更新整个页面。Nodejs是用来开发客户服务器类型应用的。第15题,解释一下nodejs中chaining.Chaining是指从一个数据流到另一个数据流的链接,从而实现多个流操作。第16题,什么是streams?解释一下有哪些类型?流的概念是不间断的,它可以不间断的从某个地方读取数据,或者向某个地方写入数据。有4种类型的流数据。可读,可写。既可读,又可写,转化。第17题,退出代码是什么?有哪些退出代码?退出代码是指中断nodejs运行时返回的代码。有这么几种unused, uncaught fatal exception, fatal error, non function internal exception handler, internal exception handler run time failure,internal JavaScript evaluation failure.第18题, 什么是globals?有三个global的关键字。Global代表的是最上层的命名空间,用来管理所有其他的全局对象。Process 是一个全局对象,可以把异步函数转化成异步回调, 它可以在任何地方被访问,它主要是用来返回系统的应用信息和环境信息.Buffer, 是用来处理二进制数据的类.第19题, Angular js和node js的区别是什么?Angular js是网络应用开发框架,而nodejs是一个实时系统。第20题, 为什么统一的风格儿非常重要,有什么工具可以保证这一点?统一的风格可以让所有的组成员按照一种规矩来写代码。工具有Standard和eslint.第21题, 用什么方法来处理没有被处理的异常?在应用和node js之间使用domain来处理这样的异常。第22题, Node js是如何支持多处理器平台的?Cluster模块是用来支持这方面的。它可以允许多个nodejs工作进程运行在相同的端口上。第23题, 如何配置开发模式和生产模式的环境?首先有一个配置文件,然后通过环境变量参数来获取对应的配置内容。第24题, nodejs中跟时间相关的函数有哪些?Set time out, clear time out.Set interval, clear interval.Set immediate, clear immediate.Process.nextTick.第25题, 解释一下什么是reactor pattern。Reactor pattern主要是非阻滞的i/o操作。提供一个回调函数来关联io操作。io请求完成以后会不会提交给demultiplexer, 这是一个通知接口用来处理并发性的非阻滞的io操作,这个功能是通过查询一个event loop来实现的.第26题,lts版本是什么意思?也就是long term support版本。至少会被支持18个月。使用的是偶数来标识。这种版本有稳定性和安全性的保证。第27题,你为什么需要把express APP和server分开?分开以后方便维护以及测试,在测试某个模块的时候,尤其是APP模块的时候,你不需要去对网络方面的连接配置做工作。第28题,next tick和setImmediate的区别是什么?Next tick会等待当前的event执行完成或者下一轮儿事件循环到达再执行。Set immediate, 会在下一轮的事件循环中,执行回调并且返回当前的循环来做读写操作.第29题,apply, call和bind有什么区别?参考答案:三者都可以把一个函数应用到其他对象上,注意不是自身对象.apply,call是直接执行函数调用,bind是绑定,执行需要再次调用.apply和call的区别是apply接受数组作为参数,而call是接受逗号分隔的无限多个参数列表,代码演示function Person() { } Person.prototype.sayName() { alert(this.name); } var obj = {name: 'michaelqin'}; // 注意这是一个普通对象,它不是Person的实例 1) apply Person.prototype.sayName.apply(obj, [param1, param2, param3]); 2) call Person.prototype.sayName.call(obj, param1, param2, param3); 3) bind var sn = Person.prototype.sayName.bind(obj); sn([param1, param2, param3]); // bind需要先绑定,再执行 sn(param1, param2, param3); // bind需要先绑定,再执行二)、node全局对象3. node有哪些核心模块?参考答案: EventEmitter, Stream, FS, Net和全局对象1. node有哪些全局对象?参考答案: process, console, Buffer2. process有哪些常用方法?参考答案: process.stdin, process.stdout, process.stderr, process.on, process.env, process.argv, process.arch, process.platform, process.exit3. console有哪些常用方法?参考答案: console.log/console.info, console.error/console.warning, console.time/console.timeEnd, console.trace, console.table4. node有哪些定时功能?参考答案: setTimeout/clearTimeout, setInterval/clearInterval, setImmediate/clearImmediate, process.nextTick5. node中的事件循环是什么样子的?总体上执行顺序是:process.nextTick >> setImmidate >> setTimeout/SetInterval 看官网吧:[https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/](https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/)6. node中的Buffer如何应用?参考答案: Buffer是用来处理二进制数据的,比如图片,mp3,数据库文件等.Buffer支持各种编码解码,二进制字符串互转.三)、EventEmitter1. 什么是EventEmitter?参考答案: EventEmitter是node中一个实现观察者模式的类,主要功能是监听和发射消息,用于处理多模块交互问题.2. 如何实现一个EventEmitter?参考答案: 主要分三步:定义一个子类,调用构造函数,继承EventEmitter代码演示var util = require('util'); var EventEmitter = require('events').EventEmitter; function MyEmitter() { EventEmitter.call(this); } // 构造函数 util.inherits(MyEmitter, EventEmitter); // 继承 var em = new MyEmitter(); em.on('hello', function(data) { console.log('收到事件hello的数据:', data); }); // 接收事件,并打印到控制台 em.emit('hello', 'EventEmitter传递消息真方便!');3. EventEmitter有哪些典型应用?参考答案:模块间传递消息回调函数内外传递消息处理流数据,因为流是在EventEmitter基础上实现的.观察者模式发射触发机制相关应用4. 怎么捕获EventEmitter的错误事件?参考答案: 监听error事件即可.如果有多个EventEmitter,也可以用domain来统一处理错误事件.代码演示var domain = require('domain'); var myDomain = domain.create(); myDomain.on('error', function(err){ console.log('domain接收到的错误事件:', err); }); // 接收事件并打印 myDomain.run(function(){ var emitter1 = new MyEmitter(); emitter1.emit('error', '错误事件来自emitter1'); emitter2 = new MyEmitter(); emitter2.emit('error', '错误事件来自emitter2'); });5. EventEmitter中的newListenser事件有什么用处?参考答案: newListener可以用来做事件机制的反射,特殊应用,事件管理等.当任何on事件添加到EventEmitter时,就会触发newListener事件,基于这种模式,我们可以做很多自定义处理.代码演示var emitter3 = new MyEmitter(); emitter3.on('newListener', function(name, listener) { console.log("新事件的名字:", name); console.log("新事件的代码:", listener); setTimeout(function(){ console.log("我是自定义延时处理机制"); }, 1000); }); emitter3.on('hello', function(){ console.log('hello node'); });四)、Stream1. 什么是Stream?参考答案: stream是基于事件EventEmitter的数据管理模式.由各种不同的抽象接口组成,主要包括可写,可读,可读写,可转换等几种类型.2. Stream有什么好处?参考答案: 非阻塞式数据处理提升效率,片断处理节省内存,管道处理方便可扩展等.3. Stream有哪些典型应用?参考答案: 文件,网络,数据转换,音频视频等.4. 怎么捕获Stream的错误事件?参考答案: 监听error事件,方法同EventEmitter.5. 有哪些常用Stream,分别什么时候使用?参考答案: Readable为可被读流,在作为输入数据源时使用;Writable为可被写流,在作为输出源时使用;Duplex为可读写流,它作为输出源接受被写入,同时又作为输入源被后面的流读出.Transform机制和Duplex一样,都是双向流,区别时Transfrom只需要实现一个函数_transfrom(chunk, encoding, callback);而Duplex需要分别实现_read(size)函数和_write(chunk, encoding, callback)函数.6. 实现一个Writable Stream?参考答案: 三步走:1)构造函数call Writable 2) 继承Writable 3) 实现_write(chunk, encoding, callback)函数代码演示var Writable = require('stream').Writable; var util = require('util'); function MyWritable(options) { Writable.call(this, options); } // 构造函数 util.inherits(MyWritable, Writable); // 继承自Writable MyWritable.prototype._write = function(chunk, encoding, callback) { console.log("被写入的数据是:", chunk.toString()); // 此处可对写入的数据进行处理 callback(); }; process.stdin.pipe(new MyWritable()); // stdin作为输入源,MyWritable作为输出源五)、文件系统1. 内置的fs模块架构是什么样子的?参考答案: fs模块主要由下面几部分组成: 1) POSIX文件Wrapper,对应于操作系统的原生文件操作 2) 文件流 fs.createReadStream和fs.createWriteStream 3) 同步文件读写,fs.readFileSync和fs.writeFileSync 4) 异步文件读写, fs.readFile和fs.writeFile2. 读写一个文件有多少种方法?参考答案: 总体来说有四种: 1) POSIX式低层读写 2) 流式读写 3) 同步文件读写 4) 异步文件读写3. 怎么读取json配置文件?参考答案: 主要有两种方式,第一种是利用node内置的require(‘data.json’)机制,直接得到js对象; 第二种是读入文件入内容,然后用JSON.parse(content)转换成js对象.二者的区别是require机制情况下,如果多个模块都加载了同一个json文件,那么其中一个改变了js对象,其它跟着改变,这是由node模块的缓存机制造成的,只有一个js模块对象; 第二种方式则可以随意改变加载后的js变量,而且各模块互不影响,因为他们都是独立的,是多个js对象.4. fs.watch和fs.watchFile有什么区别,怎么应用?参考答案: 二者主要用来监听文件变动.fs.watch利用操作系统原生机制来监听,可能不适用网络文件系统; fs.watchFile则是定期检查文件状态变更,适用于网络文件系统,但是相比fs.watch有些慢,因为不是实时机制.六)、网络1. node的网络模块架构是什么样子的?参考答案: node全面支持各种网络服务器和客户端,包括tcp, http/https, tcp, udp, dns, tls/ssl等.2. node是怎样支持https,tls的?参考答案: 主要实现以下几个步骤即可: 1) openssl生成公钥私钥 2) 服务器或客户端使用https替代http 3) 服务器或客户端加载公钥私钥证书3. 实现一个简单的http服务器?参考答案: 经典又很没毛意义的一个题目.思路是加载http模块,创建服务器,监听端口.代码演示var http = require('http'); // 加载http模块 http.createServer(function(req, res) { res.writeHead(200, {'Content-Type': 'text/html'}); // 200代表状态成功, 文档类型是给浏览器识别用的 res.write('<meta charset="UTF-8"> <h1>我是标题啊!</h1> <font color="red">这么原生,初级的服务器,下辈子能用着吗?!</font>'); // 返回给客户端的html数据 res.end(); // 结束输出流 }).listen(3000); // 绑定3ooo, 查看效果请访问 http://localhost:3000七)、child-process1. 为什么需要child-process?参考答案: node是异步非阻塞的,这对高并发非常有效.可是我们还有其它一些常用需求,比如和操作系统shell命令交互,调用可执行文件,创建子进程进行阻塞式访问或高CPU计算等,child-process就是为满足这些需求而生的.child-process顾名思义,就是把node阻塞的工作交给子进程去做.2. exec,execFile,spawn和fork都是做什么用的?参考答案: exec可以用操作系统原生的方式执行各种命令,如管道 cat ab.txt | grep hello; execFile是执行一个文件; spawn是流式和操作系统进行交互; fork是两个node程序(javascript)之间时行交互.3. 实现一个简单的命令行交互程序?参考答案: 那就用spawn吧.代码演示var cp = require('child_process'); var child = cp.spawn('echo', ['你好', "钩子"]); // 执行命令 child.stdout.pipe(process.stdout); // child.stdout是输入流,process.stdout是输出流 // 这句的意思是将子进程的输出作为当前程序的输入流,然后重定向到当前程序的标准输出,即控制台4. 两个node程序之间怎样交互?参考答案: 用fork嘛,上面讲过了.原理是子程序用process.on, process.send,父程序里用child.on,child.send进行交互.代码演示1) fork-parent.js var cp = require('child_process'); var child = cp.fork('./fork-child.js'); child.on('message', function(msg){ console.log('老爸从儿子接受到数据:', msg); }); child.send('我是你爸爸,送关怀来了!'); 2) fork-child.js process.on('message', function(msg){ console.log("儿子从老爸接收到的数据:", msg); process.send("我不要关怀,我要银民币!"); });5. 怎样让一个js文件变得像linux命令一样可执行?参考答案: 1) 在myCommand.js文件头部加入 #!/usr/bin/env node 2) chmod命令把js文件改为可执行即可 3) 进入文件目录,命令行输入myComand就是相当于node myComand.js了6. child-process和process的stdin,stdout,stderror是一样的吗?参考答案: 概念都是一样的,输入,输出,错误,都是流.区别是在父程序眼里,子程序的stdout是输入流,stdin是输出流.九、node高级话题(异步,部署,性能调优,异常调试等)1. node中的异步和同步怎么理解参考答案: node是单线程的,异步是通过一次次的循环事件队列来实现的.同步则是说阻塞式的IO,这在高并发环境会是一个很大的性能问题,所以同步一般只在基础框架的启动时使用,用来加载配置文件,初始化程序什么的.2. 有哪些方法可以进行异步流程的控制?参考答案: 1) 多层嵌套回调 2) 为每一个回调写单独的函数,函数里边再回调 3) 用第三方框架比方async, q, promise等3. 怎样绑定node程序到80端口?参考答案: 多种方式 1) sudo 2) apache/nginx代理 3) 用操作系统的firewall iptables进行端口重定向4. 有哪些方法可以让node程序遇到错误后自动重启?参考答案: 1) runit 2) forever 3) nohup npm start &5. 怎样充分利用多个CPU?参考答案: 一个CPU运行一个node实例6. 怎样调节node执行单元的内存大小?参考答案: 用–max-old-space-size 和 --max-new-space-size 来设置 v8 使用内存的上限7. 程序总是崩溃,怎样找出问题在哪里?参考答案: 1) node --prof 查看哪些函数调用次数多 2) memwatch和heapdump获得内存快照进行对比,查找内存溢出8. 有哪些常用方法可以防止程序崩溃?参考答案: 1) try-catch-finally 2) EventEmitter/Stream error事件处理 3) domain统一控制 4) jshint静态检查 5) jasmine/mocha进行单元测试9. 怎样调试node程序?参考答案: node --debug app.js 和node-inspector10. 如何捕获NodeJS中的错误,有几种方法? 参考答案: 1) 监听错误事件req.on(‘error’, function(){}), 适用EventEmitter存在的情况; 2) Promise.then.catch(error),适用Promise存在的情况 3) try-catch,适用async-await和js运行时异常,比如undefined object十、 常用知名第三方类库(Async, Express等)1. async都有哪些常用方法,分别是怎么用?参考答案: async是一个js类库,它的目的是解决js中异常流程难以控制的问题.async不仅适用在node.js里,浏览器中也可以使用.1). async.parallel并行执行完多个函数后,调用结束函数async.parallel([ function(){ ... }, function(){ ... } ], callback);2). async.series串行执行完多个函数后,调用结束函数async.series([ function(){ ... }, function(){ ... } ]);3). async.waterfall依次执行多个函数,后一个函数以前面函数的结果作为输入参数async.waterfall([ function(callback) { callback(null, 'one', 'two'); }, function(arg1, arg2, callback) { // arg1 now equals 'one' and arg2 now equals 'two' callback(null, 'three'); }, function(arg1, callback) { // arg1 now equals 'three' callback(null, 'done'); } ], function (err, result) { // result now equals 'done' });4). async.map异步执行多个数组,返回结果数组async.map(['file1','file2','file3'], fs.stat, function(err, results){ // results is now an array of stats for each file });5). async.filter异步过滤多个数组,返回结果数组async.filter(['file1','file2','file3'], fs.exists, function(results){ // results now equals an array of the existing files });2. express项目的目录大致是什么样子的参考答案: app.js, package.json, bin/www, public, routes, views.3. express常用函数参考答案: express.Router路由组件,app.get路由定向,app.configure配置,app.set设定参数,app.use使用中间件4. express中如何获取路由的参数参考答案: /users/:name使用req.params.name来获取; req.body.username则是获得表单传入参数username; express路由支持常用通配符 ?, +, *, and ()5. express response有哪些常用方法参考答案: res.download() 弹出文件下载res.end() 结束responseres.json() 返回jsonres.jsonp() 返回jsonpres.redirect() 重定向请求res.render() 渲染模板res.send() 返回多种形式数据res.sendFile 返回文件res.sendStatus() 返回状态十一、其它相关后端常用技术(MongoDB, Redis, Apache, Nginx等)1. mongodb有哪些常用优化措施参考答案: 类似传统数据库,索引和分区.2. mongoose是什么?有支持哪些特性?参考答案: mongoose是mongodb的文档映射模型.主要由Schema, Model和Instance三个方面组成.Schema就是定义数据类型,Model就是把Schema和js类绑定到一起,Instance就是一个对象实例.常见mongoose操作有,save, update, find. findOne, findById, static方法等.3. redis支持哪些功能参考答案: set/get, mset/hset/hmset/hmget/hgetall/hkeys, sadd/smembers, publish/subscribe, expire4. redis最简单的应用参考答案:var redis = require("redis"), client = redis.createClient(); client.set("foo_rand000000000000", "some fantastic value"); client.get("foo_rand000000000000", function (err, reply) { console.log(reply.toString()); }); client.end();5. apache,nginx有什么区别?参考答案: 二者都是代理服务器,功能类似.apache应用简单,相当广泛.nginx在分布式,静态转发方面比较有优势.HTTP状态码200 - 请求成功301 - 资源(网页等)被永久转移到其它URL404 - 请求的资源(网页等)不存在500 - 内部服务器错误
文章
存储  ·  缓存  ·  移动开发  ·  JavaScript  ·  前端开发  ·  搜索推荐  ·  NoSQL  ·  关系型数据库  ·  API  ·  HTML5
2022-05-23
一文梳理总结HTML+CSS琐碎知识点 快速上手前端开发
一文梳理总结HTML+CSS琐碎知识点1 前端三要素2 HTML2.1 HTML骨架2.2 HTML标签的基本概念2.3 HTML基础标签2.4 HTML高级标签2.4.1 列表2.4.2 表格2.4.3 表单2.4.4 简单布局2.5 字符实体3 CSS3.1 CSS基本概念3.2 CSS基本属性3.2.1 颜色3.2.2 样式表3.2.3 基础选择器3.2.4 高级选择器3.3 层叠性3.4 容器3.5 浮动3.6 定位3.5.1 相对定位3.5.2 绝对定位3.5.3 固定定位1 前端三要素前端三要素如下:HTML:结构层,从语义角度去搭建网页结构CSS:样式层,从美观角度去修饰网页样式JavaScript:行为层,从交互角度去描述网页行为本文主要陈述HTML+CSS。2 HTML2.1 HTML骨架HTML基本骨架如下所示。<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1> hello,world </h1> </body> </html>DOCTYPE表明文档类型,作为文本类型定义(Document Type Definition, DTD)必须在.html文件的首行声明,以告知浏览器文件格式。<html>与</html>标签限定了一个html文档的首末,其属性lang(language)表示改网页的主题语言,en表示英语,zn、cn、zh-CN表示中文。<html>与之间是文档头和文档体。文档头部由<head>标签定义,其中定义了该html文档的属性配置。其中,基本配置由meta标签引导,例如基本框架中的:(1) 字符集配置charset​​修改字符集的方法是同时修改charset属性和编辑器编码模式。字符集字库大小中文特点举例UTF-8涵盖地球上所有国家、民族的语言文字,是一个全面的国际化字库每个汉字占3字节,对中文受众,打开网页速度慢新华网gb2312只有汉语和少量其他符号每个汉字占2字节gbkgb2312的升级,包含汉语更全面每个汉字占2字节腾讯网(2) 浏览器私有设置http-equiv是http响应头,与content组成键值对,当服务器向浏览器发送文档时会先发送这些键值对设置。基本框架中的私有设置含义为,尽可能用高级核浏览器打开网页。(3) 视口标签viewport(4) 网页标题title(5) 网页关键字keywords(6) 页面描述description以腾讯网为例说明(4)~(6)含义,其在<head>中的定义如下,效果如图2.1所示。<title>腾讯首页</title> <meta content="资讯,新闻,财经,房产,视频,NBA,科技,腾讯网,腾讯,QQ,Tencent" name="Keywords"> <meta name="description" content="腾讯网从2003年创立至今,已经成为集新闻信息,区域垂直生活服务、社会化媒体资讯和产品为一体的互联网媒体平台。腾讯网下设新闻、科技、财经、娱乐、体育、汽车、时尚等多个频道,充分满足用户对不同类型资讯的需求。同时专注不同领域内容,打造精品栏目,并顺应技术发展趋势,推出网络直播等创新形式,改变了用户获取资讯的方式和习惯。">2.2 HTML标签的基本概念HTML语法由一系列标签组成,描述网络资源的组织关系。标签按是否成对出现分为单标签和双标签。单标签由一个标签组成,例如<br/>;双标签由“开始标签”和“结束标签”两部分构成,例如<p></p>,其中开始标签<p>表示一个段落的开始,结束标签</p>表示一个段落的结束。标签按能否具有嵌套关系分为文本级和容器级。文本级标签内部只能包含文本,如超链接;容器级标签内部则可以嵌套其他任何标签。标签间对空白、换行、缩进不敏感,HTML语法只关注标签的首末及嵌套关系。多余的空白会占用内存,影响传输效率,工程中应尽量减少不必要的空白,压缩代码。另外,普通文本间由空格、换行、缩进导致的空白会仅被折叠为一个空白占位显示,称为空白折叠现象,因此有意的多个空白占位应用专门的语法表达,例如空白占位符&nbsp。2.3 HTML基础标签(1) 标题标签(headline, h)h系列标签属于容器级双标签,用于给内部内容赋予权重级别的语义。从标题标签内部看,其共分为h1~h6六级标题,权重依次递减;从外部看,标题标签权重比<body></body>中其他标签都高。搜索引擎除了会首先提取meta标签配置的基本属性外,还会优先提取标题内容,h1标题权重最高且约定一个页面仅使用一对h1标签,通常赋予h1标签网页LOGO等职责。(2) 段落标签(paragraph, p)p标签属于文本级双标签,用于给内部内容赋予一个完整段落的语义。(3) 图片标签(image, img)属于文本级单标签,用于插入图片。img标签的常用属性如表所示。序号 关键字 含义1 src 表明图片的引入路径,可为本地路径或HTTP路径2 alt 表明图片未成功加载时的替换文本3 width 设置图片的宽度(Unit: pix)4 height 设置图片的高度(Unit: pix,只设置图片宽高之一时,图片等比例缩放)5 title 设置图片的悬停文本6 border 设置图片边框(Unit: pix),仅为黑色故不常用示例代码: <img src="img/src1.jpg" title="test img" alt="Not Found" width="500"/>(4) 锚点标签(anchor, a)属于文本级双标签,用于给内部内容添加超链接的语义以进行跳转。a标签的常用属性如表所示。序号 关键字 含义1 href 设置为内容添加的超链接路径,页面内跳转则以#开头链接到a标签的name属性,或其他标签的id属性2 target 设置是否新建标签页以打开链接,值为“_blank”3 title 设置文字的悬停文本4 name 设置页面内锚点,实现页面内跳转示例代码:<a href="https://www.baidu.com" target="_blank" title="百度">跳转</a>(5) 链接标签(link)属于文本级单标签,用于定义本html文档与外部资源的关系。link标签的常用属性如表所示。序号 关键字 含义1 href 设置为内容添加的超链接路径2 rel 设置当前文档与被链接文档之间的关系,常用的有图标icon、样式表stylesheet、证书license等3 sizes 设置被链接资源的尺寸,仅适用于rel=“icon”2.4 HTML高级标签2.4.1 列表列表是HTML中由一组标签组成的一种数据结构,分为由ul(Unordered List标签引导定义的无序列表、由ol(Ordered List)标签引导定义的有序列表、由dl(Definition List)标签引导定义的定制列表。约定ul或ol标签内部只能嵌套li(List Item)标签,而li内部则可嵌套其他任何标签;dl标签内部只能嵌套dt(Definition Term)标签——定制列表的自定义主题、术语与dd(Definition Description)标签——一个自定义主题或术语的自定义解释项,ul、ol、li、dl、dt、dd均属于容器级双标签。无序、有序、定制列表代码实例如下所示。<h2>四大名著</h2> <ul> <li> 三国演义 <ul> <li>刘备</li> <li>张飞</li> <li>关羽</li> </ul> </li> <li>水浒传</li> <li>红楼梦</li> <li>西游记</li> </ul><h2>电信学院期末考试排名</h2> <ol> <li>自动化 <ol> <li>自动化1班</li> <li>自动化2班</li> </ol> </li> <li>通信工程 </li> </ol><h2>计算机视觉教程</h2> <dl> <dt>数字图像</dt> <dd> <p>色彩对应电磁波可见光波段</p> <p>是被后期处理的波长信息</p> </dd> </dl> <dl> <dt>透视模型</dt> <dd> <p>生活中常见的透视现象</p> <p>物理本质是光直线传播</p> </dd> </dl>2.4.2 表格表格是HTML中由一组标签组成的一种数据结构,由table引导定义。一个完整的表格由三大分区构成:主题caption、表头thead、主体tbody。caption定义了表格的标题内容。thead定义了表格表头格式,内部只能嵌套tr(Table Rows)——表格行,tr内部嵌套th(Table Header)——表格表头。tbody定义了表格主体格式,内部只能嵌套tr,tr内部嵌套td(Table Dock)——单元格,th除了比td多了表头语义,其余行为完全一致。table、caption、thead、tbody、tr、td、th均属于容器级双标签,其中table标签具有属性border——设置表格边框(Unit:pix)、style——设置CSS样式;tr、td、th标签具有属性rowspan——上下跨行合并单元格数、colspan——左右跨列合并单元格数。<table border="1" style="border-collapse:collapse"> <!-- 主题分区 --> <caption> <p>各地区资产投资情况</p> <p>数据来源:网络</p> </caption> <!-- 表头分区 --> <thead> <tr> <th rowspan="2">地区</th> <th colspan="2">按总量分</th> <th colspan="2">按比重分</th> </tr> <tr> <th>自年初累计(亿元)</th> <th>去年同期增长(%)</th> <th>自年初累计(%)</th> <th>自年同期(%)</th> </tr> </thead> <!-- 主体分区 --> <tbody> <tr> <td rowspan="3">全国</td> <td>283949.99</td> <td>9.8</td> <td>100.0</td> <td>100.0</td> </tr> <tr> <td>283949.99</td> <td>9.8</td> <td>100.0</td> <td>100.0</td> </tr> <tr> <td>283949.99</td> <td>9.8</td> <td>100.0</td> <td>100.0</td> </tr> </tbody>2.4.3 表单表单是HTML中由一组标签组成的一种数据结构,由form引导定义,下面介绍主要的表单控件。(1) 多功能输入框input属于文本级单标签,用于构造单行输入框、单选框、复选框等丰富类型控件。序号 关键字 含义1 value 设置输入框缺省内容2 placeholder 设置输入框没有内容时的输入提示文本3 type 设置输入框类型3.1 text 纯文本3.2 password 密码样式4 radio 单选样式 通过name属性进行分组,通过checked属性设置缺省选中项5 checkbox 复选样式input控件还可使用label标签定义标注。label元素不会向用户呈现任何特殊效果,其作用是当用户选择该标签时,浏览器自动聚焦到和标签相关的表单控件上,使在label元素内点击文本就会触发此控件,为鼠标用户改进了可用性。(2) 多行输入框textarea属于文本级双标签,用于构造多行输入框。序号 关键字 含义1 placeholder 设置输入框没有内容时的输入提示文本2 rows 设置输入框可视区域行数,超出有滚动条3 cols 设置输入框可视区域每行显示字节数(3) 下拉菜单select属于容器级双标签,内部只能嵌套文本级双标签option——下拉菜单项,option通过selected属性设置缺省选中项。下面是表单控件的综合应用实例。<form> <p>用户名:<input type="text" value="winter" placeholder="enter name"/></p> <p>密码:<input type="password" placeholder="enter pwd"/></p> <p> 性别: <label><input type="radio" name="sex" checked="checked"/>男</label> <label><input type="radio" name="sex"/>女</label> <label><input type="radio" name="sex"/>保密</label> </p> <p> 爱好: <label><input type="checkbox" name="hobby" checked="checked"/>打球</label> <label><input type="checkbox" name="hobby"/>游泳</label> <label><input type="checkbox" name="hobby"/>跑步</label> </p> <p> 籍贯: <select> <option>北京</option> <option selected="selected">上海</option> <option>广州</option> </select> </p> <p> 自我介绍: <textarea placeholder="enter personal introduction" rows="4" cols="40"></textarea> </p> </form>2.4.4 简单布局HTML布局标签分为由div引导定义的跨度布局分割和由span引导定义的文字分割,前者为容器级双标签,后者为文本级双标签。布局标签仅用于区域或文本的结构化分类,无具体语义。<font color=#000 size=4>下面是div的代码实例。 <!-- 网页LOGO --> <div> </div> <!-- 导航条 --> <div> <!-- 文本 --> <div></div> <!-- 图片 --> <div></div> </div>下面是span的代码实例。<p>今天一共收入<span style="color: red;">300</span>元</p>2.5 字符实体在HTML中,某些字符为HTML语法预留而无法直接使用,例如HTML中的<和>会被认为是标签;某些字符通过键盘无法打出,例如版权声明符©。上述情况下建议在 HTML源码中使用字符实体以正确显示预留字符,常用的字符实体如表所示。显示结果 描述 实体名称 实体编号空格    < 小于号 < <> 大于号 > >& 和号 & &" 引号 " "’ 撇号 ' (IE不支持) '¢ 分 ¢ ¢£ 镑 £ £¥ 元 ¥ ¥€ 欧元 € €§ 小节 § §© 版权 © ©® 注册商标 ® ®™ 商标 ™ ™3 CSS3.1 CSS基本概念层叠式样式表(Cascading Style Sheet, CSS)主要用于配合HTML结构,添加页面样式、辅助布局。CSS主要由两个元素构成——样式和布局。其中样式分为文字样式和盒模型样式,布局指HTML结构无法完成的功能,例如并排显示、精确定位显示等。3.2 CSS基本属性3.2.1 颜色CSS颜色由属性关键字color定义,用于修饰控件颜色。常用名称表示法、HEX表示法、RGBA表示法等来声明颜色值。3.2.2 样式表名称 优先级 位置 优点 缺点行内式 0 HTML标签内,多个属性用分号分隔 优先级高,样式设置更精确 无法避免重复设置,结构与样式强耦合内嵌式 1 HTML<head>标签底部,由<style>标签引导 可以进行批量设置 结构与样式弱耦合,多个html文档不能共用一套css设置外链式 1 HTML<head>标签底部,由<style>标签引导 结构与样式完全解耦 导入式 2 HTML<head>标签底部,由<style>标签引导 结构与样式完全解耦 有样式加载顺序问题,工程较大时会页面闪烁3.2.3 基础选择器名称 选择对象 用途标签选择器 HTML文档中所有同名标签,忽略嵌套规则加载样式 全选文档同名标签,配置公共样式id选择器 标签中的id属性(标签id属性类似宏定义,约定HTML文档内标签id唯一) 定制某标签的样式类名选择器 HTML文档中class属性相同的标签(标签的class属性可以重名或多个) 同样风格的标签成组统一配置通配选择器 HTML文档内的所有标签 清除页面默认样式标签选择器<style> p{ color: skyblue;} </style> … <p>测试1</p>id选择器<div> <p>测试2</p> </div> <style> #test{ font-size: 20px;} </style> … <p id="test">测试1</p>类名选择器<style> .test{ color: blue; } </style> … <p class="test">测试1</p> <p class="test">测试2</p> <p class="test">测试3</p>通配选择器<style> *{ margin: 0; padding: 0;} </style> … <p>p</p> <h1>h1</h1> <div>div</div> 3.2.4 高级选择器名称 选择对象 用途后代选择器 根据标签间的后代关系确定(后代关系不一定是直接继承,使用空格连接多个选择器确定后代关系) 精确配置某个或某范围标签交集选择器 根据选择器的交集关系确定(使用.表示不同选择器交集) 精确配置某个或某范围标签并集选择器 根据选择器的并集关系确定(使用,表示不同选择器并集) 定制化统一配置后代选择器<style> .box1 ul li{ color: blue;} .box2 li{ color: red;} </style> … <div class="box1"> <ul> <li>box1.ul.li</li> </ul> </div> <div class="box2"> <ul> <li>box2.ul.li</li> </ul> </div>交集选择器<style> p.test{ color: blue;} .test{ color: red;} </style> … <p class="test">p</p> <div class="test">class</div>并集选择器<style> .par li,p{ color: green;} </style> … <div class="par"> <ul> <li>li</li> </ul> </div> <p>class</p>3.3 层叠性CSS层叠性定义为:有多个选择器对某个或某几个标签中的多条样式进行选择,如果多个选择器都赋予某个或某几个标签相同属性不同样式,则样式作用范围发生了冲突,产生层叠现象。CSS层叠性的规则如下:(1) 多个选择器赋予某标签不同属性样式,彼此不冲突(2) 多个同类基础选择器赋予某标签相同属性不同样式,后样式层叠前样式(3) 多个不同基础选择器赋予某标签相同属性不同样式,高优先级样式层叠低优先级(4) 高级选择器层叠性规则① 若发生标签级冲突,则累加计算高级选择器中各基础选择器的优先级,高优先级样式层叠低优先级;② 若未发生标签级冲突,则采用就近原则——继承最近层级选择器的属性;③ 若优先级相同且层级也相同,则后样式层叠前样式。3.4 容器容器是CSS布局的重要数据结构,CSS容器主要属性间关系如图所示,其中容器实际加载区域为 w i d t h × h e i g h t width\times height width×height;容器实体区域为 ( w i d t h + p a d d i n g + b o r d e r ) × ( h e i g h t + p a d d i n g + b o r d e r ) \left( width+padding+border \right) \times \left( height+padding+border \right) (width+padding+border)×(height+padding+border);容器实际占有区域为 ( w i d t h + p a d d i n g + b o r d e r + m a r g i n ) × ( h e i g h t + p a d d i n g + b o r d e r + m a r g i n ) \left( width+padding+border+margin \right) \times \left( height+padding+border+margin \right) (width+padding+border+margin)×(height+padding+border+margin)下面提供几个CSS容器的应用案例。图标制作LOGO超链接3.5 浮动CSS浮动样式使元素脱离标准文档流,实现更多自由度的设计,主要用于网页整体布局等。CSS浮动由float定义,主要有左浮动和右浮动元素设置浮动后,既可以设置宽高,又可以定制化显示,不再区分标准显示模式。父代中的一个子代容器设置了浮动特效,则所有子代均需要设置浮动,否则会打乱布局;容器设置浮动特性后,缺省宽度不再为父代宽度,而为内部实体宽度。给出一个实例:<style> .inner{ width: 970px; height: 970px; margin: 50px auto;} .inner .top{ height: 103px; margin-bottom: 10px;} .inner .top .logo{ width: 277px; height: 100%; background-color: red; float: left;} .inner .top .nav{ width: 679px; height: 100%; float: right; } .inner .top .nav .navListA{ width: 137px; height: 49px; background-color: yellowgreen; float: right; margin-bottom: 8px; } .inner .top .nav .navListB{ width: 679px; height: 46px; background-color: yellowgreen; float: right;} .inner .middle{ height: 435px; margin-bottom: 10px; } .inner .middle .news{ height: 100%; width: 310px; background-color: orange; float: left; } .inner .middle .info{ height: 100%; width: 650px; float: right; } .inner .middle .info .infoAll{ height: 400px; width: 100%; margin-bottom: 10px; } .inner .middle .info .infoAll .infoLeft{ height: 100%; width: 450px; margin-right: 10px; float: left; } .inner .middle .info .infoAll .infoLeft{ height: 240px; width: 100%; background-color: skyblue; margin-bottom: 10px;} .inner .middle .info .infoAll .infoLeft .infoLeftMid{ height: 110px; width: 100%; background-color: skyblue; margin-bottom: 10px;} .inner .middle .info .infoAll .infoLeft .infoLeftBottom{ height: 30px; width: 100%; background-color: skyblue; margin-bottom: 10px; } .inner .middle .info .infoAll .infoRight{ height: 100%; width: 190px; background-color: purple; float: right; } .inner .middle .info .infoAbs{ height: 25px; width: 100%; background-color: darkgreen; } .inner .bottom{ height: 35px; background-color: navy; } </style> ... <div class="inner"> <!-- 顶部布局 --> <div class="top"> <div class="logo"></div> <div class="nav"> <div class="navListA"></div> <div class="navListB"></div> </div> </div> <!-- 中间布局 --> <div class="middle"> <div class="news"></div> <div class="info"> <div class="infoAll"> <div class="infoLeft"> <div class="infoLeftTop"></div> <div class="infoLeftMid"></div> <div class="infoLeftBottom"></div> </div> <div class="infoRight"></div> </div> <div class="infoAbs"></div> </div> </div> <!-- 底部布局 --> <div class="bottom"></div> </div>3.6 定位CSS定位指将容器按指定位置加载,主要分为不脱离标准流的相对定位,以及脱离标准流的绝对定位和固定定位。序号 关键字 含义1 position 设置定位模式,常用属性值为relative(相对定位)、absolute(绝对定位)、fixed(固定定位)2 left 设置从参考点开始,从左往右定位的距离3 right 设置从参考点开始,从右往左定位的距离4 top 设置从参考点开始,从上往下定位的距离5 bottom 设置从参考点开始,从下往上定位的距离3.5.1 相对定位参考点为设置定位元素所在的容器。下面为使用相对定位实现导航条的案例。<style> div ul{ width: 640px; height: 60px; font-size: 20px; margin: 100px auto; } div ul li{ width: 120px; height: 100%; background-color: navy; float: left; margin-right: 2px; text-align: center; line-height: 60px; } div ul li:hover{ background-color: white; } div ul li a{ display: block; color: white; margin: auto auto; } div ul li a:hover{ background-color: cyan; position: relative; bottom: 10px; } </style> ... <div> <ul> <li><a href="#">测试</a></li> <li><a href="#">测试</a></li> <li><a href="#">测试</a></li> <li><a href="#">测试</a></li> <li><a href="#">测试</a></li> </ul> </div>3.5.2 绝对定位参考点为设置绝对定位的元素所在容器的父代容器,前提是父代容器设置定位属性,否则以网页body为参考。由于相对定位元素不脱标,结构更稳定,因而父代容器常使用相对定位,子代元素则使用绝对定位。<style> div.father{ width:400px; height: 300px; border: 2px dashed red; margin: 100px auto; position: relative; } div.test{ width: 150px; height: 150px; font-size: 20px; border: 2px solid blue; position: absolute; top:50%; left: 50%; margin-left: -75px; margin-top: -75px; padding: 20px; } </style> ... <div class='father'> <div class="test"> 测试测试测试测试测试测试测试测试测试测试 </div> </div>3.5.3 固定定位参考点为浏览器页面。<style> body{ height: 2000px; } a{ display: block; width: 100px; height: 100px; font-size: 15px; border:3px solid red; border-radius: 50%; padding: 25px 30px; position: fixed; right: 80px; bottom: 80px; } </style> ... <a class="cir" href="#">返回顶部</a>
文章
前端开发  ·  搜索推荐  ·  JavaScript  ·  vr&ar  ·  数据安全/隐私保护  ·  Ruby  ·  容器
2022-04-19
《TCP IP 详解卷1:协议》阅读笔记 - 第十八章
阅读须知:笔记为阅读《TCP IP 详解卷1:协议》后摘抄的一些知识点,其间也有加入一些根据英文原版的自己翻译和结合网上知识后的理解,所以有些段落之间并不能够串联上或者知识点与书上略有差别(基本差别不大,参考的资料属RFC官方文档)。   第十八章:安全:可扩展身份认证协议、IP安全协议、传输层安全、DNS安全、域名密钥识别邮件 任何由用户或以用户账号执行却违背了用户本身意愿的软件被称为恶意软件 网络安全是一门十分广泛及有深度的学识,而本书旨在了解TCP/IP协议族知识,所以书中只介绍了一些TCP/IP所使用的部分安全方案。并且对安全这块我也没多少深入的研究,也就基于书本内容做些知识摘抄以供了解和学习。 信息安全基础 从信息安全的角度看,无论是否在计算机网络中,信息都该具有一些属性:   1. 机密性,信息只能为其指定的用户知晓。   2. 完整性,信息在传输完成之前不能够通过未授权的方式修改。   3. 可用性,在需要的使用信息是可用的。   4. 可认证性,一个经过身份认证的组织或个体是不能够被其他个体假冒的。   5. 不可抵赖性,一个个体做出的任何行为都能够在此之后得到证实。   6. 可审计性,一些可信的日志或说明能够面试信息使用的过程。 前三者是重要的核心属性,又称'CIA三元组'。 根据[VK83],攻击通常被分为被动和主动两类。被动攻击一般会监视或窃听网络流量的内容,如果不加以控制,它将会导致信息未经授权就发布出去,这破坏了信息的机密性。主动攻击一般会篡改信息或使其拒绝服务,这破坏了信息的完整性和可用性。 被动攻击:   窃听(机密性)   流量分析(机密性) 主动攻击:   消息流篡改(可认证性,完整性)   拒绝服务DoS(可用性)   伪造机构(可认证性) 通过加密机制,即可满足以上两种攻击的防御需求,通过加密后的数据不容易泄露信息内容、不容易破坏其完整性、也更安全的保障了可认证性。 基础的加密和相关知识 传统的基础加密主要用于保护信息的机密性,但其他属性如完整性和可认证性也能够借助加密以及相关的数学技术达到。下面的图说明了两个重要的加密算法:对称密钥和公开(非对称)密钥是如何工作的。 在对称密码系统中,由于加解密的算法相同,它们的密钥也是相同的。 在非对称密码系统中,每一个个体都拥有一对密钥,包括一个公钥和一个私钥。公钥是公开的,任何希望向这对私钥所有者发送消息的人都能够获得。公钥和私钥有数学上的关联,它们都是密钥生成算法的输出结果。如果不知道对称密码系统中的对称密钥或非对称密码系统中的私钥,任何第三方截获密文后都无法生成相应的明文。 对称密码算法通常被分为分组密码(或称块密码)与流密码两类。分组密码每次只对固定数目的比特块进行操作,而流密码将提供的大量比特作为输入并且会持续的运行下去。多年来流行的对称密码算法是数据加密标准(DES,是一种分组密码,使用64比特的数据块与56位的密钥)。该算法最终被认为不安全,后期采用3重DES利用两个或三个不同密钥对每一个数据块进行三次DES加密。但无论DES还是3DES,现在都逐渐被高级加密标准(AES)所取代[FIPS197]。AES针对不同版本所提供的密钥长度,如128位、192位、256位,于是就有了AES-128、AES-192、AES-256。 如上图,非对称密码算法存在一个问题:发送者使用接收者的公钥进行消息加密后发给接收者,那么只能拥有接收者私钥才能够对消息进行解密,然而这个消息不能保证是真实可靠的(因为任何人都能够发送这条消息给接收者)。于是基于非对称加密的公钥-密钥的关联性,非对称密码系统提供了另一项功能:对发送者进行认证。 该功能由将公钥加密和私钥解密反向操作而实现,如下图: 流行的公钥密码算法如RSA,在其初始化阶段,需要生成两个大素数p和q。这项工作首先需要随机地生成数值较大的奇数,后检验这些数是否为素数,直到找到两个大素数为止。两个素数的乘积 n = pq 被称为模。n,p,q的长度一般用比特来衡量。推荐n采用2048比特的长度,但通常情况下n为1024比特,p和q的长度为512比特。 根据RSA算法,n的构建方法为: Φ(n) = (q - 1)(p - 1) Φ(n)的值表示n的欧拉数,是那些比n小且与n互质的正整数的个数。 根据Φ(n)的定义,选择RSA的公钥指数(称为e,表示加密),并按照关系式d = e(^-1)(modΦ(n))得到私钥指数(称为d,表示解密)作为乘法逆元素。为获取密文c,需要使用公式m = m(^e)(mod n)对明文m进行计算;反之则需要公式m = c(^d)(mod n)进行解密。一个RSA的公钥包含公钥指数e和模n,对应的私有则包含私钥指数d和模n。如果为了对一条消息m进行RSA数字签名,可以通过公式s = m(^d)(mod n)计算s的数值作为m的签名。任何接收到s的人能够使用公有元素e与公式m = s(^e)(mod n)进行检验,这样就能够验证生成数值s的是RSA的私有值d。RSA的安全性是基于对大数分解因数的困难性。 Diffie-Hellman-Merkle 密钥协商协议(DH)提供了一种解决"通信双方如何在窃听者不知情的情况下完成共同密钥协商"的计算方法,DH技术已用于许多与互联网相关的安全协议[RFC2631]。 DH的工作如下描述:   1. 假设所有人都有相同的特征,并且知道两个证书p和q。p是一个(大)素数,g是模p的原根(g<p)。   2. 基于1,集合Z(_p) = {1,...,p-1}中的每一个整数都能够通过不断地增加g来生成,也就是说对于任意一个证书n,必定存在倍数k使式子g(^k) ≡ n(mod p)成立。在给定g、n与p的情况下寻找合适的k值被认为是一件困难的事(离散对数问题),在给定g、k与p的情况下找出n是容易的。 建立一个共享的安全密钥过程如下(A和B之间):   1. A选择一个秘密的随机数a,并按照公式 A = g(^a)(mod p)计算出A的值,然后将这个值发送给B;B选择一个秘密的随机数b,并按照公式 B = g(^b)(mod p)计算出B的值,然后将这个值发送给A。   2. A将按照以下公式计算K值:K = B(^a)(mod p) = g(^ba)(mod p);B将按照以下公式计算K值:K = A(^b)(mod p) = g(^ab)(mod p)。 由于g(^ab)和g(^ba)是相等的,所以A和B都能获得协商密钥K。第三方窃听者只能获取g、p、A、B,因此在解决离散对数问题之前将无法获取密钥K。 在通信双方需要交换多条消息的场景中,通常会建立一个短期的会话密钥来进行对称加密。会话密钥一般由密钥派生函数(KDF)根据一些输入而生成的随机数,这些输入可能是一个主密钥或之前的会话密钥。如果一个密钥被破解,那么由该密钥加密的任何数据都会被破解,然而在一个持续的通信会话期间,往往会多次更改密钥。如果一种方案能够保证即使有一个会话密钥被破解而由其他密钥加密的后续通信过程仍然安全,那么就称该方案是完全正向保密(PFS)的。通常情况下能够提供完全正向保密的方案需要额外的密钥交换与认证过程,这样就引入了新的开销。 加密随机数是在密码协议中只使用一次的数值(又称临时密钥)。常用于认证协议,选择一个随机数或者伪随机数来保障时新性(时新性要求选取最新发生的消息或操作)。例如,在一个challenge-response协议中,服务器会为请求的客户端提供一个临时密钥,而客户端需要在指定时间内发送认证资料与临时密钥的副本作为响应。由于重放到服务器上的旧的认证交换信息不会包含正确的临时密钥数值,因此这种方法能够避免重放攻击。 混淆值是一个用于加密文本中的随机数或者伪随机数,可用于防御对密文的蛮力攻击(反复地猜测密码、口令、密钥或等效的秘密中并验证其是否正确)。 加密散列函数,类似于部分加密算法,用于做传输数据完整性的保障及预防对消息的篡改攻击。当一条消息M作为输入时,加密散列函数的输出H被称为这条消息的摘要或指纹H(M)。它不仅易于计算,还具有以下特征:   1. 原像不可计算性,在给定摘要H(M)而未知消息M的情况下,难以得出消息M的值。   2. 原像不相同性,给定消息M1的摘要H(M1),找出消息M2(M1 ≠ M2)使它的摘要与M1的摘要相等(H(M1) = H(M2))是十分困难的。   3. 抗碰撞性,找出一堆摘要相同(H(M1) = H(M2))而自身不同的消息M1、M2(M1 ≠ M2)是十分困难的。 目前最通用的两个加密散列算法是生成128位摘要的消息摘要算法(MD5)和生成160位摘要的安全散列算法(SHA-1)。SHA-2基于一系列SHA函数,能够生成长度224,256,384,512位的摘要。 消息认证码(简称MAC或MIC),一般基于有密钥的加密散列函数,用于保障消息的完整性和防止各种伪造。这些函数类似于消息摘要算法,但需要一个私钥来验证消息的完整性,甚至也可能用于验证消息的发送者。给定有密钥的散列函数H(M,K),M为输入的消息,K是密钥,抵御"选择性伪造"意味着地方在不知道密钥K的情况下对指定的消息M生成散列值H(M,K)是非常困难的。消息认证码由于不止有一方知道对应的密钥,所以并不能为不可否认性提供坚实基础。 一个标准的使用加密散列函数的消息认证码被称为基于有密钥散列的消息认证码(HMAC),下面的公式定义了使用密钥K对消息M用H进行散列的方法(HMAC-H),它形成t字节的HMAC: HMAC-H(K,M)(^t) = Λ(_t)(H((K ⊕ opad) || H((K ⊕ ipad) || M))) opad(外填充)是一个将数值0x5C重复|K|次的数组,ipad(内填充)是讲数值0x36重复|K|次的数组。⊕是向量的异或运算符,||是连接运算符,Λ(_t)表示取消息M最左边的t字节。其中的将一个散列函数作用于另一个散列函数的结构能够抵御所谓的扩展攻击,内填充与外填充的数值并不重要,但生成的2次密钥K1与K2需要有较大的区别。 随着消息认证码多年以来的发展,一些其他形式的消息认证码已经被标准化,比如基于密码的消息认证码CMAC、GMAC。这些新标准不使用HMAC的加密散列函数,而是使用分组密码,如AES。根据[RFC4493]描述,CMAC使用的是AES-128算法。GMAC则采用了AES算发的一种特殊模式,称为Galois/计数器模式,它仍然使用一个有密钥的散列函数(GHASH,并不是一个加密散列函数)。 证书相关知识 一种被称为"信任网络"的模型:通过一些当前用户(称为代言人)来做代言的方式以证明一个证书(身份-公钥对)的可靠性。一个代言人会对一个证书进行签名,然后将其发布出去,随着时间推移,如果一个证书有越来越多的代言人,那么它就越可靠。该模型是分散的、没有中心的权威机构,因此它具有一定的"草根"性。"信任网络"的优缺点显而易见,有点是其不存在中心的权威机构,模型不会因为单点失效而奔溃;缺点是新加入者需要经历相当长的时间才能使自己的密钥得到一定数量用户的代言。 一种更常见的方法是依靠中心化的机构,其中包括对公钥基础设施(PKI)的使用,PKI负责提供创建、吊销、分发以及更新密钥对证书的服务。它需要一些证书颁发机构(CA)才能运行,CA是用于管理与认证一些个体与它们的公钥间的绑定关系的实体。 ITU-T X.509 是公钥证书的格式标准[RFC5280],常见的的包括DER、PEM、PKCS#7、PKCS#12。 可用 openssl 命令来查看网站证书信息: openssl x509 -in xxx.pem -text 给出结构大致: Certificate: 解码后的证书信息 Data: 元数据 Version: 版本,特定的证书类型 Serial Number: 特定证书的序列号 Signature Algorithm: 签名算法 Issuer: 发行者,拥有以下特殊子域:C(国家)、L(地区或城市)、O(组织)、OU(组织单元)、ST(州或省)、CN(通用名称) Validity: 有效时间 Not Brfore: 起始时间 Not After: 结束时间 Subject: 主题,标识与当前证书相关的实体 Subject Public Key Info: 主题公钥信息,标识公钥的拥有者 Public Key Algorithm: 公钥算法 Public-Key: 公钥 Modulus: 模 ... Exponent: 指数 Signature Algorithm: 签名算法 ... -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- # ... 根据字段决定值类型,代表密钥/签名等结果内容 在证书撤销的过程中,需要考虑一些问题'如何撤销证书?'、'如何让依赖方知道他们所依赖的证书不再可信?'。 为了验证某个证书,需要建立一条验证(或认证)路径,这条路径应当是一个已被验证过的证书集合,通常会包含依赖方已经的信任锚点(例如,根证书)。验证过程的一个关键步骤在于确定证书链中的一个或多个证书是否已被撤销。若是,则验证路径将失效。 互联网中实现证书撤销的两种方法:证书撤销列表(CRL)和在线证书状态协议(OCSP)[RFC2560]。 CRL:一个被签署的列表,它指定了一套证书发布者认为无效的证书。除了普通CRL外,还定义了一些特殊的CRL类型用于覆盖特殊领域的CRL。 OCSP:一个应用层的请求/应答协议,通常运行在HTTP协议之上。当用户试图访问一个服务器时,在线证书状态协议发送一个对于证书状态信息的请求,服务器回复一个"有效"、"过期"或"未知"的响应。 OCSP克服了CRL的缺陷:必须经常在客户端下载以确保列表的更新。 TCP/IP安全协议与分层 存在与OSI协议栈中各层次以及一些'中间'层的安全协议,如下: 层号 层名称 实例 7 应用层 DNSEC/DKM/EAP/Diameter/RADIUS/SSH/Kerberos/IPsec(IKE) 4 传输层 TLS/DTLS/PANA 3 网络层 IPsec(ESP) 2 链路层 802.1X(EAPoL)/802.1AE(MACSec)/802.11i/WPA2/EAP 网络访问控制 网络访问控制(NAC)是指对于特定系统或用户而言用于授权或拒绝网络通信的方法。 由IEEE定义的802.1X基于端口的网络访问控制(PNAC)标准广泛用于TCP/IP网络,为企业局域网提供安全,其中包括有线和无线网络。PNAC的目的在于只有当系统或用户基于网络接入点完成认证后,才会为其提供网络访问服务。由于常与IETF标准的可扩展身份验证协议(EAP)配合使用[RFC3748],所以802.1X协议有时也称为局域网上的EAP协议(EAPoL)。2010年的版本[802.1X-2010]还包括了802.1AE(IEEE的局域网加密标准,称为MACSec)与802.1AR(面向安全设备表示的X.509证书),还包括了一个比较复杂的MACSec密钥协商协议MKA。 EAP可与多种链路层技术一同使用,并提供多种方法来实现身份验证、授权及计费(AAA)。然而EAP本身并不执行加密,所以它必须与其他一些加密功能矫情的协议一同才能保证安全。如下图是EAP的一个实例设置: 上图假设了一个包括有线和无线端点的企业网络,这个受保护的网络包括了AAA服务器、特殊虚拟局域网中的内网服务器以及一个不需要认证的虚拟局域网。认证者负责与未认证端点以及AAA服务器进行交互以确定是否给予每个端点访问受保护网络的权限。上图认证者能够以'直通模式'允运行,以帮助认证者免于执行大量的认证方法。 EAP数据包的格式非常简单,如图所示: 代码字段包含了6中EAP数据包类型之一:请求(1)、响应(2)、成功(3)、失败(4)、初始化(5)、结束(6)。 标识符字段包含了一个由发送者选择的序号,用于匹配请求与响应。 长度字段给出了EAP消息的字节数(含代码、标识符、长度)。 典型的EAP交互过程:   1. 从认证者发送一个请求消息给端点;   2. 端点以一条响应消息作为回应,两条消息使用的格式相同。 请求与响应消息的主要目的在于交换实现成功认证所需要的信息,如下图: EAP消息承载着端点与认证者之间的认证材料。 EAP是一个支持自身的多路复用与多路分解的分层体系结构,从概念上讲,它包括四个层次:底层、EAP层、EAP端点/认证者层、EAP方法层。底层负责有序的传输EAP帧;EAP层实现可靠性和消除重复;EAP端点/认证者层负责实现端点与认证者协议的消息,基于对代码字段的多路分解实现;EAP方法层包含了所有用于认证的特殊方法,包含任何用于处理大消息的协议操作。 网络接入认证信息承载协议(PANA)作为EAP的下次,扮演着EAP信息承载者的角色,它使用UDP/IP协议(端口号716),因此能够用于多种类型的链路,并且不限于点对点的网络模型。 PANA的框架包含了三个主要的功能性实体,PANA客户端(PaC)、PANA认证代理(PAA)、PANA中继原件(PRE):   PANA的用途通常包含认证服务器(AS)和执行点(EP),AS是一个通过访问协议访问的常规AAA服务器。   PAA负责将认证材料从PaC传输至AS,并且在网络访问被批准或撤销时对EP进行配置。   PaC与PAA之间的直接通信不能实现时,PRE可用于两者之间的中继通信。 PANA协议由一组请求/响应消息构成,包括一个有"属性-值"对组成的扩展集合。PANA会话包含4个节点:认证/授权、访问、重新认证、终止。重新认证实际上是访问阶段的一部分,所以重新认证后会话的生存期也得到相应的扩展。终止节点一般会以明确的方式进入,也会因为会话超时而进入。 PANA是一个弱传输协议,它按照"stop-and-wait"模式工作,没有使用自适应的重传计时器,不能够对数据包进行重新分组。当出现多个数据包丢失的情况时,它的重传计时器会以指数的方式进行回退。 IP安全(IPsec) IPsec的操作可分为建立阶段和数据交换阶段。建立阶段负载交换密钥材料并建立安全管理(SA);数据交换阶段会使用不同类型的封装架构,称为认证头部(AH)与封装安全负载(ESP)。 一个完整的IPsec包含了SA建立协议、AH(可选)、ESP以及一些合适的加密套件、配置信息与设置工具。[RFC6071]总结了所有IPsec组件的发展过程与当前规范。 IPsec会有选择地针对某些数据包进行操作,这些操作基于管理员所设定的策略。所有的策略都包含在一个安全策略数据库(SPD)中,逻辑上与每一个IPsec的实现相伴。IPsec还需要两个额外的数据库,称为安全关联数据库(SAD)和端点认证数据包(PAD)。下图简单的描述了需要如何使用这些数据库及如何处理数据包: SA IPsec的第一步就是建立SA,SA是在两个通信方之间建立的单工(单向)认证关联。常见的情况是双方之间的双向通信,因此需要一对SA才能有效地使用IPsec,特殊协议Internet密钥交换(IKE)自动完成这项工作。IKE开始于一个简单的请求/响应消息对,该消息对包括一个建立以下参数的请求:加密请求、完整性保护算法、Diffie-Hellman组,以及根据任何输入的比特串随机生成输出的PRF(PRF用于生成会话密钥)。 IKE的前两次交换称为IKE_SA_INIT和IKE_AUTH,建立一个IKE_SA和CHILD_SA。随后出现两个交换,其中CREATE_CHILD_SA交换用于建立其他的CHILD_SA,INFORMATIONAL交换则用于初始化SA中的变化或收集SA的状态信息。IKE消息封装在UDP中通过端口500或4500发送,而IKE的接收者则应该准备接收来自任何端口的流量。 IKE消息格式如下: SPI,安全参数索引,一个64位的号码,用于标识一个特定的IKE_SA,发起者和响应者都会有一个属于自己的SA,所以它们能提供正在使用的SPI,这一对SPI值能够与通信两端的IP地址结合起来用于形成一个有效的连接标识符。 下一个负载字段指出了后面负载的类型。 主要版本字和次要版本字段应分别设置为2和0,当无法维持版本直接的互操作性时,主要版本号就会被修改。 交换类型字段给出了消息的交换类型,包含:IKE_SA_INIT(34),IKE_AUTH(35),CREATE_CHILD_SA(36),INFORMATIONAL(37),IKE_SESSION_RESUME(38),其他数值被保留,240~255范围被留作私人用途。 标志位字段定义了一个3比特位的字段:I(发起者,第3位),V(版本,第4位),R(响应者,第5位)。I由原始发起者设置,接收者会在返回消息中将其清除;V指出一个版本号,高于发送者当前使用的协议的主要版本号;R指出当前消息是之前某一消息的响应,与其使用相同的消息标识符。 消息标识符字段是于TCP序列号类似的功能,标识包含该标识符的数据流的第一个字节。不同的是发起者消息标识符从0开始,而响应者从1开始。无论是在发送还是接收时,消息标识符都会被记录下,这样做可以帮助每一个通信端检测重放攻击。 长度字段统计了IKE消息头部和所有负载的合计大小。 IKEv2负载类型表,数值0表示没有下一个负载: "通用"的IKEv2负载头部如下图所示: 通用的负载头部固定为32位,下一个负载与负载长度字段提供了一个大小可变的负载"链"(最多位65535字节,包括负载头部的4字节)。C位指出当前负载对于一个成功的IKE交换而言被认为是"关键"的。 IKE_SA_INIT与IKE_AUTH交换过程: HDR IKE 头部(非有效载荷);SAi1/SAr1(SAi2/SAr2)分别表示发起者和响应者可支持的密码算法套件,数值表示阶段;KEi/KEr表示双方的 Diffie–Hellman密钥交换内容和一次性随机数。 CREATE_CHILD_SA交换用于创建或更新一个CHILD_SA,或用于更新一个IKE_SA。交换过程如下: INFORMATIONAL交换用于传输状态与错误信息,通常使用N(通知)负载。交换过程如下: AH IP认证头部(AH)[RFC4302]是IPsec协议套件的可选部分,提供了一种源认证与保护IP数据报完整性的方法。 看下IPsec AH处理后的IP头部(IPsec头部): IPsec AH处理后的隧道模式IP头部: AH结构: 下一个头部字段指出下一个类型值。 负载长度字段指出AH的长度。 保留字段作为保留。 安全参数索引字段包含一个32位的位于接收者端的SA标识符,指出AH属于哪个SA,随着每一个SA数据包的发送而增1。 序列号字段,如果开启,则用于重放保护。 完整性校验值字段是可变的,且依赖于使用的密码套件,该字段在长度上保持为32比特的整数倍。 ESP IPsec的封装安全负载(ESP)[RFC4303],也称作ESP(v3)(注意,其本身并不提供正式的版本号),提供了一个可选的组合,包括机密性、完整性、原始认证以及对IP数据报的反重放保护。 看下IPsec ESP处理后的IP头部(IPsec头部): IPsec ESP处理后的隧道模式IP头部: ESP结构: 安全参数索引字段包含一个32位的位于接收者端的SA标识符,指出ESP属于哪个SA,随着每一个SA数据包的发送而增1。 序列号字段,如果开启,则用于重放保护。 负载数据以32位(IPv6中64位)为边界终止,并且最后两个8位字段能够识别填充长度与下一个头部字段值,填充、填充长度、下一个头部字段共同构成了ESP尾部。 完整性校验值字段是一个长度可变的尾部,用于启用完整性支持以及满足完整性检验算法的需要。它会对ESP头部、负载以及ESP尾部进行计算。ICV的长度取决于所选择的特定完整性检验方法,因此它会在相关的SA建立之后才建立起来,并且要求SA在其生存期中不发生改变。 传输层安全(TLS和DTLS) 传输层安全(TLS)用于保证Web通信以及其他流行协议的安全,其面向数据报的版本成为数据报传输层安全(DTLS)。 TLS协议本身分为两层:记录层和上层。如图所示: TLS是一个客户端/服务器协议,设计用于为两个应用程序的连接提供安全。记录协议提供分片、压缩、完整性保护及客户端与服务器之间所交换数据的加密服务。信息交换协议(即上层协议)负责建立身份、进行认证、提示警报、以及为用于每一条连接的记录协议提供唯一的密钥材料,其包含4个特殊的协议:握手协议、警告协议、密码变更协议、应用数据协议。 记录协议 记录协议使用一个可扩展的记录"内容类型"值集合来识别可多路复用的消息类型。 在任何给定的时间点时,记录协议有一个活跃的当前连接状态和一组被称为挂起连接状态的状态参数;每一个连接状态又进一步被划分为读状态和写状态;每个状态又指定一个压缩算法、加密算法和用于通信的MAC算法,同时还包括必需的密钥与参数。 TLS记录过程: 压缩算法可以为NULL压缩协议,即不提供任何压缩,且压缩算法应该是无损的,产出的输出结果不能大于输入记录的1KB。为了防止负载被披露或修改,加密与完整性保护算法会将TLS压缩结构转换为能够在底层传输层连接上发送的TLS密文结构。 消息交换协议  TLS的三个子协议是通过数字分辨的,这些数字被记录层用于多路复用和多路分解,比如握手协议(22)、警告协议(21)、密码变更协议(20)。 密码变更协议包括一个单字节的消息,该字节的数值为1,该消息的目的在于指出通信一方希望将当前状态修改为挂起状态。如果收到这条消息,就将读挂起状态作为当前状态并指示记录层尽快转换至挂起写状态。 警告协议用于从TLS脸颊的一端向另一端传递状态信息,它可以包括一些终止条件或非致命的错误条件。 握手协议建立了与连接相关的运行参数。它允许TLS端点完成6个主要目标:协商加密算法并交换形成对称密钥时使用的随机值;建立算法运行参数;交换证书并执行互相认证;生成特定的会话密钥;为记录层提供安全参数;验证所有的操作都已正确执行。 握手协议过程:   1. 客户端向服务端发送第一条ClientHello消息,该消息包含:会话标识符、建议的加密套件变化(CS)、一套可接受的压缩算法、TLS版本号、一个称为ClientHello.random的随机数。   2. 服务端接收到ClientHello消息,检查其中的会话标识是否存在其缓存中。如果存在,则服务端通过一个简化的握手过程继续之前已有的连接(称为重新开始)。服务端通过ServerHello消息将服务端的随机数ServerHello.random传递至客户端,完成了交换的第一部分。这条消息也包含一个会话标识符,如果它的数值与客户端的数值相同,则表明服务端愿意重新开始;否则其数值为0表示需要开启一个完整的握手过程。如果服务端需要通过身份验证,会要求它在证书(Certificate)消息中提供自己的证书链。如果证书的签名是无效的,那么服务器可能还需要发送一个服务器密钥交换消息,使其在没有证书的情况下通过一个暂时或短暂的密钥生成会话密钥。   3. 客户端收到服务端返回信息并确认后,以一个握手协议已完成消息(Finished)结束。 如下图: 在缺乏可靠传输层的情况下提供类似TLS服务的主要挑战在于数据报可能会丢失、重新排序或重复。这些问题会影响到加密与握手协议,这两者都依赖于TLS协议。为了处理这些问题,DTLS为记录层承载的每一条记录添加了一个明确的序列号,在每一条ChangeCipherSpec消息发送之后这些序列号被重置为0。 在DTLS中的MAC计算修改了对应的TLS版本,包含了一个由两个新字段组成的64位块,以允许单独处理每一条记录。注意:在TLS中一个错误的MAC会导致连接终止;而在DTLS中,终止一个完整的连接是没有必要的,接收者会选择简单地丢弃包含错误MAC的记录,或是发送一条警告消息。 重复的消息会被简单地丢弃,或者被视为一个潜在的重放攻击。如果支持重放检测,那么将会在接收端设置一个当前序列号窗口。要求该窗口只是容纳32条消息,建议至少64条。以下列出接收到消息后的行为:   1. 如果到达记录的序列号小于窗口左边沿对应的数值,那么会将它视为旧的或重复的记录而默默地丢弃;   2. 那些在窗口之内的记录也会被检查,看是否出现重复;   3. 如果一条消息在窗口之内并且拥有正确的序列号,即便出现顺序错乱的情况也会将其保留下来;   4. 而那些拥有错误MAC的消息会被丢弃;   5. 有正确MAC却超出窗口右边沿的消息会使得右边沿增加。 因此,右边沿代表已验证消息的最高序列号。 为了处理消息丢失的问题,DTLS具有简单的超时和重传功能。重传功能是以消息组的形式运行的,也被称为"班次"。 上图初始的完整交换(左)包含6个班次的信息,每个班次都能够持续传输。DTLS简化交换(右上)只使用3个班次,且与TLS略不同。DTLS在处理协议时报错一个拥有三个状态的有限状态机(右下)。 状态机的三个状态分别为:准备、发送、等待。状态机由一个重传计时器驱动,它的默认建议值为1秒。如果在超时期限内接收不到某一班次的响应,就会使用相同的握手协议序列号重新传输这一班次。然而需要注意的是,记录层序列号仍然会向前增加。后续重传如何没有获得响应将会使RTX的超时值加倍,至少高达60s。在一次成功传输或一个长的空闲期后会重置该数值。 在DTLS中,当一台服务器接受到一条ClientHello消息,它会生成一条心的包含32位cookie的HelloVerifyRequest消息。后续的ClientHello消息必须包含之前的cookie,否则服务器会拒绝交换。这被DTLS用于防御DoS攻击。 DNS安全(DNSEC) DNS的安全不仅指DNS中的数据(资源记录,RR)安全,还包含在同步或更新DNS服务器内容时的传输安全。针对其部署的安全机制称为域名系统安全扩展(DNSSEC)[RFC4033][RFC4034][RFC4035]。DNSSEC提供了DNS数据的源认证与完整性保护,以及(有限的)密钥分发设施。DNSSEC还能够进行不存在性验证,DNS响应能够指出某一受保护的特定域名是不存在的并对此提供保护。DNSSEC不能为DNS信息提供保密性、DoS攻击保护以及访问控制。 当执行一个带有DNSSEC的DNS查询时,一个已知安全的解析器就会使用DNS扩展机制(EDNS0),并且将请求中一个OPT元资源记录的DO位置位(表示DNSSEC OK)。该位指出客户端不仅有兴趣而且有能力来处理DNSSEC相关的信息并支持EDNS0。DO位在EDNS0元资源记录的"扩展的RCODE与标志"部分,是其中第2个16位字段的第1位。接收到那些DO位未置位(或不存在)请求时,会禁止服务器返回大多数资源记录,除非这些记录是在请求中明确要求的。 当服务器处理来自一个DNSSEC可用解析器的请求时,它会检测DNS请求的CD(Checking Disabled)位,如果该位置位,那么表明客户端愿意接收包含未验证数据的响应。在准备一个响应时,服务器通常会利用密码方法验证要返回的数据,成功的验证结果会使得响应中的AD(Authentic Data)位置位[RFC4035]。如果拥有一条到达服务器的安全路径,那么一个安全已知但未验证的解析器在原则上是能够信任这条信息的。然而,最好的情况是使用验证存根解析器,它能够进行加密验证,从而将查询的CD位置位。这样不仅提供了端到端的DNS安全(即中间解析器不需要是可信的),还减少了中间服务器的计算负担;否则,这些中间服务器不得不进行密码验证。 DNSSEC 资源记录 DNSKEY,用以维护公钥。密钥只能与DNSSEC一起使用;其他的资源记录可能用于维护针对其他用途的密钥或证书。 DNSKEY资源记录格式如下图: DNSKEY资源记录的RDATA部分包含一个只用于DNSSEC的公钥,标志字段包含了一个区域密钥指示符(第7位),如果置位,那么DNSKEY资源记录拥有者的名称必须为区域的名称,并且所包含的密钥也被称为区域签名密钥(ZSK)或密钥签名密钥(KSK),如果未置位,那么记录将会维护另一种不能用于验证区域签名的DNS密钥;一个安全入口点指示符(第15位)作为调试或签名软件时的一条提示,能够根据密钥的用途做出明智的猜测,签名验证不会解释SEP位,但该位置位的密钥通常为KSK,并通过验证子区域的密钥来确保DNS层次结构的安全;一个撤销指示符(第8位),如果置位,则表示密钥不能用于验证。算法字段指出了签名算法,根据[RFC4034],只有DSA与具有SHA-1的RSA(值分别为3和5)才被定义用于DNSKEY资源记录。公钥字段维护了一个公钥,它的格式依赖于算法字段。 DS,授权签名者资源记录用于指定一条DNSKEY资源记录,通常从一个父区域到一个子区域。 DS资源记录格式如图: 密钥标签字段包含了对一条DNSKEY资源记录的非唯一参考。 算法字段使用了DNSKEY资源记录的算法字段相同的数值。 摘要类型字段指出了所用的签名类型[RFC4034]中只定义了数值1(SHA-1),SHA-256是通过[RFC4509]指定的。 摘要字段包含了将要引用的DNSKEY资源记录的摘要,该摘要计算方法如下: 摘要 = 摘要算法(DNSKEY所有者名|DNSKEY RDATA) 此处的"|"是连接运算符,而DNSKEY RDATA的数值是根据引用的DNSKEY资源记录来计算的,计算方法如下: DNSKEY RDATA = 标志 | 协议 | 算法 | 公钥 在SHA-1情况下,摘要长度为20字节;在SHA-256情况下,长度为32字节。 NSEC/NSEC3,NextSECure,下一个安全资源记录用于规范有序的名称或一个NS类型的RRset(资源记录集)授权点中维护"下一个"RRset所有者的域名,它还维护位于NSEC资源记录的所有者名称中的RR类型列表,这样能够为区域结构提供认证与完整性验证。 NSEC资源记录格式如图: 下一个域名字段维护一个区域的规范有序的域名链中的下一个条目。 类型位图字段维护了一张关于RR类型的位图,这些RR类型记录在NSEC资源记录所有者的域名中。 NSEC3是对NSEC结构做的优化,旨在消除"任何人能够通过遍历NSEC链而列举出一个区域中的权威记录"这个问题(也被称为区域列举)。 NSEC3资源记录格式如图: 散列算法字段标识了应用于下一个所有者名称的散列函数,以产生下一个散列的所有者字段。 标志字段的低比特位包含了一个opt-out标志,如果置位,它将指出NSEC3记录可能包含未签名的授权。 迭代次数字段指出散列函数使用了多少次,较大的迭代次数有助于防止找到与NSEC3记录中的散列数值相关的所有者名称(字典攻击)。 混淆值长度字段给出了混淆值字段的字节长度,包含了一个在计算散列函数之前附加于原所有者名称的数值,目的在于帮助抵御字典攻击。 为了获得下一个散列所有者字段的散列值,需要进行以下计算: IH(0) = H(所有者名称 | 混淆值) IH(k) = H(IH(k - 1) | 混淆值), 若 k > 0 下一个散列所有者 = H(IH(迭代次数) | 混淆值) 其中H是散列算法字段指定的散列函数,所有者名称必须按照标准的格式。迭代次数与混淆值取自NSEC3资源记录的相关字段。 为了避免混淆NSEC与NSEC3资源记录类型,[RFC5155]在NSEC3资源记录的区域中分配并要求使用特殊的安全算法编号6和7,作为标识符3(DSA)和5(SHA-1)的别名。 RRSIG,资源记录签名的资源记录用于签署并验证RRset中的签名。区域中每一条授权的资源记录都必须签名,一条RRSIG资源记录包含了某一特定RRset的数字签名以及使用哪一个公钥来验证签名的信息。 RRSIG资源记录格式如图: 覆盖类型字段指出了签名适用的RRset类型,它的数值来自标准的RR类型集合。 算法字段指出了签名算法。 标签字段给出了在RRSIG资源记录的原所有者名称中的标签数目。 源TTL字段维护了一份TTL副本,这份副本是当RRset出现于授权区域时保留下来的。 签名到期与签名成立字段指出了一个签名有效期的开始和结束时间。 密钥标签字段标识那些用于获得某种特殊公钥的DNSKEY资源记录。 DNSSEC运行  对于一个特殊的资源记录而言,需要有一个定义良好的规范形式:   1. 每一个域名都是一个完全限定域名并被完全展开(无压缩标签)。   2. 在所有者名称中的所有大写的US-ASCII码字符都需要被它们的小写版本代替。   3. 对于任何类型号为2~9、12、14、15、17、18、21、24、26、33、35、36、39以及38的记录,在它们的RDATA部分出现的域名中,所有大写的US-ASCII码字符都需要被它们的小写版本代替。   4. 任何通配符都不会被取代。   5. 当出现在源权威区域或覆盖RRSIG资源记录的源TTL字段,TTL将会设置为原始值。 DNSSEC依赖于签名区域。这样的区域包括RRSIG、DNSKEY以及NSEC(或NSEC3)资源记录,而且如果有一个签名授权点,它还可能包含DS资源记录。签名使用公钥加密,公钥的存储于分发通过DNS来完成。 如下图展示了位于父子区域之间的抽象授权点: 父区域包含了自己的DNSKEY资源记录,它能够提供与使用RRSIG资源记录来签名一个区域中的所有授权RRset的私钥相关的公钥。父区域中的一条DS资源记录提供子顶点的一条DNSKEY资源记录的散列值,这样就能见了起一条从父区域到子区域的信任链。一个信任父区域的DS资源记录的验证解析器也能验证子区域的DNSKEY资源记录,以及最终的RRSIG和子区域中签名的RRset(该情况只有在验证者拥有一个与父区域DSNKEY资源记录相连的信任根节点时才会发生)。 事务认证(TSIG,TKEY,SIG(0)) DNSSEC提供了数据的源认证与区域数据的完整性保护,而事务认证为客户端与服务器之间不检查交换内容正确性的特殊事务提供了完整性保护与认证。DNS中的事务(如区域传输、动态更新)安全并不直接保护DNS的内容,所以它和DNSSEC是互补的,需要能够被一同部署。 主要有两种方法来认证DNS的事务:TSIG和SIG(0)。SIG使用共享密钥而SIG(0)使用公钥/私钥对,为了缓解部署的负担,可以使用TKEY资源记录类型来帮助形成TSIG或SIG(0)的密钥。 针对DNS或事务签名的密钥事务认证(TSIG)[RFC2845]5]使用基于共享密钥的签名为DNS交换添加事务认证,TSIG使用一个按需计算并且只用于保障一次事务的TSIG伪资源记录。 TSIG伪资源记录格式如图: 上面的资源记录是包含在DNS请求与响应的附加数据部分发送的。 算法名称字段指出使用什么算法。 签名时间字段是按照UNIX系统的时间格式组织的,并且给出了消息内容被签署的时间,此字段隐藏在数字签名中,被设计用于检测并抵御重放攻击,此处使用一个绝对时间的结果是,使用TSIG的端点必须在更新字段指定秒数内对时间达成一致。 MAC大小字段给出了MAC字段中包含的MAC与其依赖的特殊MAC算法所需的字节数。 源ID字段是该消息的一个标识,与DNS的事务ID匹配。 错误字段用以承载错误信息。 其他长度字段给出了其他数据字段的字节数,一般用来运送错误的消息。 SIG(0)[RFC2931]没有覆盖DNS中静态的记录,而是为交换动态地生成,SIG(0)的0部分指一条被签署资源记录中数据的长度。SIG(0)记录原则上能够替代TSIG资源记录,并达到相同的结果,但他们是以不同的方法实现的。更重要的是,SIG(0)将信任基础放置于公钥中来代替共享密钥。 TKEY元资源记录类型旨在简化DNS交换安全的部署,为了完成这项工作,它会动态创建TKEY资源记录并添加到DNS请求与响应的附加信息部分发送出去,它们能够包含密钥或者用于形成密钥的资料,比如DH公共数值。 域名密钥识别邮件  域名密钥识别邮件(DKIM)[RFC5585]提供了一个实体与一个域名之间的关联,从而决定哪一方发送初始消息,特别是以电子邮件形式。域名密钥识别邮件的工作是通过在基本的Internet消息格式中添加一个DKIM签名实现的[RFC5322],该字段包含了对消息头部和消息体的数字签名。DKIM取代了早期称为域名密钥的标准,该标准使用域名密钥签名字段。 为生成一条消息的数字签名,签名域表示符(SDID)会使用RSA/SHA-1或者RSA/SHA-256算法及相关的私钥。SDID来自DNS的域名,并用于检索以TXT资源记录存储的公钥。一个DKIM签名会通过Base64被编码为一个消息头部字段,该签名能够签署一个明确列出的消息字段与消息体集合。 当接收到一封电子邮件时,邮件传输代理会使用SDID来实现一个DNS查询,从而找出相关的公钥。该公钥会在之后用于验证签名,这样就避免了请求一个PKI的工作。所拥有的域名是由域本身和选择器(公钥选择器)一起构成的。例如,在域example.com中的选择器key35的公钥是一条由key35._domainkey.example.com拥有的TXT资源记录。  
文章
算法  ·  安全  ·  网络协议  ·  网络安全  ·  数据安全/隐私保护
2019-01-14
浅谈oracle中SYS_CONTEXT上下文关系以及TCP和IPC两种连接方式
前天维护数据库,在执行某个的脚本时,发现结果与实际情况有所出入。对该脚本进行检查,发现其中包含有一条子查询语句: SELECT sys_context('userenv','ip_address') from DUAL; 在sqlplus内执行,返回结果为空。经翻阅资料,发现该语句的作用是返回一个上下文的参数值。其中sys_context是一个oracle关键字,用于查询一个命名空间(namespace)中某个参数(parameter)的值。Oracle默认建立的命名空间为“userenv”。该命名空间包含以下参数(摘自Docs Oracle ): ACTION:模块中的位置标识(应用程序名),通过DBMS_APPLICATION_INFO包或者OCI设置。 AUDITED_CURSORID:返回触发审计的SQL游标标识。该参数在高精度审计环境下总是返回NULL。 AUTHENTICATED_IDENTITY:返回认证用的标识。下列列表中各种用户类型返回其后的值: Kerberos认证企业用户:kerberos主体名 Kerberos认证外部用户:kerberos主体名;等同于Schema名 SSL认证企业用户:用户PKI证书的识别号 SSL认证外部用户:用户PKI证书的识别号 密钥认证企业用户:昵称;等同于登陆名 密钥认证数据库用户:数据库用户名,等同于Schema名 OS认证外部用户:外部操作系统用户名 Radius/DCE认证外部用户:方案名 携带DN代理:OID识别号 携带证书代理:客户的证书识别号 携带用户名代理:客户若为本地数据库用户则为数据库用户名,若为企业用户则返回昵称。 以密码文件登陆SYSDBA/SYSOPER:登陆名 以操作系统认证登陆SYSDBA/SYSOPER:操作系统用户名 AUTHENTICATION_DATA:用于认证登录用户的数据。 AUTHENTICATION_METHOD:认证方式,包括PASSWORD、KERBEROS、SSL、RADIUS、OS、DCE或者NONE。在Password, Kerberos或者SSL认证模式下可用关键字IDENTIFICATION_TYPE区分外部用户和企业用户。 BG_JOB_ID:若本会话是由Oracle数据库后台进程创建的,返回其任务ID;否则返回NULL。 CLIENT_IDENTIFIER:返回某应用通过DBMS_SESSION.SET_IDENTIFIER程序、OCI特性OCI_ATTR_CLIENT_IDENTIFIER或者JAVA类Oracle.jdbc.OracleConnection.setClientIdentifier所设置的标识。该特性用于各类数据库组件,鉴别认证为同一数据库用户的不同轻量级应用用户。 CLIENT_INFO:返回最多64字节的用户会话信息,当应用使用到DBMS_APPLICATION_INFO包时该信息可被保存下来。 CURRENT_BIND:返回高精度审计的绑定变量。 CURRENT_SCHEMA:返回当前Schema中的默认Schema名。该值随着会话中所使用ALTERSESSION SET CURRENT_SCHEMA声明而改变。 CURRENT_SCHEMAID:本会话所使用的默认Schema标识。 CURRENT_SQL/CURRENT_SQLn:CURRENT_SQL返回当前触发高精度审计事件的SQL前4k个字节。CURRENT_SQLn特性返回接下来以4k字节递增的序列,n可以是整数1-7。CURRENT_SQL1返回4k-8k字节;CURRENT_SQL2返回4k至8k字节,以此往下推。该属性只能在高精度审记特性的事件处理器中被指定。 CURRENT_SQL_LENGTH:当前触发高精度审记、行级安全策略功能或事件处理器的SQL声明长度。仅在功能或者事件处理器内有效。 DB_DOMAIN:由初始化参数DB_DOMAIN所指定的数据库域。 DB_NAME:由初始化参数DB_NAME所指定的数据库名。 DB_UNIQUE_NAME:由初始化参数DB_UNIQUE_NAME所指定的数据库名。 ENTRYID:当前审计项号码。高精度审记记录与一般审计记录共享该审计项标识序列。该属性不能用于分布式SQL声明。在一个标准或高精度审记的审计处理器中才能看到准确的审计项标识。 ENTERPRISE_IDENTITY:返回用户在企业范围内的标识: 对于企业用户: OID识别号。 对于外部用户:外部标识,例如Kerberos主体名,Radius和DCE方案名,操作系统用户名,证书辨析名等。 对于本地用户和SYSDBA/SYSOPER登陆:NULL。 下列属性值根据代理方式而有所变化: 对于带有识别号的代理:客户的OID识别号。 对于带有证书的代理:对于外部用户为客户证书识别号;全局用户为OID识别号。 对于带有用户名的代理:若客户为企业用户则为OID识别号;若客户为本地数据库用户则为NULL。 FG_JOB_ID:若当前会话是由客户前台进程创建的,返回任务标识;否则返回NULL。 GLOBAL_CONTEXT_MEMORY:返回在全局访问的情况下SGA中所使用的号码。 GLOBAL_UID:在企业用户安全登陆情况下,返回从Oracle因特网目录中全局用户标识,其余的登陆返回NULL。 HOST:客户端用于连接本服务器的设备名称。 IDENTIFICATION_TYPE:返回数据库中创建该用户Schema的方式。特别指出,其将显示出CREATE/ALTERUSER语法中的IDENTIFIED字句。下述列表中,对于不同Schema创建的语法返回其随后的标识: 密码标识: LOCAL 外部标识: EXTERNAL 全局标识: GLOBAL SHARED 使用分辨号作为全局标识: GLOBAL PRIVATE INSTANCE:本实例的实例ID数目。 INSTANCE_NAME:实例名。 IP_ADDRESS:客户端用于连接本服务器的设备IP地址。 ISDBA:若用户通过操作系统或者密码文件的形式通过DBA特权认证,则返回TURE。 LANG:语言ISO名,是已有参数‘Language’的缩写。 LANGUAGE:你的会话当前的语言和范围,随后是数据库字符集,格式如下:语言_范围.字符集。 MODULE:由DBMS_APPLICATION_INFO包或者OCI设置的应用名(模块)。 NETWORK_PROTOCOL:客户端与服务器之间用来创建连接的连接字符串中'PROTOCOL='所指定的协议名。 NLS_CALENDAR:本会话的日程表。 NLS_CURRENCY:本会话的货币单位。 NLS_DATE_FORMAT:本会话的日期格式。 NLS_DATE_LANGUAGE:用于表示日期的语言。 NLS_SORT:二进制或者语义排序基础。 NLS_TERRITORY:本会话的范围。 OS_USER:初始化该数据库会话的客户端进程,其操作系统用户名。 POLICY_INVOKER:行级别的安全策略功能调用者。 PROXY_ENTERPRISE_IDENTITY:当代理用户为企业用户时,返回OID的用户辨识名(Distinguished Name)。 PROXY_GLOBAL_UID:对于企业用户安全(EUS)代理用户,从Oracle英特网目录中返回的全局用户ID。对其他代理用户返回NULL。 PROXY_USER:为session_user打开当前会话的数据库用户名(代理用户名)。 PROXY_USERID:为session_user打开当前会话的数据库用户ID(代理用户ID)。 SERVER_HOST:返回本实例所在服务器的hostname; SERVICE_NAME:返回本会话的service_name; SESSION_USER:对企业用户而言,返回该user的schema. 对于其他用户,返回通过数据库认证的该用户的username。整个会话中该值保持不变。 SESSION_USERID:当前被认证用户的user ID。 SESSIONID:审计会话标识。该属性无法用于分布式SQL声明。 SID:会话号(与会话标识不同)。 STATEMENTID:审计声明标识。STATEMENTID表示给定会话中被审计的SQL声明号码。该特性不能用于分布式SQL声明。只有在标准或高精度审计中通过审计处理器才能看到正确的审计声明标识。 TERMINAL:当前会话客户的操作系统标识。分布式SQL声明中,该特性返回本地会话的标识。在分布式环境中,本特性只支持远程SELECT声明,不支持远程INSERT、UPDATE或者DELETE操作。(该参数返回长度随着不同操作系统而改变。) 其中上述语句的返回值应为客户端连接的IP地址。由于该脚本应在服务器上执行,因此发现该处应返回服务器IP地址,而返回空值意味着无法获取该IP地址。事实上,只要把该语句改为直接填写的IP地址,则脚本顺利通过。 进一步检查,发现该脚本在登陆数据库时使用的命令为conn user/passwd。而其它没有问题的服务器上使用conn user/passwd@IP进行连接。经过上网搜索,发现两种登陆形式确实影响了脚本的执行。 使用TCP连接可以使程序在本地或远程连接Oracle数据库。TCP连接需要对Listener进行配置,主要参数为服务器名(需要DNS)或者服务器IP地址。  LISTENER=    (DESCRIPTION=      (ADDRESS_LIST=  (ADDRESS=(PROTOCOL=tcp)(HOST=ServerName/ServerIP)(PORT=1521))      )    )  以下述方式进行连接:  conn user/passwd@OracleServer 使用IPC可以使程序在本地直接连接Oracle数据库,可以与Oracle共享服务器同时配置。IPC同样需要Listener进行连接。IPC的参数主要为Service Name或者SID。  LISTENER=    (DESCRIPTION=      (ADDRESS_LIST=        (ADDRESS=(PROTOCOL=ipc)(KEY=ServiceName/SID))      )    )  以下述方式进行连接:  conn user/passwd@ServiceName 若只有一个Oracle服务开启,可省略服务名: conn user/passwd 另外,据Docs Oracle介绍,还有第三种连接模式:Bequeath Protocol。这是一种SQL*NET的协议,无需使用Listener,只能连接到本地独占模式的Oracle数据库。 结论: 本地使用客户端连接服务器时,使用IPC,程序之间直接递交查询申请和结果反馈;相比之下,TCP连接需要经过TCP/IP4层封装解封装。因此,一般情况下,使用IPC约有7%到8%的性能提升。但这样由于不经过TCP/IP协议栈的处理,sys_context无法获取连接客户端的IP地址,从而导致该脚本的无法执行。 解决方法:不使用 sys_context(‘userenv’,’ip_address’) from dual; 改用 select utl_inaddr.get_host_address from dual; 本文转自 gole_huang 51CTO博客,原文链接:http://blog.51cto.com/golehuang/1179281
文章
SQL  ·  Oracle  ·  网络协议  ·  关系型数据库  ·  数据库  ·  网络安全  ·  安全  ·  数据安全/隐私保护  ·  数据库管理  ·  Java
2017-11-12
ISA Server不作为域成员是最安全的吗?
       我想大家都多多少少都接触过ISA,或者使用过它,但是你有没有想过它在工作组环境下和域环境下有什么区别,我们为什么都把ISA加入到工作组,而往往只关心它的安全吗。对于大多数的人不确定质疑我总结以下四点:1、ISA在工作组中比在域中更安全;2、如果域的安全受到威胁,ISA Server 仍然会正常工作;3、如果ISA Server的安全受到威胁,域却不能 被访问;4、因为ISA 运行在Windows 上本身就不安全。OKAY,我相信第四条是大家最担心的一点吧。认为Windows本身就不安全,再加上一个ISA防火墙那就更摇摇欲坠了。好的,我就开始分析这列举的四点,ISA加域有什么好处,不加入域又能给我们带来哪些益处和不利之处。        首先,我们先来谈谈ISA作为域成员的好处。我相信大家选择ISA作为防火墙,80%的人看中了ISA的Porxy功能。可以对不同类型的用户进行访问控制,这时候,如果ISA在工作组下就无法实现,必须依赖我们的活动目录。ISA的企业版有阵列可以实现高可用性,我们搭建阵列可以在工作下,也可以在域环境下。但是如果工作在工作环境下,阵列的搭建想必是一个复杂过程,即要创建用户,还要申请服务验证证书和客户端证书,并且对IT管理员排错也是头疼的事,而在域环境下我们不需要创建额外的帐号,直接使用域帐号就可以实现CSS和成员之间进行通讯。ISA在域环境下对Firewall Client的支持会更简单。对于管理来说,有人认为ISA的可管理性不是很强,如果它受到攻击哪怎么办?于是就引入了微软管理的平台SCOM2007或者MOM2005,这样可以实现ISA服务器的全部性能和服务进行监控,并对所有安全事件进行收集,我们通过SCOM2007强大的报告功能可以全局性的看一些事件,管理人员会一目了然的了解ISA服务器的运行状况。换句话说,如果要对ISA服务器进行管理,那么也必须作为域成员才行。        上面谈的是作为域成员的好处,但是还会存在另一方面的声音,那就是ISA服务器作为域成员会出现哪些问题。好的,首先如果我们企业的活动目录受到危及,想必我们ISA服务器就不能正常工作。反之,如果ISA服务器受到危及,我们企业的活动目录就会受到牵连,黑客只要能登录到ISA服务器就可以轻松的访问我内网任何资源,想必这样风险对一个企业来说是致命的。呵呵,但是从现在微软相关部门统计来看,ISA服务器从来没有被攻击过。最后,是从ISA的管理来讲,ISA服务器是域成员,那域内的管理人员就可以随便的对ISA进行访问和配置,对于ISA服务器来说也是不安全的。        其次,我们再来谈谈ISA作为工作组成员的好处。可能我相信大家都认识工作组是最安全的,其实我也这么认为。如果ISA服务器受到黑客的攻击,我们企业内网的活动目录不会受到任何影响,也就是说内部数据资产不受牵连,反之,企业内部活动目录受到安全的威胁,ISA服务器仍可以正常的工作。其实这一点来说,如果我内部活动目录工作不正常,有我ISA服务器正常工作对企业来说意义不大了,因为内网的一些关键应用,如SQL Server,Exchange Server,Sharepoint Server都不能运行了,那这ISA还起什么大作用呢,所以我们一定要避免此类事情的发生。在工作组环境下,对于ISA服务器的管理来说,我会不需要域管理员来参与,因为ISA服务器有自己的用户来管理,这样服务器自身安全性有了提高。        上面谈的是作为工作组成员的好处,那么它在工作组下会存在什么不足。1、CSS缺乏冗余,因为在工作组下只存在一个CSS配置实例,上面存放着ISA服务器的所有配置数据,也就是说,如果CSS不工作了,ISA服务器也就罢工了。2、需要证书保证策略存储服务器 CSS的安全,因为是工作组,所有阵列成员需要证书进行通讯,配置比较复杂。3、针对阵列的通讯和管理需要本地帐号,这样就会和公司内部的密码策略会产生违背,不符合公司IT管理的合规性。4、对于ISA服务器的验证,就需要配置Radius服务器,并且无法体验ISA2006的诸多验证方式。       最后,言归正传,ISA Server不作为域成员是最安全的吗?这个答案是没有解答的,这需要根据你的实际应用来判定它应该工作哪种环境下,但我提出我个人的观点就是,ISA服务器加入域是不会给企业带来风险的,而会给我们带来ISA相关的更多更好的体验,特别是在身份验证方面,加入域会给我们管理带来很多的便利。 本文转自 chinaperrylee 51CTO博客,原文链接:http://blog.51cto.com/perry/151314,如需转载请自行联系原作者
文章
前端开发  ·  安全
2017-11-08
跳转至:
阿里云开发者学堂
130324 人关注 | 7314 讨论 | 12051 内容
+ 订阅
  • 企业运维训练营之云上监控运维最佳实践启动!参营送好礼
  • 可观测Grafana入门训练营,帮助同学们由浅入深的对阿里云Grafana服务拥有全面了解
  • 【开发者7日学】求职达人训练营上线啦~快来打卡赢好礼
查看更多 >
开发与运维
5756 人关注 | 133164 讨论 | 317866 内容
+ 订阅
  • SaaS时代下的我们需要什么样的数据库?
  • FDF循环互助游戏开发系统逻辑demo
  • 可观测系统如何识别网站有多少文件命中了缓存?
查看更多 >
安全
1237 人关注 | 24092 讨论 | 85342 内容
+ 订阅
  • SaaS时代下的我们需要什么样的数据库?
  • FDF循环互助游戏开发系统逻辑demo
  • Polygon马蹄链系统开发DAPP源码demo
查看更多 >
人工智能
2859 人关注 | 12253 讨论 | 102107 内容
+ 订阅
  • SaaS时代下的我们需要什么样的数据库?
  • JVM学习.02 内存分配和回收策略
  • 无线自组网AODV路由机制matlab仿真
查看更多 >
数据库
252933 人关注 | 51905 讨论 | 98688 内容
+ 订阅
  • SaaS时代下的我们需要什么样的数据库?
  • FDF循环互助游戏开发系统逻辑demo
  • Polygon马蹄链系统开发DAPP源码demo
查看更多 >