• 关于

    函数-变量作用域

    的搜索结果

回答

全局变量就得了解一下变量作用域搜索原则LEGB: 1.L(local)局部作用域 2.E(enclosing)嵌套作用域 3.G(global)全局作用域 4.B(built-in)内置作用域 如果定定了全局变量,在本地作用域内比如在函数内部要修改,就必须用gloabl 声明一下变量 否则会报错。
游客aasf2nc2ujisi 2019-12-02 03:10:35 0 浏览量 回答数 0

回答

闭包是关于变量作用域链的闭包建立在函数声明阶段,而非执行阶段闭包是依附在函数对象上的JS垃圾回收是基于引用计数的函数执行时生成的局部变量在函数执行完毕后就会从执行栈中清除掉,但不意味着者可以GC掉,还要看其是否被引用那么我们回到问题`$button1=$("#button1");$button2=$("#button2");`声明了$button1变量和$button2变量function Panel(){} Panel.prototype.activate=function(){ var a=1; $button2.click(function(){ a+=1; }); }定义了Panel函数,声明了一个匿名函数A,在匿名函数内部声明了一个内部变量a,引用了变量$button2,并在内部同事声明了一个匿名函数A1,将会使用到其定义时所处的函数的内部变量a;至此就会形成2个闭包,[闭包1]一个针对Panel函数原型对象的activate方法(函数)的闭包-可以能访问非内部变量$button2;[闭包2] 一个针对匿名函数的闭包-可以/需要访问activate函数的内部变量a$button1.click(function(){ new Panel().activate(); });声明了一个匿名函数B,其需要访问Panel构造函数,所以匿名函数还有又构成一个闭包[闭包3]-可以/需要范围访问Panel构造函数在函数声明阶段完成,也就是词法作用域分析结束后开始代码的执行,为Panel函数原型添加了一个方法activate并将其指向声明的匿名函数A为$button1绑定click事件回调匿名函数B当$button1触发click事件后,匿名函数B被执行,利用闭包能够访问到Panel函数,进而新建了一个Panel对象,并执行了activate方法,初始化变量a,用到闭包能够访问到$button2,为$button2绑定click事件回调匿名函数A1.当$button2触发click事件,匿名函数A1就被访问,利用前面的闭包能够访问a匿名函数A1/匿名函数B分别绑定在$button2,$button1上的,这个2个对象都函数都还有引用,所以执行完了以后函数对象不会被GC掉,那么闭包也就保留着,闭包保留着,那么对其中的变量就会有引用存在,那么变量就不会被清除的闭包中的变量并不会随着函数的执行完毕而被清除掉,反而会一直保留着,除非这个闭包被清除-也就是闭包中涉及的变量再也没有被别的函数引用到。例如function add10(init){ var a=10; var add=function(){ a+=10; } add(); return a; } console.log(add10(10));//输出20add函数就会形成一个闭包,可以/需要访问变量a但在add10函数执行完了后,闭包将会消失,因为没有其它对象会引用到函数add,那么可以GC掉add,闭包也就失去了其依赖的对象,也就会被GC掉
小旋风柴进 2019-12-02 02:24:47 0 浏览量 回答数 0

回答

1、不要在同一行声明多个变量 2、使用===或!==来比较 3、使用字面量的方式来创建对象、数组,替代new Array这种形式 4、不要使用全局函数 5、switch语句必须要带default分支 6、函数不应该有的时候有return,有的时候没有return 7、fon-in循环中的变量,用var关键字说明作用域,防止变量污染 8、变量的声明遵循驼峰命名法,用let替代val,声明构造函数时首字母大写,定义常量的时候尽量用大写字母,用_分割 9、三元表达式可以替代if语句 10、&&和||是可以短路的,使用&&时如果前面一个值是错的,那么后面的值不用判断,使用||时,如果前面一个值是对的,那么后面的值不用判断 11、比较数据类型以下6中情况是false,其他都是true------false、""、0、null、undefined、NaN 12、数据类型检测用typeof,对象类型检测用instanceof 13、异步加载第三方的内容 14、单行注释//,多行注释/**/ 15、使用命名空间解决变量名冲突 16、多人协作开发,新建一个js文件,const声明常量,在js文件中引用,用常量名替代方法名,这样做可以防止命名冲突
景凌凯 2020-04-03 22:27:53 0 浏览量 回答数 0

域名特惠专场,热门顶级域名低至1元,适用企业/个人域名注册!

域名低至1元起,更有服务器低至0.55折

回答

adda = function  ()  前面没有var 所有是全局的######声明的函数表达式为全局变量,可以在外部调用,是作用域链的原因,具体我也不清楚######是作用域问题###### 这段代码出现了好多全局变量. 按照你所谓的正常的代码, adda , aa, bb, result , 这些都是全局范围的. 这样的代码多了.很可能造成污染. 你所说的替换后不正常. 是由于全局变量没了. adda根本不会被执行. 所以结果无变化. ###### 用firebug看下就知道了 ######变量作用域的问题吧######THX###### 你可以看看作用域和闭包的知识 http://www.veryued.org/2011/09/javascript-scope-closure-this/ http://mzhou.me/article/81001/ 这个里面最后一个例子就是你的答案 ######感谢######已找到答案,问题出在小白我之前看的文献理解有误,把function的某些概念搞错了,正确的是var xx = function () {} 才是和function () {}的用法相同,两个的作用域不是全局的,而 xxx = function(){}才是全局变量,所以能在外部调用
kun坤 2020-06-05 13:23:52 0 浏览量 回答数 0

回答

用 var 声明的变量的作用域是它当前的执行上下文,它可以是嵌套的函数,也可以是声明在任何函数外的变量。let 和 const 是块级作用域,意味着它们只能在最近的一组花括号(function、if-else 代码块或 for 循环中)中访问。
茶什i 2019-12-02 03:21:13 0 浏览量 回答数 0

问题

语言相关-什么是变量

什么是变量 所谓变量是指在为了快速读取而在内存中保存数据的一块空间. 您可以把它想象成是一个在内存里的邮箱, 我们可以往里面存信也可以取信.例如您可以创建 一个变量用来保存用户回复的数值或者某个数学表达式的 运算结果. 每个变量都有自...
码栈 2019-12-01 21:48:25 2147 浏览量 回答数 0

回答

顶下,顺便帮你总结下, : 1、函数声明像变量声明一样会提升,但函数表达式不会提升 2、函数声明会覆盖变量声明 3、函数声明不会覆盖变量赋值或者变量初始化 貌似你上次发过类似的 var声明提升至作用域顶部嘛,function声明更上一点。最近研究js痴迷了。mark学习。搞个系列出来,有点不过瘾  正在翻译一个系列:https://github.com/justjavac/12-javascript-quirksmk 那么如此声明还有什么意义呢?好吧,就我目前找到的资料而言,这样做的好处就是便于调试。 帮你补充一个,这样还可以用来递归调用,虽然可以用arguments.callee(但EC5不推荐用arguments.callee)。 顺便问下,你面试的是前端职位?
爱吃鱼的程序员 2020-06-22 18:54:46 0 浏览量 回答数 0

问题

谈 javascript 变量声明?报错

这篇文章还是对基础的复习,对面试经历的一个总结。 之前的面试中遇到过一道面试题 var a = 10; (function () { console.log(a); var a =...
爱吃鱼的程序员 2020-06-22 18:54:29 0 浏览量 回答数 1

回答

两种写法都是不正确(不标准)的写法。前者的标准写法:const char *pt = "hello world!";这种写法字符串被存储在静态存储区,整个程序内都可以使用,因为是 const, 所以不能修改。后者的标准写法:char pt[] = "hello world!";这个字符串会在运行时在栈上分配空间,超出作用域内存即被释放,可以修改,长度取决于后面的字符串(编译时计算)。回应 @小_秦 的质疑:你可以在任何现代的编译器上编译你写的下面这行代码:char *p = "Hello World!";并开启编译器的所有警告,你会收到这样的警告(我的编译器是 Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)):warning: conversion from string literal to 'char *' is deprecated [-Wc++11-compat-deprecated-writable-strings]解决这个警告的办法就是如我前面所说,把 char 改成 const char . 我上面用的是 C++ (我看你用的也是 C++),在 C 语言里可能不会出现这个警告,但因为字符串字面量存储在静态存储区,该地址被整个程序的所有相同字符串字面量共享,所以 pt 从语义上必须是只读的,即必须 const.关于我说的「整个程序内都可以使用」是指 pt 所指向的内存地址(你可以将这个地址保存在一个全局变量里,当你离开了这个函数,你依然可以使用),而不是 pt 这个符号
a123456678 2019-12-02 02:39:20 0 浏览量 回答数 0

回答

递归是一种算法结构,回溯是一种算法思想,一个递归就是在函数中调用函数本身来解决问题,回溯就是通过不同的尝试来生成问题的解,有点类似于穷举,但是和穷举不同的是回溯会“剪枝”,意思就是对已经知道错误的结果没必要再枚举接下来的答案了,比如一个有序数列1,2,3,4,5,要找和为5的所有集合,从前往后搜索我选了1,然后2,然后选3 的时候发现和已经大于预期,那么4,5肯定也不行,这就是一种对搜索过程的优化。 回溯分析是追踪决策的特性之一。 是指对原始决策的产生机制、决策内容、主客观环境等进行分析.从起点开始,按顺序考察导致决策失误的原因、问题的性质、失误的程度等。 [算法分析] 为了描述问题的某一状态,必须用到它的上一状态,而描述上一状态,又必须用到它的上一状态……这种用自已来定义自己的方法,称为递归定义。例如:定义函数f(n)为: f(n)=n*f(n-1) (n>0) f(n)=1 (n=0) 则当0时,须用f(n-1)来定义f(n),用f(n-1-1)来定义f(n-1)……当n=0时,f(n)=1。 由上例我们可看出,递归定义有两个要素: (1)递归边界条件。也就是所描述问题的最简单情况,它本身不再使用递归的定义。 如上例,当n=0时,f(n)=1,不使用f(n-1)来定义。 (2)递归定义:使问题向边界条件转化的规则。递归定义必须能使问题越来越简单。 如上例:f(n)由f(n-1)定义,越来越靠近f(0),也即边界条件。最简单的情况是f(0)=1。 递归算法的效率往往很低, 费时和费内存空间. 但是递归也有其长处, 它能使一个蕴含递归关系且结构复杂的程序简介精炼, 增加可读性. 特别是在难于找到从边界到解的全过程的情况下, 如果把问题推进一步,其结果仍维持原问题的关系, 则采用递归算法编程比较合适. 递归按其调用方式分为: 1. 直接递归, 递归过程P直接自己调用自己; 2. 间接递归, 即P包含另一过程D, 而D又调用P. 递归算法适用的一般场合为: 1. 数据的定义形式按递归定义. 如裴波那契数列的定义: f(n)=f(n-1)+f(n-2); f(0)=1; f(1)=2. 对应的递归程序为: Function fib(n : integer) : integer; Begin if n = 0 then fib := 1 { 递归边界 } else if n = 1 then fib := 2 else fib := fib(n-2) + fib(n-1) { 递归 } End; 这类递归问题可转化为递推算法, 递归边界作为递推的边界条件. 2. 数据之间的关系(即数据结构)按递归定义. 如树的遍历, 图的搜索等. 3. 问题解法按递归算法实现. 例如回溯法等. 从问题的某一种可能出发, 搜索从这种情况出发所能达到的所有可能, 当这一条路走到" 尽头 " 的时候, 再倒回出发点, 从另一个可能出发, 继续搜索. 这种不断" 回溯 "寻找解的方法, 称作 " 回溯法 ". [参考程序] 下面给出用回溯法求所有路径的算法框架. 注释已经写得非常清楚, 请读者仔细理解. Const maxdepth = ????; Type statetype = ??????; { 状态类型定义 } operatertype = ??????; { 算符类型定义 } node = Record { 结点类型 } state : statetype; { 状态域 } operater :operatertype { 算符域 } End; { 注: 结点的数据类型可以根据试题需要简化 } Var stack : Array [1..maxdepth] of node; { 存当前路径 } total : integer; { 路径数 } Procedure make(l : integer); Var i : integer; Begin if stack[L-1]是目标结点 then Begin total := total+1; { 路径数+1 } 打印当前路径[1..L-1]; Exit End; for i := 1 to 解答树次数 do Begin 生成 stack[l].operater; stack[l].operater 作用于 stack[l-1].state, 产生新状态 stack[l].state; if stack[l].state 满足约束条件 then make(k+1); { 若不满足约束条件, 则通过for循环换一个算符扩展 } { 递归返回该处时, 系统自动恢复调用前的栈指针和算符, 再通过for循环换一个算符扩展 } { 注: 若在扩展stack[l].state时曾使用过全局变量, 则应插入若干语句, 恢复全局变量在 stack[l-1].state时的值. } End; { 再无算符可用, 回溯 } End; Begin total := 0; { 路径数初始化为0 } 初始化处理; make(l); 打印路径数total End.
寒凝雪 2019-12-02 01:24:19 0 浏览量 回答数 0

回答

首先tmp[len]这里的确有问题新标起码也要求constlen=strlen(str); 其次告警提示很明确返回值是一个局部变量跳出本函数的作用域tmp就不知道是什么内容的可能出现野指针 都是基本知识细节这是警告,不是错误,提示你返回了一个局部变量的地址变量是有作用域的,参照http://c.biancheng.net/cpp/html/62.html网上找了个http://www.linuxidc.com/Linux/2014-07/104736.htmchartmp[]中的tmp在函数结束时会被弹出栈区,因为这是系统自动管理的。你注释掉的那个是对的,因为堆区是由程序员管理的。没人发现他这样写有问题吗?char tmp[len];我说的就是这个问题轩辕君是对的,c不能这么写,需要手动malloc
爱吃鱼的程序员 2020-06-10 13:51:18 0 浏览量 回答数 0

问题

Java 8 Lambda限制:报错

Java 8 Lambda限制:闭包 Java 8 Lambda表达式从哪里来? Java 8 Lambda限制 JavaScript及其功能 Java创建闭包? 副作用和JavaScript 副作...
kun坤 2020-06-08 11:12:26 4 浏览量 回答数 1

问题

你真的已经搞懂JavaScript了吗? 热 400 请求报错 

昨天在著名前端架构师Baranovskiy的博客中看到一个帖子 题目一: if (!("a" in window)) { var a = 1; } alert(a);   题目二: ...
kun坤 2020-05-29 11:26:12 3 浏览量 回答数 1

回答

一、内存溢出类型 1、java.lang.OutOfMemoryError: PermGen space JVM管理两种类型的内存,堆和非堆。堆是给开发人员用的上面说的就是,是在JVM启动时创建;非堆是留给JVM自己用的,用来存放类的信息的。它和堆不同,运行期内GC不会释放空间。如果web app用了大量的第三方jar或者应用有太多的class文件而恰好MaxPermSize设置较小,超出了也会导致这块内存的占用过多造成溢出,或者tomcat热部署时侯不会清理前面加载的环境,只会将context更改为新部署的,非堆存的内容就会越来越多。 PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中,它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的应用中有很CLASS的话,就很可能出现PermGen space错误,这种错误常见在web服务器对JSP进行pre compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。 一个最佳的配置例子:(经过本人验证,自从用此配置之后,再未出现过tomcat死掉的情况) set JAVA_OPTS=-Xms800m -Xmx800m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m 2、java.lang.OutOfMemoryError: Java heap space 第一种情况是个补充,主要存在问题就是出现在这个情况中。其默认空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。如果内存剩余不到40%,JVM就会增大堆到Xmx设置的值,内存剩余超过70%,JVM就会减小堆到Xms设置的值。所以服务器的Xmx和Xms设置一般应该设置相同避免每次GC后都要调整虚拟机堆的大小。假设物理内存无限大,那么JVM内存的最大值跟操作系统有关,一般32位机是1.5g到3g之间,而64位的就不会有限制了。 注意:如果Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。 垃圾回收GC的角色 JVM调用GC的频度还是很高的,主要两种情况下进行垃圾回收: 当应用程序线程空闲;另一个是java内存堆不足时,会不断调用GC,若连续回收都解决不了内存堆不足的问题时,就会报out of memory错误。因为这个异常根据系统运行环境决定,所以无法预期它何时出现。 根据GC的机制,程序的运行会引起系统运行环境的变化,增加GC的触发机会。 为了避免这些问题,程序的设计和编写就应避免垃圾对象的内存占用和GC的开销。显示调用System.GC()只能建议JVM需要在内存中对垃圾对象进行回收,但不是必须马上回收, 一个是并不能解决内存资源耗空的局面,另外也会增加GC的消耗。 二、JVM内存区域组成 简单的说java中的堆和栈 java把内存分两种:一种是栈内存,另一种是堆内存 1。在函数中定义的基本类型变量和对象的引用变量都在函数的栈内存中分配; 2。堆内存用来存放由new创建的对象和数组 在函数(代码块)中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量所分配的内存空间;在堆中分配的内存由java虚拟机的自动垃圾回收器来管理 堆的优势是可以动态分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的。缺点就是要在运行时动态分配内存,存取速度较慢; 栈的优势是存取速度比堆要快,缺点是存在栈中的数据大小与生存期必须是确定的无灵活性。 java堆分为三个区:New、Old和Permanent GC有两个线程: 新创建的对象被分配到New区,当该区被填满时会被GC辅助线程移到Old区,当Old区也填满了会触发GC主线程遍历堆内存里的所有对象。Old区的大小等于Xmx减去-Xmn java栈存放 栈调整:参数有+UseDefaultStackSize -Xss256K,表示每个线程可申请256k的栈空间 每个线程都有他自己的Stack 三、JVM如何设置虚拟内存 提示:在JVM中如果98%的时间是用于GC且可用的Heap size 不足2%的时候将抛出此异常信息。 提示:Heap Size 最大不要超过可用物理内存的80%,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。 提示:JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。 默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。 提示:假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。 简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制, 这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了 提示:注意:如果Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。 提示:设置NewSize、MaxNewSize相等,"new"的大小最好不要大于"old"的一半,原因是old区如果不够大会频繁的触发"主" GC ,大大降低了性能 JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64; 由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。 解决方法:手动设置Heap size 修改TOMCAT_HOME/bin/catalina.bat 在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行: JAVA_OPTS="-server -Xms800m -Xmx800m -XX:MaxNewSize=256m" 四、性能检查工具使用 定位内存泄漏: JProfiler工具主要用于检查和跟踪系统(限于Java开发的)的性能。JProfiler可以通过时时的监控系统的内存使用情况,随时监视垃圾回收,线程运行状况等手段,从而很好的监视JVM运行情况及其性能。 1. 应用服务器内存长期不合理占用,内存经常处于高位占用,很难回收到低位; 2. 应用服务器极为不稳定,几乎每两天重新启动一次,有时甚至每天重新启动一次; 3. 应用服务器经常做Full GC(Garbage Collection),而且时间很长,大约需要30-40秒,应用服务器在做Full GC的时候是不响应客户的交易请求的,非常影响系统性能。 因为开发环境和产品环境会有不同,导致该问题发生有时会在产品环境中发生,通常可以使用工具跟踪系统的内存使用情况,在有些个别情况下或许某个时刻确实是使用了大量内存导致out of memory,这时应继续跟踪看接下来是否会有下降, 如果一直居高不下这肯定就因为程序的原因导致内存泄漏。 五、不健壮代码的特征及解决办法 1、尽早释放无用对象的引用。好的办法是使用临时变量的时候,让引用变量在退出活动域后,自动设置为null,暗示垃圾收集器来收集该对象,防止发生内存泄露。 对于仍然有指针指向的实例,jvm就不会回收该资源,因为垃圾回收会将值为null的对象作为垃圾,提高GC回收机制效率; 2、我们的程序里不可避免大量使用字符串处理,避免使用String,应大量使用StringBuffer,每一个String对象都得独立占用内存一块区域; String str = "aaa"; String str2 = "bbb"; String str3 = str + str2;//假如执行此次之后str ,str2以后再不被调用,那它就会被放在内存中等待Java的gc去回收,程序内过多的出现这样的情况就会报上面的那个错误,建议在使用字符串时能使用StringBuffer就不要用String,这样可以省不少开销; 3、尽量少用静态变量,因为静态变量是全局的,GC不会回收的; 4、避免集中创建对象尤其是大对象,JVM会突然需要大量内存,这时必然会触发GC优化系统内存环境;显示的声明数组空间,而且申请数量还极大。 这是一个案例想定供大家警戒 使用jspsmartUpload作文件上传,运行过程中经常出现java.outofMemoryError的错误, 检查之后发现问题:组件里的代码 m_totalBytes = m_request.getContentLength(); m_binArray = new byte[m_totalBytes]; 问题原因是totalBytes这个变量得到的数极大,导致该数组分配了很多内存空间,而且该数组不能及时释放。解决办法只能换一种更合适的办法,至少是不会引发outofMemoryError的方式解决。 5、尽量运用对象池技术以提高系统性能;生命周期长的对象拥有生命周期短的对象时容易引发内存泄漏,例如大集合对象拥有大数据量的业务对象的时候,可以考虑分块进行处理,然后解决一块释放一块的策略。 6、不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。可以适当的使用hashtable,vector 创建一组对象容器,然后从容器中去取那些对象,而不用每次new之后又丢弃 7、一般都是发生在开启大型文件或跟数据库一次拿了太多的数据,造成 Out Of Memory Error 的状况,这时就大概要计算一下数据量的最大值是多少,并且设定所需最小及最大的内存空间值。 “答案来源于网络,供您参考” 希望以上信息可以帮到您!
牧明 2019-12-02 02:16:21 0 浏览量 回答数 0

问题

【精品问答】Python数据爬取面试题库100问

Python爬虫面试题库100问: 1.遇到过得反爬虫策略以及解决方法? 2.urllib 和 urllib2 的区别? 3.列举网络爬虫所用到的网络数据包,解析包? 4.简述一下爬虫...
珍宝珠 2019-12-01 21:55:53 6502 浏览量 回答数 3

问题

【精品问答】python技术1000问(1)

为了方便python开发者快速找到相关技术问题和答案,开发者社区策划了python技术1000问内容,包含最基础的如何学python、实践中遇到的技术问题、python面试等维度内容。 我们会以每天至少50条的...
问问小秘 2019-12-01 21:57:48 456417 浏览量 回答数 22

回答

1、了解视频面试的有效交流成分 面试者可先试演盯着摄像头说话,让对方有一种面谈的感觉;增加一些无伤大雅的微动作,比如点头赞同对方;以及找到自己最适合视频说话的语调和语速,这些将会缩小与面试官的距离感。 2、熟悉面试平台的操作流程 可以使用一下自己常用的招聘APP,查找一下平台视频面试流程的详细说明 3、做好个人面试前的准备 天下大事,必作于细。除了对视频面试和面试平台的了解,个人的准备也是事关重要的。 - [1]个人的形象准备。 虽然是线上的视频面试,但还是可以看到彼此,我们都需要做好准备。比如面试官在国外的下午进行视频面试,国内刚好是晚上,如果此时一身家居服的你与面试官视频,对方难以感受到尊重。所以,无论任何时间点,符合面试的正式服装并且穿戴整齐,才能将专业度传递给面试官。 - [2]室内场所的选择。 选择一个安静的没有干扰的地方,视频区域整洁没有多余的杂物;灯光明亮,避免人像曝光,面试官可清晰看到你;确保坐的椅子舒适,利于自己在面试过程中精神保持专注。 - [3]个人设备和网络。 确认手机电量充足,对应的相机和麦克风功能可以正常使用;关闭任何会发出提示音的设备,避免面试中收到干扰;测试设备和网络是否能正常使用,减少面试中出现断网等低级错误。疫情未止,但这不会成为找工作面试的阻碍,在疫情期间做好面试的充足准备,提高线上面试的重视度,即便现场出现突发状况,镇静并且及时与对方沟通,商量解决方案,一切都能迎刃而解。总之,只要做好十足的准备,确保一切都是最佳状态,即便从未经历过视频面试的你,也能脱颖而出。 面试某技术岗位,事先练习面试题 比如Python,小编为大家精心准备了以下面试题 1.Python是如何进行内存管理的? 答:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制 一、对象的引用计数机制 Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。 引用计数增加的情况: - 1,一个对象分配一个新名称 - 2,将其放入一个容器中(如列表、元组或字典) 引用计数减少的情况: - 1,使用del语句对对象别名显示的销毁 - 2,引用超出作用域或被重新赋值 sys.getrefcount( )函数可以获得对象的当前引用计数 多数情况下,引用计数比你猜测得要大得多。对于不可变数据(如数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存。 二、垃圾回收 - 1,当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。 - 2,当两个对象a和b相互引用时,del语句可以减少a和b的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。 三、内存池机制 Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。 - 1,Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。 - 2,Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的malloc。 - 3,对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。 2.什么是lambda函数?它有什么好处? 答:lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数 lambda函数:首要用途是指点短小的回调函数 lambda [arguments]:expression a=lambdax,y:x+y a(3,11) 3.Python里面如何实现tuple和list的转换? 答:直接使用tuple和list函数就行了,type()可以判断对象的类型 4.请写出一段Python代码实现删除一个list里面的重复元素 答: - 1,使用set函数,set(list) - 2,使用字典函数, a=[1,2,4,2,4,5,6,5,7,8,9,0] b={} b=b.fromkeys(a) c=list(b.keys()) c 5.编程用sort进行排序,然后从最后一个元素开始判断 a=[1,2,4,2,4,5,7,10,5,5,7,8,9,0,3] a.sort() last=a[-1] for i inrange(len(a)-2,-1,-1): if last==a[i]: del a[i] else:last=a[i] print(a) 6.Python里面如何拷贝一个对象?(赋值,浅拷贝,深拷贝的区别) 答:赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个。 浅拷贝:创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用引用的方式修改其中一个对象,另外一个也会修改改变){1,完全切片方法;2,工厂函数,如list();3,copy模块的copy()函数} 深拷贝:创建一个新的对象,并且递归的复制它所包含的对象(修改其中一个,另外一个不会改变){copy模块的deep.deepcopy()函数} 7.介绍一下except的用法和作用? 答:try…except…except…[else…][finally…] 执行try下的语句,如果引发异常,则执行过程会跳到except语句。对每个except分支顺序尝试执行,如果引发的异常与except中的异常组匹配,执行相应的语句。如果所有的except都不匹配,则异常会传递到下一个调用本代码的最高层try代码中。 try下的语句正常执行,则执行else块代码。如果发生异常,就不会执行 如果存在finally语句,最后总是会执行。 8.Python中pass语句的作用是什么? 答:pass语句不会执行任何操作,一般作为占位符或者创建占位程序,whileFalse:pass 9.介绍一下Python下range()函数的用法? 答:列出一组数据,经常用在for in range()循环中 10.如何用Python来进行查询和替换一个文本字符串? 答:可以使用re模块中的sub()函数或者subn()函数来进行查询和替换, 格式:sub(replacement, string[,count=0])(replacement是被替换成的文本,string是需要被替换的文本,count是一个可选参数,指最大被替换的数量) import re p=re.compile(‘blue|white|red’) print(p.sub(‘colour’,'blue socks and red shoes’)) colour socks and colourshoes print(p.sub(‘colour’,'blue socks and red shoes’,count=1)) colour socks and redshoes subn()方法执行的效果跟sub()一样,不过它会返回一个二维数组,包括替换后的新的字符串和总共替换的数量 11.Python里面match()和search()的区别? 答:re模块中match(pattern,string[,flags]),检查string的开头是否与pattern匹配。 re模块中research(pattern,string[,flags]),在string搜索pattern的第一个匹配值。 print(re.match(‘super’, ‘superstition’).span()) (0, 5) print(re.match(‘super’, ‘insuperable’)) None print(re.search(‘super’, ‘superstition’).span()) (0, 5) print(re.search(‘super’, ‘insuperable’).span()) (2, 7) 12.用Python匹配HTML tag的时候,<.>和<.?>有什么区别? 答:术语叫贪婪匹配( <.> )和非贪婪匹配(<.?> ) 例如: test <.> : test <.?> : 13.Python里面如何生成随机数? 答:random模块 随机整数:random.randint(a,b):返回随机整数x,a<=x<=b random.randrange(start,stop,[,step]):返回一个范围在(start,stop,step)之间的随机整数,不包括结束值。 随机实数:random.random( ):返回0到1之间的浮点数 random.uniform(a,b):返回指定范围内的浮点数。 14.有没有一个工具可以帮助查找python的bug和进行静态的代码分析? 答:PyChecker是一个python代码的静态分析工具,它可以帮助查找python代码的bug, 会对代码的复杂度和格式提出警告 Pylint是另外一个工具可以进行codingstandard检查 15.如何在一个function里面设置一个全局的变量? 答:解决方法是在function的开始插入一个global声明: def f() global x 16.单引号,双引号,三引号的区别 答:单引号和双引号是等效的,如果要换行,需要符号(),三引号则可以直接换行,并且可以包含注释 如果要表示Let’s go 这个字符串 单引号:s4 = ‘Let\’s go’ 双引号:s5 = “Let’s go” s6 = ‘I realy like“python”!’ 这就是单引号和双引号都可以表示字符串的原因了 最后小编祝福大家能在2020年找到心仪的工作哈
剑曼红尘 2020-03-12 16:06:50 0 浏览量 回答数 0

问题

【分享】html5 开发工具——WeX5中的各种绑定方式

今天我想整理一下html5 开发工具——WeX5中的各种绑定方式,下面分为表现类、流程类、交互类 3 种类型分别介绍。 表现类绑定     表现类的绑定属性有visible、text、html、css、style、a...
小太阳1号 2019-12-01 21:25:48 4942 浏览量 回答数 3

问题

代码跑得慢甩锅Python,怎样给它提速30%?

大数据文摘出品 来源:Medium 编译:王转转 Python已经得到了全球程序员的喜爱,但是还是遭到一些人的诟病,原因之一就是认为它运行缓慢。 其实某个特定程序(...
茶什i 2020-01-13 18:42:24 177 浏览量 回答数 2

问题

写JQuery插件的基本知识:报错

普及JQuery知识 知识1:用JQuery写插件时,最核心的方法有如下两个: 复制代码 代码如下: $.extend(object) 可以理解为JQuery 添加一个静态方法。 ...
kun坤 2020-06-09 23:27:01 0 浏览量 回答数 1

回答

v-on 指令(可以简写为 @) 1、使用不带圆括号的形式,event 对象将被自动当做实参传入; 2、使用带圆括号的形式,我们需要使用 $event 变量显式传入 event 对象。 解析: 一、event 对象 (一)事件的 event 对象 你说你是搞前端的,那么你肯定就知道事件,知道事件,你就肯定知道 event 对象吧?各种的库、框架多少都有针对 event 对象的处理。比如 jquery,通过它内部进行一定的封装,我们开发的时候,就无需关注 event 对象的部分兼容性问题。最典型的,如果我们要阻止默认事件,在 chrome 等浏览器中,我们可能要写一个: event.preventDefault(); 而在 IE 中,我们则需要写: event.returnValue = false; 多亏了 jquery ,跨浏览器的实现,我们统一只需要写: event.preventDefault(); 兼容?jquery 内部帮我们搞定了。类似的还有比如阻止事件冒泡以以及事件绑定(addEventListener / attachEvent)等,简单到很多的后端都会使用 $('xxx').bind(...),这不是我们今天的重点,我们往下看。 (二)vue 中的 event 对象 我们知道,相比于 jquery,vue 的事件绑定可以显得更加直观和便捷,我们只需要在模板上添加一个 v-on 指令(还可以简写为 @),即可完成类似于 $('xxx').bind 的效果,少了一个利用选择器查询元素的操作。我们知道,jquery 中,event 对象会被默认当做实参传入到处理函数中,如下 $("body").bind("click", function(event) { console.log(typeof event); // object }); 这里直接就获取到了 event 对象,那么问题来了,vue 中呢? <div id="app"> <button v-on:click="click">click me</button> </div> ... var app = new Vue({ el: '#app', methods: { click(event) { console.log(typeof event); // object } } }); 这里的实现方式看起来和 jquery 是一致的啊,但是实际上,vue 比 jquery 要要复杂得多,jquery 官方也明确的说,v-on 不简单是 addEventListener 的语法糖。在 jquery 中,我们传入到 bind 方法中的回调,只能是一个函数表类型的变量或者一个匿名函数,传递的时候,还不能执行它(在后面加上一堆圆括号),否则就变成了取这一个函数的返回值作为事件回调。而我们知道,vue 的 v-on 指令接受的值可以是函数执行的形式,比如 v-on:click="click(233)" 。这里我们可以传递任何需要传递的参数,甚至可以不传递参数: <div id="app"> <button v-on:click="click()">click me</button> </div> ... var app = new Vue({ el: '#app', methods: { click(event) { console.log(typeof event); // undefined } } }); 咦?我的 event 对象呢?怎么不见了?打印看看 arguments.length 也是 0,说明这时候确实没有实参被传入进来。T_T,那我们如果既需要传递参数,又需要用到 event 对象,这个该怎么办呢? (三)$event 翻看 vue 文档,不难发现,其实我们可以通过将一个特殊变量 $event 传入到回调中解决这个问题: <div id="app"> <button v-on:click="click($event, 233)">click me</button> </div> ... var app = new Vue({ el: '#app', methods: { click(event, val) { console.log(typeof event); // object } } }); 好吧,这样看起来就正常了。 简单总结来说: 使用不带圆括号的形式,event 对象将被自动当做实参传入; 使用带圆括号的形式,我们需要使用 $event 变量显式传入 event 对象。 二、乌龙 前面都算是铺垫吧,现在真正的乌龙来了。 翻看小伙伴儿的代码,偶然看到了类似下面的代码: <div id="app"> <button v-on:click="click(233)">click me</button> </div> ... var app = new Vue({ el: '#app', methods: { click(val) { console.log(typeof event); // object } } }); 看到这一段代码,我的内心是崩溃的,丢进 chrome 里面一跑,尼玛还真可以,打印 arguments.length,也是正常的 1。尼玛!这是什么鬼?毁三观啊? 既没有传入实参,也没有接收的形参,这个 event 对象的来源,要么是上级作用链,要么。。。是全局作用域。。。全局的,不禁想到了 window.event 。再次上 MDN 确认了一下,果然,window.event,ie 和 chrome 都在 window 对象上有这样一个属性:
问问小秘 2019-12-02 03:20:58 0 浏览量 回答数 0

回答

Python里的name查找是满足LEGB规则的(local=>enclosed=>global=>build-in),所以第一段代码完全OK; 但第二段就涉及到class的命名空间问题了,learningpython里是这么说的: •Unqualifiednames(e.g.,X)dealwithscopes.•Qualifiedattributenames(e.g.,object.X)useobjectnamespaces. 总之,如果直接printi的话,就会按照LEGB准则来查找,而这里的i是在a的一个属性,在fun的作用域中是找不到的,所以就出错啦~~~谢谢~明白了~ def里加个globali试试 http://blog.sina.com.cn/s/blog_76e94d210100vxur.html不行的,i是在class作用域里的,也不是global的,除非两个i都加global,但这就不是我要说的意思了~python的语法是这样的,引用对象的属性一定要用self.i,直接i就是全局或函数的局部变量恩~谢谢~~ 第二个例子里,i是一个类变量 应该好好看看python的面向对象。
爱吃鱼的程序员 2020-06-22 14:17:59 0 浏览量 回答数 0

回答

一、接口的默认方法 Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法,示例如下: interface Formula { double calculate(int a); default double sqrt(int a) { return Math.sqrt(a); } } Formula接口在拥有calculate方法之外同时还定义了sqrt方法,实现了Formula接口的子类只需要实现一个calculate方法,默认方法sqrt将在子类上可以直接使用。 Formula formula = new Formula() { @Override public double calculate(int a) { return sqrt(a * 100); } }; formula.calculate(100); // 100.0 formula.sqrt(16); // 4.0 文中的formula被实现为一个匿名类的实例,该代码非常容易理解,6行代码实现了计算 sqrt(a * 100)。在下一节中,我们将会看到实现单方法接口的更简单的做法。 译者注: 在Java中只有单继承,如果要让一个类赋予新的特性,通常是使用接口来实现,在C++中支持多继承,允许一个子类同时具有多个父类的接口与功能,在其他语言中,让一个类同时具有其他的可复用代码的方法叫做mixin。新的Java 8 的这个特新在编译器实现的角度上来说更加接近Scala的trait。 在C#中也有名为扩展方法的概念,允许给已存在的类型扩展方法,和Java 8的这个在语义上有差别。 二、Lambda 表达式 首先看看在老版本的Java中是如何排列字符串的: List<String> names = Arrays.asList("peter", "anna", "mike", "xenia"); Collections.sort(names, new Comparator<String>() { @Override public int compare(String a, String b) { return b.compareTo(a); } }); 只需要给静态方法 Collections.sort 传入一个List对象以及一个比较器来按指定顺序排列。通常做法都是创建一个匿名的比较器对象然后将其传递给sort方法。 在Java 8 中你就没必要使用这种传统的匿名对象的方式了,Java 8提供了更简洁的语法,lambda表达式: Collections.sort(names, (String a, String b) -> { return b.compareTo(a); }); 看到了吧,代码变得更段且更具有可读性,但是实际上还可以写得更短: Collections.sort(names, (String a, String b) -> b.compareTo(a)); 对于函数体只有一行代码的,你可以去掉大括号{}以及return关键字,但是你还可以写得更短点: Collections.sort(names, (a, b) -> b.compareTo(a)); Java编译器可以自动推导出参数类型,所以你可以不用再写一次类型。接下来我们看看lambda表达式还能作出什么更方便的东西来 三、函数式接口 Lambda表达式是如何在java的类型系统中表示的呢?每一个lambda表达式都对应一个类型,通常是接口类型。而“函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。因为 默认方法 不算抽象方法,所以你也可以给你的函数式接口添加默认方法。 我们可以将lambda表达式当作任意只包含一个抽象方法的接口类型,确保你的接口一定达到这个要求,你只需要给你的接口添加 @FunctionalInterface 注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。 @FunctionalInterface interface Converter<F, T> { T convert(F from); } Converter<String, Integer> converter = (from) -> Integer.valueOf(from); Integer converted = converter.convert("123"); System.out.println(converted); // 123 需要注意如果@FunctionalInterface如果没有指定,上面的代码也是对的。 译者注 将lambda表达式映射到一个单方法的接口上,这种做法在Java 8之前就有别的语言实现,比如Rhino JavaScript解释器,如果一个函数参数接收一个单方法的接口而你传递的是一个function,Rhino 解释器会自动做一个单接口的实例到function的适配器,典型的应用场景有 org.w3c.dom.events.EventTarget 的addEventListener 第二个参数 EventListener。 四、方法与构造函数引用 前一节中的代码还可以通过静态方法引用来表示: Converter<String, Integer> converter = Integer::valueOf; Integer converted = converter.convert("123"); System.out.println(converted); // 123 Java 8 允许你使用 :: 关键字来传递方法或者构造函数引用,上面的代码展示了如何引用一个静态方法,我们也可以引用一个对象的方法: converter = something::startsWith; String converted = converter.convert("Java"); System.out.println(converted); // "J" 接下来看看构造函数是如何使用::关键字来引用的,首先我们定义一个包含多个构造函数的简单类: class Person { String firstName; String lastName; Person() {} Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } } 接下来我们指定一个用来创建Person对象的对象工厂接口: interface PersonFactory<P extends Person> { P create(String firstName, String lastName); } 这里我们使用构造函数引用来将他们关联起来,而不是实现一个完整的工厂: PersonFactory<Person> personFactory = Person::new; Person person = personFactory.create("Peter", "Parker"); 我们只需要使用 Person::new 来获取Person类构造函数的引用,Java编译器会自动根据PersonFactory.create方法的签名来选择合适的构造函数。 五、Lambda 作用域 在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。 六、访问局部变量 我们可以直接在lambda表达式中访问外层的局部变量: final int num = 1; Converter<Integer, String> stringConverter = (from) -> String.valueOf(from + num); stringConverter.convert(2); // 3 但是和匿名对象不同的是,这里的变量num可以不用声明为final,该代码同样正确: int num = 1; Converter<Integer, String> stringConverter = (from) -> String.valueOf(from + num); stringConverter.convert(2); // 3 不过这里的num必须不可被后面的代码修改(即隐性的具有final的语义),例如下面的就无法编译: int num = 1; Converter<Integer, String> stringConverter = (from) -> String.valueOf(from + num); num = 3; 在lambda表达式中试图修改num同样是不允许的。 七、访问对象字段与静态变量 和本地变量不同的是,lambda内部对于实例的字段以及静态变量是即可读又可写。该行为和匿名对象是一致的: class Lambda4 { static int outerStaticNum; int outerNum; void testScopes() { Converter<Integer, String> stringConverter1 = (from) -> { outerNum = 23; return String.valueOf(from); }; Converter<Integer, String> stringConverter2 = (from) -> { outerStaticNum = 72; return String.valueOf(from); }; } } 八、访问接口的默认方法 还记得第一节中的formula例子么,接口Formula定义了一个默认方法sqrt可以直接被formula的实例包括匿名对象访问到,但是在lambda表达式中这个是不行的。 Lambda表达式中是无法访问到默认方法的,以下代码将无法编译: Formula formula = (a) -> sqrt( a * 100); Built-in Functional Interfaces JDK 1.8 API包含了很多内建的函数式接口,在老Java中常用到的比如Comparator或者Runnable接口,这些接口都增加了@FunctionalInterface注解以便能用在lambda上。 Java 8 API同样还提供了很多全新的函数式接口来让工作更加方便,有一些接口是来自Google Guava库里的,即便你对这些很熟悉了,还是有必要看看这些是如何扩展到lambda上使用的。 Predicate接口 Predicate 接口只有一个参数,返回boolean类型。该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非): Predicate<String> predicate = (s) -> s.length() > 0; predicate.test("foo"); // true predicate.negate().test("foo"); // false Predicate<Boolean> nonNull = Objects::nonNull; Predicate<Boolean> isNull = Objects::isNull; Predicate<String> isEmpty = String::isEmpty; Predicate<String> isNotEmpty = isEmpty.negate(); Function 接口 Function 接口有一个参数并且返回一个结果,并附带了一些可以和其他函数组合的默认方法(compose, andThen): Function<String, Integer> toInteger = Integer::valueOf; Function<String, String> backToString = toInteger.andThen(String::valueOf); backToString.apply("123"); // "123" Supplier 接口 Supplier 接口返回一个任意范型的值,和Function接口不同的是该接口没有任何参数 Supplier personSupplier = Person::new; personSupplier.get(); // new Person Consumer 接口 Consumer 接口表示执行在单个参数上的操作。 Consumer greeter = (p) -> System.out.println("Hello, " + p.firstName); greeter.accept(new Person("Luke", "Skywalker")); Comparator 接口 Comparator 是老Java中的经典接口, Java 8在此之上添加了多种默认方法: Comparator comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName); Person p1 = new Person("John", "Doe"); Person p2 = new Person("Alice", "Wonderland"); comparator.compare(p1, p2); // > 0 comparator.reversed().compare(p1, p2); // < 0 Optional 接口 Optional 不是函数是接口,这是个用来防止NullPointerException异常的辅助类型,这是下一届中将要用到的重要概念,现在先简单的看看这个接口能干什么: Optional 被定义为一个简单的容器,其值可能是null或者不是null。在Java 8之前一般某个函数应该返回非空对象但是偶尔却可能返回了null,而在Java 8中,不推荐你返回null而是返回Optional。 Optional optional = Optional.of("bam"); optional.isPresent(); // true optional.get(); // "bam" optional.orElse("fallback"); // "bam" optional.ifPresent((s) -> System.out.println(s.charAt(0))); // "b" Stream 接口 java.util.Stream 表示能应用在一组元素上一次执行的操作序列。Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,这样你就可以将多个操作依次串起来。Stream 的创建需要指定一个数据源,比如 java.util.Collection的子类,List或者Set, Map不支持。Stream的操作可以串行执行或者并行执行。 首先看看Stream是怎么用,首先创建实例代码的用到的数据List: List stringCollection = new ArrayList<>(); stringCollection.add("ddd2"); stringCollection.add("aaa2"); stringCollection.add("bbb1"); stringCollection.add("aaa1"); stringCollection.add("bbb3"); stringCollection.add("ccc"); stringCollection.add("bbb2"); stringCollection.add("ddd1"); Java 8扩展了集合类,可以通过 Collection.stream() 或者 Collection.parallelStream() 来创建一个Stream。下面几节将详细解释常用的Stream操作: Filter 过滤 过滤通过一个predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作,所以我们可以在过滤后的结果来应用其他Stream操作(比如forEach)。forEach需要一个函数来对过滤后的元素依次执行。forEach是一个最终操作,所以我们不能在forEach之后来执行其他Stream操作。 stringCollection .stream() .filter((s) -> s.startsWith("a")) .forEach(System.out::println); // "aaa2", "aaa1" Sort 排序 排序是一个中间操作,返回的是排序好后的Stream。如果你不指定一个自定义的Comparator则会使用默认排序。 stringCollection .stream() .sorted() .filter((s) -> s.startsWith("a")) .forEach(System.out::println); // "aaa1", "aaa2" 需要注意的是,排序只创建了一个排列好后的Stream,而不会影响原有的数据源,排序之后原数据stringCollection是不会被修改的。 System.out.println(stringCollection); // ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1 Map 映射 中间操作map会将元素根据指定的Function接口来依次将元素转成另外的对象,下面的示例展示了将字符串转换为大写字符串。你也可以通过map来讲对象转换成其他类型,map返回的Stream类型是根据你map传递进去的函数的返回值决定的。 stringCollection .stream() .map(String::toUpperCase) .sorted((a, b) -> b.compareTo(a)) .forEach(System.out::println); // "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1" Match 匹配 Stream提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。所有的匹配操作都是最终操作,并返回一个boolean类型的值。 boolean anyStartsWithA = stringCollection .stream() .anyMatch((s) -> s.startsWith("a")); System.out.println(anyStartsWithA); // true boolean allStartsWithA = stringCollection .stream() .allMatch((s) -> s.startsWith("a")); System.out.println(allStartsWithA); // false boolean noneStartsWithZ = stringCollection .stream() .noneMatch((s) -> s.startsWith("z")); System.out.println(noneStartsWithZ); // true Count 计数 计数是一个最终操作,返回Stream中元素的个数,返回值类型是long。 long startsWithB = stringCollection .stream() .filter((s) -> s.startsWith("b")) .count(); System.out.println(startsWithB); // 3 Reduce 规约 这是一个最终操作,允许通过指定的函数来讲stream中的多个元素规约为一个元素,规越后的结果是通过Optional接口表示的: Optional reduced = stringCollection .stream() .sorted() .reduce((s1, s2) -> s1 + "#" + s2); reduced.ifPresent(System.out::println); // "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2" 并行Streams 前面提到过Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。 下面的例子展示了是如何通过并行Stream来提升性能: 首先我们创建一个没有重复元素的大表 int max = 1000000; List values = new ArrayList<>(max); for (int i = 0; i < max; i++) { UUID uuid = UUID.randomUUID(); values.add(uuid.toString()); } 然后我们计算一下排序这个Stream要耗时多久, 串行排序: long t0 = System.nanoTime(); long count = values.stream().sorted().count(); System.out.println(count); long t1 = System.nanoTime(); long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0); System.out.println(String.format("sequential sort took: %d ms", millis)); // 串行耗时: 899 ms 并行排序: long t0 = System.nanoTime(); long count = values.parallelStream().sorted().count(); System.out.println(count); long t1 = System.nanoTime(); long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0); System.out.println(String.format("parallel sort took: %d ms", millis)); // 并行排序耗时: 472 ms 上面两个代码几乎是一样的,但是并行版的快了50%之多,唯一需要做的改动就是将stream()改为parallelStream()。 Map 前面提到过,Map类型不支持stream,不过Map提供了一些新的有用的方法来处理一些日常任务。 Map<Integer, String> map = new HashMap<>(); for (int i = 0; i < 10; i++) { map.putIfAbsent(i, "val" + i); } map.forEach((id, val) -> System.out.println(val)); 以上代码很容易理解, putIfAbsent 不需要我们做额外的存在性检查,而forEach则接收一个Consumer接口来对map里的每一个键值对进行操作。 下面的例子展示了map上的其他有用的函数: map.computeIfPresent(3, (num, val) -> val + num); map.get(3); // val33 map.computeIfPresent(9, (num, val) -> null); map.containsKey(9); // false map.computeIfAbsent(23, num -> "val" + num); map.containsKey(23); // true map.computeIfAbsent(3, num -> "bam"); map.get(3); // val33 接下来展示如何在Map里删除一个键值全都匹配的项 map.remove(3, "val3"); map.get(3); // val33 map.remove(3, "val33"); map.get(3); // null 另外一个有用的方法 map.getOrDefault(42, "not found"); // not found 对Map的元素做合并也变得很容易了: map.merge(9, "val9", (value, newValue) -> value.concat(newValue)); map.get(9); // val9 map.merge(9, "concat", (value, newValue) -> value.concat(newValue)); map.get(9); // val9concat Merge做的事情是如果键名不存在则插入,否则则对原键对应的值做合并操作并重新插入到map中。 九、Date API Java 8 在包java.time下包含了一组全新的时间日期API。新的日期API和开源的Joda-Time库差不多,但又不完全一样,下面的例子展示了这组新API里最重要的一些部分: Clock 时钟 Clock类提供了访问当前日期和时间的方法,Clock是时区敏感的,可以用来取代 System.currentTimeMillis() 来获取当前的微秒数。某一个特定的时间点也可以使用Instant类来表示,Instant类也可以用来创建老的java.util.Date对象。 Clock clock = Clock.systemDefaultZone(); long millis = clock.millis(); Instant instant = clock.instant(); Date legacyDate = Date.from(instant); // legacy java.util.Date Timezones 时区 在新API中时区使用ZoneId来表示。时区可以很方便的使用静态方法of来获取到。 时区定义了到UTS时间的时间差,在Instant时间点对象到本地日期对象之间转换的时候是极其重要的。 System.out.println(ZoneId.getAvailableZoneIds()); // prints all available timezone ids ZoneId zone1 = ZoneId.of("Europe/Berlin"); ZoneId zone2 = ZoneId.of("Brazil/East"); System.out.println(zone1.getRules()); System.out.println(zone2.getRules()); // ZoneRules[currentStandardOffset=+01:00] // ZoneRules[currentStandardOffset=-03:00] LocalTime 本地时间 LocalTime 定义了一个没有时区信息的时间,例如 晚上10点,或者 17:30:15。下面的例子使用前面代码创建的时区创建了两个本地时间。之后比较时间并以小时和分钟为单位计算两个时间的时间差: LocalTime now1 = LocalTime.now(zone1); LocalTime now2 = LocalTime.now(zone2); System.out.println(now1.isBefore(now2)); // false long hoursBetween = ChronoUnit.HOURS.between(now1, now2); long minutesBetween = ChronoUnit.MINUTES.between(now1, now2); System.out.println(hoursBetween); // -3 System.out.println(minutesBetween); // -239 LocalTime 提供了多种工厂方法来简化对象的创建,包括解析时间字符串。 LocalTime late = LocalTime.of(23, 59, 59); System.out.println(late); // 23:59:59 DateTimeFormatter germanFormatter = DateTimeFormatter .ofLocalizedTime(FormatStyle.SHORT) .withLocale(Locale.GERMAN); LocalTime leetTime = LocalTime.parse("13:37", germanFormatter); System.out.println(leetTime); // 13:37 LocalDate 本地日期 LocalDate 表示了一个确切的日期,比如 2014-03-11。该对象值是不可变的,用起来和LocalTime基本一致。下面的例子展示了如何给Date对象加减天/月/年。另外要注意的是这些对象是不可变的,操作返回的总是一个新实例。 LocalDate today = LocalDate.now(); LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS); LocalDate yesterday = tomorrow.minusDays(2); LocalDate independenceDay = LocalDate.of(2014, Month.JULY, 4); DayOfWeek dayOfWeek = independenceDay.getDayOfWeek(); System.out.println(dayOfWeek); // FRIDAY 从字符串解析一个LocalDate类型和解析LocalTime一样简单: DateTimeFormatter germanFormatter = DateTimeFormatter .ofLocalizedDate(FormatStyle.MEDIUM) .withLocale(Locale.GERMAN); LocalDate xmas = LocalDate.parse("24.12.2014", germanFormatter); System.out.println(xmas); // 2014-12-24 LocalDateTime 本地日期时间 LocalDateTime 同时表示了时间和日期,相当于前两节内容合并到一个对象上了。LocalDateTime和LocalTime还有LocalDate一样,都是不可变的。LocalDateTime提供了一些能访问具体字段的方法。 LocalDateTime sylvester = LocalDateTime.of(2014, Month.DECEMBER, 31, 23, 59, 59); DayOfWeek dayOfWeek = sylvester.getDayOfWeek(); System.out.println(dayOfWeek); // WEDNESDAY Month month = sylvester.getMonth(); System.out.println(month); // DECEMBER long minuteOfDay = sylvester.getLong(ChronoField.MINUTE_OF_DAY); System.out.println(minuteOfDay); // 1439 只要附加上时区信息,就可以将其转换为一个时间点Instant对象,Instant时间点对象可以很容易的转换为老式的java.util.Date。 Instant instant = sylvester .atZone(ZoneId.systemDefault()) .toInstant(); Date legacyDate = Date.from(instant); System.out.println(legacyDate); // Wed Dec 31 23:59:59 CET 2014 格式化LocalDateTime和格式化时间和日期一样的,除了使用预定义好的格式外,我们也可以自己定义格式: DateTimeFormatter formatter = DateTimeFormatter .ofPattern("MMM dd, yyyy - HH:mm"); LocalDateTime parsed = LocalDateTime.parse("Nov 03, 2014 - 07:13", formatter); String string = formatter.format(parsed); System.out.println(string); // Nov 03, 2014 - 07:13 和java.text.NumberFormat不一样的是新版的DateTimeFormatter是不可变的,所以它是线程安全的。 关于时间日期格式的详细信息:http://download.java.net/jdk8/docs/api/java/time/format/DateTimeFormatter.html 十、Annotation 注解 在Java 8中支持多重注解了,先看个例子来理解一下是什么意思。 首先定义一个包装类Hints注解用来放置一组具体的Hint注解: @interface Hints { Hint[] value(); } @Repeatable(Hints.class) @interface Hint { String value(); } Java 8允许我们把同一个类型的注解使用多次,只需要给该注解标注一下@Repeatable即可。 例 1: 使用包装类当容器来存多个注解(老方法) @Hints({@Hint("hint1"), @Hint("hint2")}) class Person {} 例 2:使用多重注解(新方法) @Hint("hint1") @Hint("hint2") class Person {} 第二个例子里java编译器会隐性的帮你定义好@Hints注解,了解这一点有助于你用反射来获取这些信息: Hint hint = Person.class.getAnnotation(Hint.class); System.out.println(hint); // null Hints hints1 = Person.class.getAnnotation(Hints.class); System.out.println(hints1.value().length); // 2 Hint[] hints2 = Person.class.getAnnotationsByType(Hint.class); System.out.println(hints2.length); // 2 即便我们没有在Person类上定义@Hints注解,我们还是可以通过 getAnnotation(Hints.class) 来获取 @Hints注解,更加方便的方法是使用 getAnnotationsByType 可以直接获取到所有的@Hint注解。 另外Java 8的注解还增加到两种新的target上了: @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) @interface MyAnnotation {}
日你dady哟 2019-12-02 03:08:13 0 浏览量 回答数 0

问题

使用IBPP在C++中操作FireBird/Interbase数据库:报错

FireBird是一种小巧的关系型数据库,它有多种版本,包括服务器版(象MySQL),单机版(象Access)以及嵌入式(象SQLite)。而且不管是服务器版还是嵌入式版...
kun坤 2020-06-06 13:49:18 0 浏览量 回答数 1

问题

阅读《C陷阱与缺陷》的知识增量 第一章 词法陷阱 第二章 语法陷阱 第三章 语义?400报错

阅读《C陷阱与缺陷》的知识增量 第一章 词法陷阱 第二章 语法陷阱 第三章 语义陷阱 第四章 连接 第五章 库函数 第六章 预处理器 第七章 可移植性缺陷? 400 报错 看完《C陷阱与缺陷》,忍不住要重新翻一下ÿ...
爱吃鱼的程序员 2020-06-04 15:05:01 2 浏览量 回答数 1

问题

阅读《C陷阱与缺陷》的知识增量 第一章 词法陷阱 第二章 语法陷阱 第三章 语义?400报错

阅读《C陷阱与缺陷》的知识增量 第一章 词法陷阱 第二章 语法陷阱 第三章 语义陷阱 第四章 连接 第五章 库函数 第六章 预处理器 第七章 可移植性缺陷? 400 报错 看完《C陷阱与缺陷》,忍不住要重新翻一下ÿ...
爱吃鱼的程序员 2020-06-04 12:00:05 3 浏览量 回答数 1

回答

我来解释下你的问题,可能会有点长 charp[]="helloworld";   -称为A定义方式char*p="helloworld";   -称为B定义方式两个p的区别  分两种情况: 1这个p是全局变量(通俗点就是在函数外面定义的)那么这两种方式,产生的效果有点相同的地方:  A:使用A定义方式,只分配了 sizeof(p)== sizeof("helloworld")==12字节的内存 (字符串长度为11,加上一个字节的结束符号) p是这段内存的开始地址,他不是实际的指针变量,所以  p=p+1; 这类的操作,连编译都通过不了。  B:使用B定义方式,字符串分配了sizeof("helloworld")==12 的内存,除了这之外还分配了sizeof(p)==sizeof(void*)的内存(一个指针的内存一般是4或8字节) p是一个指针,它存的值是这个字符串的开始地址。所以   p++;p="shit";  这类的操作都是合法的。 但是如果B方式没有修改p指针的指向,这两种方式使用p都能够获取到字符串"helloworld",产生是一样的错觉,其实差别很大。但是有一点是相同的: 相同的字符串"helloworld"会存放在全局变量存放的地方。 2这个p是局部变量(通俗点就是在函数内部定义的)那么这两种方式,产生的效果就会有很大的不同:  A:使用A定义方式,只在stack(栈)中分配了12字节的内存 p是这段内存的开始地址,他不是实际的指针变量,所以  p=p+1; 这类的操作,连编译都通过不了。 而且只能在函数内部使用p,函数返回后,p这块内存值就是非法的了  B:使用B定义方式,也是在全局变量区分配了sizeof("helloworld")==12的内存, 除了这之外还在stack(栈)中分配了一个指针的内存 p是一个指针,它存的值是这个字符串的开始地址。所以   p++;p="shit";  这类的操作都是合法的。 但是只能在函数内部使用p      还有一个可以修改和不能修改忘记说了回答的不能再好了不是内存泄露,当函数调用的时候,里面你只是用到了局部变量,自然函数调用完之后就被自动清除了,所以指针指向的地方已经没有数据了,不存在内存泄露;如果你在函数中换成malloc就可以成功返回了,不过记得自己用完后释放,否则会造成内存泄露回复 @幻の上帝:你看下我回复zerodeng的错。此处决定生存期的重点是存储类而不是作用域。自动局部对象会在块结束时销毁,但静态局部对象就不会。大概对吧回复 @Xsank:“HelloWorld”这个数据还在,会被编译器放到.rodata这个只读的段里回复 @txgcwm:多半会被覆盖,栈空间那么少如果那块内存被其他数据覆盖了,就出问题了用char*p="abc";就可以了要加const printf(str); =》楼主这样也不合理,要么就用puts(str);“Youshouldnever returnanaddresstoalocalvariable” 引用来自“Xsank”的答案 不是内存泄露,当函数调用的时候,里面你只是用到了局部变量,自然函数调用完之后就被自动清除了,所以指针指向的地方已经没有数据了,不存在内存泄露;如果你在函数中换成malloc就可以成功返回了,不过记得自己用完后释放,否则会造成内存泄露还有一个错误。字符串字面量在C语言不具有const类型,根本就没说一定要实现为映像的只读区域,更不是什么常量。因为修改字符串字面量行为未定义,所以允许实现在只读存储上。调用栈是具体的语言实现才需要考虑的,不使用栈来模拟栈语义也可行(虽然一般低效)。顺便,避免使用“堆栈”这种对新手来说稀里糊涂的翻译。仍然理解错误。局部是指作用域,而决定生存期的是存储期。只不过俗称“局部”的块作用域对象可以显式或隐式地声明为自动存储类对象(而文件作用域不行)而具有自动存储期罢了,并没有和局部进一步的联系。关于前者,是局部变量,执行的时候会在堆栈上分配空间存放数据,你可以随意操控,但是过后就被抹杀了;关于后者,其实那是常量,放在.data中,只不过你有了一个指向其地址的指针,这个是在程序执行过程中保存的,但是只可读,所以过后你依旧能访问 引用来自“zerodeng”的答案 引用来自“Xsank”的答案 不是内存泄露,当函数调用的时候,里面你只是用到了局部变量,自然函数调用完之后就被自动清除了,所以指针指向的地方已经没有数据了,不存在内存泄露;如果你在函数中换成malloc就可以成功返回了,不过记得自己用完后释放,否则会造成内存泄露#Goodquestion#建议先去了解下应用程序在内存中的分布,理解堆和栈,然后再回过头来看这个就会轻松很多。
爱吃鱼的程序员 2020-06-22 21:00:36 0 浏览量 回答数 0

回答

vue 双向数据绑定实现原理(数据劫持) ,卡槽slot,生命周期,getter, setter,nexttrick vue router hash 模式,history模式,meta参数,keep-alive,路由传值params和query的区别,redirct(重定向) vuex state, action, mutation,数据流 inject、provide mixin混入 eventbus vue axios 、axios 拦截器 es6 箭头函数(this指向),解构赋值 ,异步(promise–then、catch、all、finally;async–awit),设计模式,模块化,let 和 var 区别(作用域,变量提升)、pubsub Object.assign({}, item, ob); 解决vue双向数据绑定对对象属性的新增和删除不能及时响应的问题 Set 实现数组去重 filter 实现数组 arry.filter(item => item); 筛选 组件:组件间传值 ref、ref、ref、parent、 $emit, css预处理器:stylus,less,sass 打包工具:grunt,webpack typeScript :js超集 react svg(path,stroke, clip-path,mask,refs,use,滤镜, transform),canvas,css3 rxjs rxjs 集成到 vue node(koa) + nuxt + vue 无障碍阅读 quartz/corn jsDoc WebAssembly
问问小秘 2019-12-27 11:12:26 0 浏览量 回答数 0

回答

JavaScript具有强大的语义,可以遍历数组和类似数组的对象。我将答案分为两部分:真正数组的选项,以及仅是数组之类的东西的选项,例如arguments对象,其他可迭代对象(ES2015 +),DOM集合,等等。 我会很快注意到,您现在可以通过将ES2015转换为ES5 ,甚至在ES5引擎上使用ES2015选项。搜索“ ES2015 transpiling” /“ ES6 transpiling”以了解更多... 好吧,让我们看看我们的选择: 对于实际数组 您目前在ECMAScript 5(“ ES5”)中拥有三个选项,这是目前最广泛支持的版本,在ECMAScript 2015中又添加了两个选项(“ ES2015”,“ ES6”): 使用forEach及相关(ES5 +) 使用一个简单的for循环 正确使用for-in 使用for-of(隐式使用迭代器)(ES2015 +) 明确使用迭代器(ES2015 +) 细节: 1.使用forEach及相关 在任何可以访问ArrayES5(直接或使用polyfills)添加的功能的模糊现代环境(因此,不是IE8)中,都可以使用forEach(spec| MDN): var a = ["a", "b", "c"]; a.forEach(function(entry) { console.log(entry); }); forEach接受回调函数,以及(可选)this调用该回调时要使用的值(上面未使用)。依次为数组中的每个条目调用回调,从而跳过稀疏数组中不存在的条目。尽管上面只使用了一个参数,但回调函数使用以下三个参数调用:每个条目的值,该条目的索引以及对要迭代的数组的引用(以防您的函数尚未使用它) )。 除非您支持IE8之类的过时浏览器(截至2016年9月,NetApps在该市场上所占份额刚刚超过4%),forEach否则您可以在没有垫片的情况下在通用网页中愉快地使用。如果您确实需要支持过时的浏览器,forEach则可以轻松进行填充/填充(搜索“ es5 shim”以获得多个选项)。 forEach 这样做的好处是您不必在包含范围中声明索引和值变量,因为它们是作为迭代函数的参数提供的,因此可以很好地将作用域限定为该迭代。 如果您担心为每个数组条目进行函数调用的运行时成本,请不必担心;细节。 此外,forEach它是“遍历所有对象”功能,但是ES5定义了其他几个有用的“遍历数组并做事”功能,包括: every(在第一次返回回调false或出现错误时停止循环) some(在第一次返回回调true或发生错误时停止循环) filter(创建一个新数组,其中包含过滤器函数返回的元素,true并省略其返回的元素false) map (根据回调返回的值创建一个新数组) reduce (通过重复调用回调并传入先前的值来建立值;有关详细信息,请参见规范;对汇总数组内容和许多其他内容很有用) reduceRight(如reduce,但按降序而不是升序工作) 2.使用一个简单的for循环 有时,旧方法是最好的: var index; var a = ["a", "b", "c"]; for (index = 0; index < a.length; ++index) { console.log(a[index]); } 如果数组的长度将不会在循环过程中改变,它在性能敏感的代码(不可能),一个稍微复杂一点的版本抓住了长度达阵可能是一个很小的有点快: var index, len; var a = ["a", "b", "c"]; for (index = 0, len = a.length; index < len; ++index) { console.log(a[index]); } 和/或倒数: var index; var a = ["a", "b", "c"]; for (index = a.length - 1; index >= 0; --index) { console.log(a[index]); } 但是,使用现代JavaScript引擎,很少需要消耗掉最后的能量。 在ES2015及更高版本中,可以使索引和值变量在for循环本地: let a = ["a", "b", "c"]; for (let index = 0; index < a.length; ++index) { let value = a[index]; console.log(index, value); } //console.log(index); // would cause "ReferenceError: index is not defined" //console.log(value); // would cause "ReferenceError: value is not defined" 而且,当您执行此操作时,不仅会为每个循环迭代创建一个新的闭包,value而且还会index为每个循环迭代重新创建一个闭包,这意味着在循环主体中创建的闭包保留对为该特定迭代创建的index(和value)的引用: let divs = document.querySelectorAll("div"); for (let index = 0; index < divs.length; ++index) { divs[index].addEventListener('click', e => { console.log("Index is: " + index); }); } 如果您有五个div,则单击第一个将获得“索引为:0”,如果单击最后一个则将为“索引为:4”。如果您使用而不是则无法使用。varlet 3. 正确使用for-in 你会得到别人告诉你使用for-in,但是这不是for-in对。for-in遍历对象的可枚举属性,而不是数组的索引。甚至在ES2015(ES6)中也不保证顺序。ES2015 +不定义为对象属性(通过[[OwnPropertyKeys]],[[Enumerate]]以及使用他们喜欢的东西Object.getOwnPropertyKeys),但它并没有定义for-in将遵循这个顺序。(其他答案的详细信息。) for-in数组上唯一真正的用例是: 这是一个稀疏的数组,里面有巨大的空隙,或者 您正在使用非元素属性,并且希望将它们包括在循环中 仅查看第一个示例:for-in如果使用适当的保护措施,则可以用来访问那些备用阵列元素: // a is a sparse array var key; var a = []; a[0] = "a"; a[10] = "b"; a[10000] = "c"; for (key in a) { if (a.hasOwnProperty(key) && // These checks are /^0$|^[1-9]\d*$/.test(key) && // explained key <= 4294967294 // below ) { console.log(a[key]); } } 请注意以下三个检查: 该对象具有该名称的自身属性(不是从其原型继承的属性),并且 该键是所有十进制数字(例如,正常的字符串形式,而不是科学计数法),并且 该键的值在被强制为数字时为<= 2 ^ 32-2(即4,294,967,294)。这个数字从哪里来?它是规范中数组索引定义的一部分。其他数字(非整数,负数,大于2 ^ 32-2的数字)不是数组索引。它的2 ^ 32的理由- 2是使得大于2 ^ 32下一个最大的索引值- 1,这是一个数组的最大值length可以有。(例如,数组的长度适合于32位无符号整数。)(向RobG表示支持,在我的博客文章的评论中指出我先前的测试不太正确。) 当然,您不会在内联代码中执行此操作。您将编写一个实用程序函数。也许: 4.使用for-of(隐式使用迭代器)(ES2015 +) ES2015将迭代器添加到JavaScript。使用迭代器最简单的方法是new for-of语句。看起来像这样: const a = ["a", "b", "c"]; for (const val of a) { console.log(val); } 在幕后,它从数组中获取一个迭代器并循环遍历,从而从中获取值。这没有使用for-inhas 的问题,因为它使用了由对象(数组)定义的迭代器,并且数组定义了其迭代器遍历其条目(而不是其属性)。与for-inES5 不同,访问条目的顺序是其索引的数字顺序。 5.明确使用迭代器(ES2015 +) 有时,您可能想显式使用迭代器。您也可以这样做,尽管它比笨拙得多for-of。看起来像这样: const a = ["a", "b", "c"]; const it = a.values(); let entry; while (!(entry = it.next()).done) { console.log(entry.value); } 迭代器是与规范中的迭代器定义匹配的对象。每次调用时,其next方法都会返回一个新的结果对象。结果对象具有属性,done告诉我们是否完成操作,以及一个value具有该迭代值的属性。(done如果是false,value则为可选,如果是,则为可选undefined。) 的含义value取决于迭代器;数组至少支持三个返回迭代器的函数: values():这是我上面使用的那个。它返回迭代,其中每个value是用于该迭代阵列条目("a","b",和"c"在实施例更早)。 keys():返回一个迭代器,每个迭代器value都是该迭代的关键(因此,对于我们a上面的代码,将是"0",然后是"1",然后是"2")。 entries():返回一个迭代器,其中每个迭代器value都是[key, value]该迭代形式的数组。 对于类似数组的对象 除了真正的数组之外,还有一些类数组对象,它们具有一个length或多个具有数字名称的属性:NodeList实例,arguments对象等。我们如何遍历它们的内容? 对数组使用上面的任何选项 上面的至少一些(可能是大多数甚至全部)数组方法经常同样适用于类似数组的对象: 使用forEach及相关(ES5 +) 上的各种功能Array.prototype是“有意通用的”,通常可以通过Function#call或在类似数组的对象上使用Function#apply。(在此答案的末尾,请参阅警告,以了解主机提供的对象,但这是一个罕见的问题。) 假设您要forEach在Node的childNodes属性上使用。您可以这样做: Array.prototype.forEach.call(node.childNodes, function(child) { // Do something with `child` }); 如果要执行很多操作,则可能需要将函数引用的副本复制到变量中以供重用,例如: // (This is all presumably in some scoping function) var forEach = Array.prototype.forEach; // Then later... forEach.call(node.childNodes, function(child) { // Do something with `child` }); 使用一个简单的for循环 显然,一个简单的for循环适用于类似数组的对象。 正确使用for-in for-in具有与数组相同的保护措施,也应与类似数组的对象一起使用;上面#1中由主机提供的对象的警告可能适用。 使用for-of(隐式使用迭代器)(ES2015 +) for-of将使用对象提供的迭代器(如果有);我们将不得不看一下它如何与各种类似数组的对象一起运行,尤其是主机提供的对象。例如,NodeListfrom 的规范querySelectorAll已更新以支持迭代。HTMLCollectionfrom 的规格getElementsByTagName不是。 明确使用迭代器(ES2015 +) 参见#4,我们必须看看迭代器如何发挥作用。 创建一个真实的数组 其他时候,您可能希望将类似数组的对象转换为真正的数组。做到这一点非常容易: 使用slice数组的方法 我们可以使用slice数组的方法,就像上面提到的其他方法一样,它是“故意通用的”,因此可以与类似数组的对象一起使用,如下所示: var trueArray = Array.prototype.slice.call(arrayLikeObject); 因此,例如,如果我们要将a NodeList转换为真实数组,则可以执行以下操作: var divs = Array.prototype.slice.call(document.querySelectorAll("div")); 请参阅下面的警告,了解主机提供的对象。特别要注意的是,这将在IE8及更早版本中失败,这不允许您this像这样使用主机提供的对象。 使用传播语法(...) 还可以将ES2015的扩展语法与支持此功能的JavaScript引擎一起使用: var trueArray = [...iterableObject]; 因此,例如,如果我们想将a NodeList转换为真正的数组,使用扩展语法,这将变得非常简洁: var divs = [...document.querySelectorAll("div")]; 使用Array.from (规格) | (MDN) Array.from(ES2015 +,但很容易填充),从类似数组的对象创建数组,可以选择先将条目通过映射函数传递。所以: var divs = Array.from(document.querySelectorAll("div")); 或者,如果您想获取具有给定类的元素的标记名称的数组,则可以使用映射函数: // Arrow function (ES2015): var divs = Array.from(document.querySelectorAll(".some-class"), element => element.tagName); // Standard function (since `Array.from` can be shimmed): var divs = Array.from(document.querySelectorAll(".some-class"), function(element) { return element.tagName; }); 警告主机提供的对象 如果您将Array.prototype函数与主机提供的类似数组的对象一起使用(DOM列表和浏览器而非JavaScript引擎提供的其他内容),则需要确保在目标环境中进行测试,以确保主机提供的对象行为正常。大多数(现在)确实表现正常,但是测试很重要。原因是Array.prototype您可能要使用的大多数方法都依赖于主机提供的对象,该对象为抽象[[HasProperty]]操作提供了诚实的答案。在撰写本文时,浏览器在这方面做得很好,但是5.1规范确实允许由主机提供的对象可能不诚实。在§8.6.2中,该部分开头附近的大表下方的几段中),其中表示: 除非另有说明,否则宿主对象可以以任何方式实现这些内部方法。例如,一种可能性是,[[Get]]和[[Put]]对特定宿主对象确实读取与存储的属性值但[[HasProperty]]总是产生假。 (我在ES2015规范中找不到等效的用法,但情况肯定仍然如此。)同样,在撰写本文时,现代浏览器中的主机提供的类似数组的对象(NodeList例如,实例)确实可以处理[[HasProperty]]正确,但是测试很重要。) 问题来源于stack overflow
保持可爱mmm 2020-01-08 11:20:24 0 浏览量 回答数 0

回答

本人学习数据结构时看到的不错的总结,共享一下了 文件有一组记录组成,记录有若干数据项组成,唯一标识记录的数据项称关键字; 排序是将文件按关键字的递增(减)顺序排列; 排序文件中有相同的关键字时,若排序后相对次序保持不变的称稳定排序,否则称不稳定排序; 在排序过程中,文件放在内存中处理不涉及数据的内、外存交换的称内部排序,反之称外部排序; 排序算法的基本操作:1)比较关键字的大小;2)改变指向记录的指针或移动记录本身。 评价排序方法的标准:1)执行时间;2)所需辅助空间,辅助空间为O(1)称就地排序;另要注意算法的复杂程度。 若关键字类型没有比较运算符,可事先定义宏或函数表示比较运算。 8.2插入排序 8.2.1直接插入排序 实现过程: void insertsort(seqlist R) { int i, j; for(i=2;i<=n;i++) if(R[i].key< R[i-1].key{ R[0]=R[i];j=i-1; do{R[j+1]=R[j];j--;} while(R[0].key R[j+1]=R[0]; } } 复制代码 算法中引入监视哨R[0]的作用是:1)保存 R[i] 复制代码 的副本;2)简化边界条件,防止循环下标越界。 关键字比较次数最大为(n+2)(n-1)/2;记录移动次数最大为(n+4)(n-1)/2; 算法的最好时间是O(n);最坏时间是O(n^2);平均时间是O(n^2);是一种就地的稳定的排序; 8.2.2希尔排序 实现过程:是将直接插入排序的间隔变为d。d的取值要注意:1)最后一次必为1;2)避免d值互为倍数; 关键字比较次数最大为n^1.25;记录移动次数最大为1.6n^1.25; 算法的平均时间是O(n^1.25);是一种就地的不稳定的排序; 8.3交换排序 8.3.1冒泡排序 实现过程:从下到上相邻两个比较,按小在上原则扫描一次,确定最小值,重复n-1次。 关键字比较次数最小为n-1、最大为n(n-1)/2;记录移动次数最小为0,最大为3n(n-1)/2; 算法的最好时间是O(n);最坏时间是O(n^2);平均时间是O(n^2);是一种就地的稳定的排序; 8.3.2快速排序 实现过程:将第一个值作为基准,设置i,j指针交替从两头与基准比较,有交换后,交换j,i。i=j时确定基准,并以其为界限将序列分为两段。重复以上步骤。 关键字比较次数最好为nlog2n+nC(1)、最坏为n(n-1)/2; 算法的最好时间是O(nlog2n);最坏时间是O(n^2);平均时间是O(nlog2n);辅助空间为O(log2n);是一种不稳定排序; 8.4选择排序 8.4.1直接选择排序 实现过程:选择序列中最小的插入第一位,在剩余的序列中重复上一步,共重复n-1次。 关键字比较次数为n(n-1)/2;记录移动次数最小为0,最大为3(n-1); 算法的最好时间是O(n^2);最坏时间是O(n^2);平均时间是O(n^2);是一种就地的不稳定的排序; 8.4.2堆排序 实现过程:把序列按层次填入完全二叉树,调整位置使双亲大于或小于孩子,建立初始大根或小根堆,调整树根与最后一个叶子的位置,排除该叶子重新调整位置。 算法的最好时间是O(nlog2n);最坏时间是O(nlog2n);平均时间是O(nlog2n);是一种就地的不稳定排序; 8.5归并排序 实现过程:将初始序列分为2个一组,最后单数轮空,对每一组排序后作为一个单元,对2个单元排序,直到结束。 算法的最好时间是O(nlog2n);最坏时间是O(nlog2n);平均时间是O(nlog2n);辅助空间为O(n);是一种稳定排序; 8.6分配排序 8.6.1箱排序 实现过程:按关键字的取值范围确定箱子的个数,将序列按关键字放入箱中,输出非空箱的关键字。 在桶内分配和收集,及对各桶进行插入排序的时间为O(n),算法的期望时间是O(n),最坏时间是O(n^2)。 8.6.2基数排序 实现过程:按基数设置箱子,对关键字从低位到高位依次进行箱排序。 算法的最好时间是O(d*n+d*rd);最坏时间是O(d*n+d*rd);平均时间是O(d*n+d*rd);辅助空间O(n+rd);是一种稳定排序; 8.7各种内部排序方法的比较和选择 按平均时间复杂度分为: 1) 平方阶排序:直接插入、直接选择、冒泡排序; 2) 线性对数阶:快速排序、堆排序、归并排序; 3) 指数阶:希尔排序; 4) 线性阶:箱排序、基数排序。 选择合适排序方法的因素:1)待排序的记录数;2)记录的大小;3)关键字的结构和初始状态;4)对稳定性的要求;5)语言工具的条件;6)存储结构;7)时间和辅助空间复杂度。 结论: 1) 若规模较小可采用直接插入或直接选择排序; 2) 若文件初始状态基本有序可采用直接插入、冒泡或随机快速排序; 3) 若规模较大可采用快速排序、堆排序或归并排序; 4) 任何借助于比较的排序,至少需要O(nlog2n)的时间,箱排序和基数排序只适用于有明显结构特征的关键字; 5) 有的语言没有提供指针及递归,使归并、快速、基数排序算法复杂; 6) 记录规模较大时为避免大量移动记录可用链表作为存储结构,如插入、归并、基数排序,但快速、堆排序在链表上难以实现,可提取关键字建立索引表,然后对索引表排序。 附二: 第八章排序 ************************************************************************************* 记录中可用某一项来标识一个记录,则称为关键字项,该数据项的值称为关键字。 排序是使文件中的记录按关键字递增(或递减)次序排列起来。·基本操作:比较关键字大小;改变指向记录的指针或移动记录。 ·存储结构:顺序结构、链表结构、索引结构。 经过排序后这些具有相同关键字的记录之间的相对次序保持不变,则称这种排序方法是稳定的,否则排序算法是不稳定的。 排序过程中不涉及数据的内、外存交换则称之为"内部排序"(内排序),反之,若存在数据的内外存交换,则称之为外排序。 内部排序方法可分五类:插入排序、选择排序、交换排序、归并排序和分配排序。 评价排序算法好坏的标准主要有两条:执行时间和所需的辅助空间,另外算法的复杂程序也是要考虑的一个因素。 ************************************************************************************* 插入排序:·直接插入排序: ·逐个向前插入到合适位置。 ·哨兵(监视哨)有两个作用: ·作为临变量存放 R[i] 复制代码 ·是在查找循环中用来监视下标变量j是否越界。 ·直接插入排序是就地的稳定排序。时间复杂度为O(n^2),比较次数为(n+2)(n-1)/2;移动次数为(n+4)(n-1)/2; ·希尔排序: ·等间隔的数据比较并按要求顺序排列,最后间隔为1。 ·希尔排序是就地的不稳定排序。时间复杂度为O(n^1.25),比较次数为(n^1.25);移动次数为(1.6n^1.25); 交换排序:·冒泡排序:·自下向上确定最轻的一个。·自上向下确定最重的一个。·自下向上确定最轻的一个,后自上向下确定最重的一个。 ·冒泡排序是就地的稳定排序。时间复杂度为O(n^2),比较次数为n(n-1)/2;移动次数为3n(n-1)/2; ·快速排序:·以第一个元素为参考基准,设定、动两个指针,发生交换后指针交换位置,直到指针重合。重复直到排序完成。 ·快速排序是非就地的不稳定排序。时间复杂度为O(nlog2n),比较次数为n(n-1)/2; 选择排序:·直接选择排序: ·选择最小的放在比较区前。 ·直接选择排序就地的不稳定排序。时间复杂度为O(n^2)。比较次数为n(n-1)/2; ·堆排序 ·建堆:按层次将数据填入完全二叉树,从int(n/2)处向前逐个调整位置。 ·然后将树根与最后一个叶子交换值并断开与树的连接并重建堆,直到全断开。 ·堆排序是就地不稳定的排序,时间复杂度为O(nlog2n),不适宜于记录数较少的文件。。 归并排序: ·先两个一组排序,形成(n+1)/2组,再将两组并一组,直到剩下一组为止。 ·归并排序是非就地稳定排序,时间复杂度是O(nlog2n), 分配排序:·箱排序: ·按关键字的取值范围确定箱子数,按关键字投入箱子,链接所有非空箱。 ·箱排序的平均时间复杂度是线性的O(n). ·基数排序:·从低位到高位依次对关键字进行箱排序。 ·基数排序是非就稳定的排序,时间复杂度是O(d*n+d*rd)。 各种排序方法的比较和选择: ·.待排序的记录数目n;n较大的要用时间复杂度为O(nlog2n)的排序方法; ·记录的大小(规模);记录大最好用链表作为存储结构,而快速排序和堆排序在链表上难于实现; ·关键字的结构及其初始状态; ·对稳定性的要求; ·语言工具的条件; ·存储结构; ·时间和辅助空间复杂度。 排序(sort)或分类 所谓排序,就是要整理文件中的记录,使之按关键字递增(或递减)次序排列起来。其确切定义如下: 输入:n个记录R1,R2,…,Rn,其相应的关键字分别为K1,K2,…,Kn。 输出:Ril,Ri2,…,Rin,使得Ki1≤Ki2≤…≤Kin。(或Ki1≥Ki2≥…≥Kin)。 1.被排序对象--文件 被排序的对象--文件由一组记录组成。 记录则由若干个数据项(或域)组成。其中有一项可用来标识一个记录,称为关键字项。该数据项的值称为关键字(Key)。 注意: 在不易产生混淆时,将关键字项简称为关键字。 2.排序运算的依据--关键字 用来作排序运算依据的关键字,可以是数字类型,也可以是字符类型。 关键字的选取应根据问题的要求而定。 【例】在高考成绩统计中将每个考生作为一个记录。每条记录包含准考证号、姓名、各科的分数和总分数等项内容。若要惟一地标识一个考生的记录,则必须用"准考证号"作为关键字。若要按照考生的总分数排名次,则需用"总分数"作为关键字。 排序的稳定性 当待排序记录的关键字均不相同时,排序结果是惟一的,否则排序结果不唯一。 在待排序的文件中,若存在多个关键字相同的记录,经过排序后这些具有相同关键字的记录之间的相对次序保持不变,该排序方法是稳定的;若具有相同关键字的记录之间的相对次序发生变化,则称这种排序方法是不稳定的。 注意: 排序算法的稳定性是针对所有输入实例而言的。即在所有可能的输入实例中,只要有一个实例使得算法不满足稳定性要求,则该排序算法就是不稳定的。 排序方法的分类 1.按是否涉及数据的内、外存交换分 在排序过程中,若整个文件都是放在内存中处理,排序时不涉及数据的内、外存交换,则称之为内部排序(简称内排序);反之,若排序过程中要进行数据的内、外存交换,则称之为外部排序。 注意: ① 内排序适用于记录个数不很多的小文件 ② 外排序则适用于记录个数太多,不能一次将其全部记录放人内存的大文件。 2.按策略划分内部排序方法 可以分为五类:插入排序、选择排序、交换排序、归并排序和分配排序。 排序算法分析 1.排序算法的基本操作 大多数排序算法都有两个基本的操作: (1) 比较两个关键字的大小; (2) 改变指向记录的指针或移动记录本身。 注意: 第(2)种基本操作的实现依赖于待排序记录的存储方式。 2.待排文件的常用存储方式 (1) 以顺序表(或直接用向量)作为存储结构 排序过程:对记录本身进行物理重排(即通过关键字之间的比较判定,将记录移到合适的位置) (2) 以链表作为存储结构 排序过程:无须移动记录,仅需修改指针。通常将这类排序称为链表(或链式)排序; (3) 用顺序的方式存储待排序的记录,但同时建立一个辅助表(如包括关键字和指向记录位置的指针组成的索引表) 排序过程:只需对辅助表的表目进行物理重排(即只移动辅助表的表目,而不移动记录本身)。适用于难于在链表上实现,仍需避免排序过程中移动记录的排序方法。 3.排序算法性能评价 (1) 评价排序算法好坏的标准 评价排序算法好坏的标准主要有两条: ① 执行时间和所需的辅助空间 ② 算法本身的复杂程度 (2) 排序算法的空间复杂度 若排序算法所需的辅助空间并不依赖于问题的规模n,即辅助空间是O(1),则称之为就地排序(In-PlaceSou)。 非就地排序一般要求的辅助空间为O(n)。 (3) 排序算法的时间开销 大多数排序算法的时间开销主要是关键字之间的比较和记录的移动。有的排序算法其执行时间不仅依赖于问题的规模,还取决于输入实例中数据的状态。
马铭芳 2019-12-02 01:19:07 0 浏览量 回答数 0

云产品推荐

上海奇点人才服务相关的云产品 小程序定制 上海微企信息技术相关的云产品 国内短信套餐包 ECS云服务器安全配置相关的云产品 开发者问答 阿里云建站 自然场景识别相关的云产品 万网 小程序开发制作 视频内容分析 视频集锦 代理记账服务 阿里云AIoT