• 关于

    JavaScript中变量的几个相关函数

    的搜索结果

回答

JavaScript (ECMAScript) :JavaScript 是脚本语言。JavaScript和ECMAScript通常被人用来表达相同的含义,但是JavaScript并不是这么一点含义,它是由ECMAScript 核心. DOM 文档对象模型. BOM 浏览器对象模型 这三部分组成。浏览器会在读取代码时,逐行地执行脚本代码。而对于传统编程来说,会在执行前对所有代码进行编译。 组成部分包括语法,类型,语句,关键字,保留字,操作符,对象。 其中,文档对象模型(DOM , Document Object Model)是针对XML但是经过拓展用于HTML的应用程序编程接口。DOM把整个页面映射为一个多层节点结构,开发人员借助DOM Api对节点进行操作。可以通过浏览器F12进入开发者模式,查看层级关系。当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。HTML DOM 模型被构造为对象的树。通过可编程的对象模型,JavaScript 获得了足够的能力来创建动态的 HTML。 功能大致上: · JavaScript 能够改变页面中的所有 HTML 元素 · JavaScript 能够改变页面中的所有 HTML 属性 · JavaScript 能够改变页面中的所有 CSS 样式 · JavaScript 能够对页面中的所有事件做出反应 同时,浏览器对象模型(Browser Object Model)使用BOM控制浏览器显示页面意外的部分。 javaScript脚本加载方式 1 通过在网页中加入标记JavaScript的开始和结束,将JavaScript代码放到之间 2 也可以引入一个外部的JavaScript文件,这个JavaScript文件一般以.js作为扩展名 3 原则上,放在之间。但视情况可以放在网页的任何部分 4 一个页面可以有几个,不同部分的方法和变量,可以共享。 javaScript语句开发 (1)对大小写敏感 (2)自动忽略多余的空格 (3)在文本字符串中使用反斜杠对代码行进行换行 (4)单行注释(//)多行注释(/* */) JavaScript 是一个程序语言。语法规则定义了语言结构。 JavaScript 字面量 在编程语言中,一般固定值称为字面量,如 3.14。 数字(Number)字面量 可以是整数或者是小数,或者是科学计数(e)。 字符串(String)字面量 可以使用单引号或双引号: 数组(Array)字面量 定义一个数组: [40, 100, 1, 5, 25, 10] 对象(Object)字面量 定义一个对象: {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"} 函数(Function)字面量 定义一个函数: function myFunction(a, b) { return a * b;} **JavaScript 变量 ** 在编程语言中,变量用于存储数据值。 JavaScript 使用关键字 var 来定义变量, 使用等号来为变量赋值: var x, length x = 5 length = 6 JavaScript 操作符 JavaScript使用 算术运算符 来计算值: (5 + 6) * 10 JavaScript使用赋值运算符给变量赋值: x = 5 y = 6 z = (x + y) * 10 JavaScript语言有多种类型的运算符: JavaScript 语句 在 HTML 中,JavaScript 语句向浏览器发出的命令。 语句是用分号分隔: x = 5 + 6; y = x * 10; JavaScript 关键字 JavaScript 关键字用于标识要执行的操作。 和其他任何编程语言一样,JavaScript 保留了一些关键字为自己所用。 var 关键字告诉浏览器创建一个新的变量: var x = 5 + 6; var y = x * 10; JavaScript 同样保留了一些关键字,这些关键字在当前的语言版本中并没有使用,但在以后 JavaScript 扩展中会用到。 以下是 JavaScript 中最重要的保留字(按字母顺序): JavaScript 注释 不是所有的 JavaScript 语句都是"命令"。双斜杠 // 后的内容将会被浏览器忽略: // 我不会执行 JavaScript 数据类型 JavaScript 有多种数据类型:数字,字符串,数组,对象等等: var length = 16; // Number 通过数字字面量赋值 var points = x * 10; // Number 通过表达式字面量赋值 var lastName = "Johnson"; // String 通过字符串字面量赋值 var cars = ["Saab", "Volvo", "BMW"]; // Array 通过数组字面量赋值 var person = {firstName:"John", lastName:"Doe"}; // Object 通过对象字面量赋值 数据类型的概念 编程语言中,数据类型是一个非常重要的内容。 为了可以操作变量,了解数据类型的概念非常重要。 如果没有使用数据类型,以下实例将无法执行: 16 + "Volvo" 16 加上 "Volvo" 是如何计算呢? 以上会产生一个错误还是输出以下结果呢? "16Volvo" 你可以在浏览器尝试执行以上代码查看效果。 在接下来的章节中你将学到更多关于数据类型的知识。 JavaScript 函数 JavaScript 语句可以写在函数内,函数可以重复引用: 引用一个函数 = 调用函数(执行函数内的语句)。 function myFunction(a, b) { return a * b; // 返回 a 乘以 b 的结果 } JavaScript 字母大小写 JavaScript 对大小写是敏感的。 当编写 JavaScript 语句时,请留意是否关闭大小写切换键。 函数 getElementById 与 getElementbyID 是不同的。 同样,变量 myVariable 与 MyVariable 也是不同的。 JavaScript 字符集 JavaScript 使用 Unicode 字符集。 Unicode 覆盖了所有的字符,包含标点等字符。 三 推荐学习网站 JS具体的语法内容还有很多,可以参考官方API或者学习网站完成掌握,简单易学,推荐网站 菜鸟教程:https://www.runoob.com/js/js-tutorial.html w3cschool:https://www.w3school.com.cn/js/index.asp 四 推荐学习书籍 引用自 https://www.cnblogs.com/xhqq/p/7561384.html 个人觉得不错的,没事可以翻翻的。书籍如下: 《javascript设计模式》,张容铭写的,可能不太适合零基础的,是非常不错的进阶书籍。 《javascript面向对象编程指南》,风格轻松易懂,比较适合初学者,原型那块儿讲得透彻,12种继承方式呢。 《js权威指南》、《js高级程序设计》,这两本书经典是经典,但是太厚,适合把其中任意一章都当成一本书来读。洋洋洒洒,很难一口气看完。比较适合当做参考书。 《你不知道的javascript》狙击js核心细节,闭包、原型、this讲得都还清楚。 《js设计模式与开发实践》js设计模式也是要学的,此书把js的设计模式讲得非常清晰,一点不晦涩,看起来没多少难度。 《正则指引》,分析源码时,如果正则表达式不懂,没法进行下去的。此书相对来说讲得比较清晰。 《基于MVC的JavaScript Web富应用开发》,看完后,基本能写出自己的mvc框架了。是本好书。 《javascript函数式编程》,js是一门函数式语言,此书是函数式编程一个入门,函数是一等公民那是非常重要的。 《js忍者秘籍》,jq作者写的,没有传说中的那么难读,话说就算你看完并理解所有知识点,也不会达到世界高手级别的。因为你还没有做到随心所欲。 《javascript框架设计》,如果初看此书,会觉得此书有罗列代码之嫌。在我看来,此书讲究的是框架的全局观。以上书籍是我认为是成就高手之路上必须看的,也需要反复看。 css相关的书籍,说实话我看得比较少,总共有六七本吧。有两本必须推荐一下: 《css权威指南》,css基础知识点那是讲得非常清楚的。什么层叠优先级、line-height啥的。不是随便一本书都敢叫“权威指南”的。 《css揭秘》,此书我也是不断的看,此书才不屑于全面讲css3各属性呢。css规范文档能讲的,它只会讲你最不在意的。此书解决的47问题,解决思路和解决方案同等重要,很有启发性。以上各书你都可以不买,至少买本此书吧

问问小秘 2020-03-03 09:32:57 0 浏览量 回答数 0

问题

最大限度利用 JavaScript 和 Ajax 性能:报错

kun坤 2020-06-05 22:56:50 0 浏览量 回答数 1

问题

【分享】WeX5的正确打开方式(1)

小太阳1号 2019-12-01 21:15:23 6117 浏览量 回答数 0

阿里云高校特惠,助力学生创业梦!0元体验,快速入门云计算!

学生动手场景应用,快速了解并掌握云服务器的各种新奇玩法!

回答

1、轻量级 JQuery 非常轻巧,采用 Dean Edwards 编写的 Packer 压缩后,大小不到 30KB,如果使用 Min 版并且在服务器端启用 Gzip 压缩后,大小只有 18KB。 gzip: 每天一个 linux 命令(32):gzip 减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间。gzip 是在 Linux 系统中经常使用的一个对文件进行压缩和解压缩的命令,既方便又好用。gzip 不仅可以用来压缩大的、较少使用的文件以节省磁盘空间,还可以和 tar 命令一起构成 Linux 操作系统中比较流行的压缩文件格式。据统计,gzip 命令对文本文件有 60%~ 70%的压缩率。 2、强大的选择器 JQuery 允许开发者使用从 CSS1 到 CSS3 几乎所有的选择器,以及 JQuery 独创的高级而且复杂的选择器,另外还可以加入插件使其支持 XPath 选择器,甚至开发者可以编写属于自己的选择器。由于 JQuery 支持选择器这一特性,因此有一定 CSS 经验的开发人员可以很容易的切入到 JQuery 的学习中来。 XPath: XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。 XPath 是 W3C XSLT 标准的主要元素,并且 XQuery 和 XPointer 都构建于 XPath 表达之上。 因此,对 XPath 的理解是很多高级 XML 应用的基础。 3、出色的 DOM 操作的封装 JQuery 封装了大量常用的 DOM 操作,使开发者在编写 DOM 操作相关程序的时候能够得心应手。JQuery 轻松地完成各种原本非常复杂的操作,让 JavaScript 新手也能写出出色的程序。 4、可靠的事件处理机制 JQuery 的事件处理机制吸收了 JavaScript 专家 Dean Edwards 编写的事件处理函数的精华,是的 JQuery 在处理事件绑定的时候相当可靠。在预留退路、循序渐进以及非入侵式编程思想方面,JQuery 也做得非常不错。 5、完善的 Ajax JQuery 将所有的 Ajax 操作封装到一个函数$.ajax()里,使得开发者处理 Ajax 的时候能够专心处理业务逻辑而无需关心复杂的浏览器兼容性和 XMLHttpRequest 对象的创建和使用的问题。 6、不污染顶级变量 JQuery 只建立一个名为 JQuery 的对象,其所有的函数方法都在这个对象之下。其别名$也可以随时交流控制权,绝对不会污染其他的对象。该特性是 JQuery 可以与其他 JavaScript 库共存,在项目中放心地引用而不需要考虑到后期的冲突。 7、出色的浏览器兼容性 作为一个流行的 JavaScript 库,浏览器的兼容性是必须具备的条件之一。JQuery 能够在 IE6.0+,FF 2+,Safari2.+和 Opera9.0+下正常运行。JQuery 同时修复了一些浏览器之间的的差异,使开发者不必在开展项目前建立浏览器兼容库。 8、链式操作方式 JQuery 中最有特色的莫过于它的链式操作方式——即对发生在同一个 JQuery 对象上的一组动作,可以直接接连写无需要重复获取对象。这一特点使得 JQuery 的代码无比优雅。 9.隐式迭代 当用 JQuery 找到带有“.myClass”类的全部元素,然后隐藏他们时。无需循环遍历每一个返回的元素。相反,JQuery 里的方法都被设计成自动操作的对象集合,而不是单独的对象,这使得大量的循环结构变得不再必要,从而大幅度地减少代码量。 10、行为层与结构层的分离 开发者可以使用选择器选中元素,然后直接给元素添加事件。这种将行为层与结构层完全分离的思想,可以使 JQuery 开发人员和 HTML 或其他页面开发人员各司其职,摆脱过去开发冲突或个人单干的开发模式。同时,后期维护也非常方便,不需要在 HTML 代码中寻找某些函数和重复修改 HTML 代码。 11、丰富的插件支持 JQuery 的易扩展性,吸引了来自全球开发者来编写 JQuery 的扩展插件。目前已经有超过几百种官方插件支持,而且还不断有新插件面试。 12、完善的文档 JQuery 的文档非常丰富,现阶段多位英文文档,中文文档相对较少。很多热爱 JQuery 的团队都在努力完善 JQuery 中文文档,例如 JQuery 的中文 API。 13、开源 JQuery 是一个开源的产品,任何人都可以自由地使用并提出修改意见。

茶什i 2019-12-02 03:21:37 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

回答

浅谈Flutter框架原理及其生态圈 Flutter的锋芒 跨平台高性能的渲染引擎逐渐成为移动端、大前端领域的一个热点,作为其中的明星框架Flutter,经过近几年来的迅速发展,由极大的可能成为下一代跨端终端解决方案。自从2017 年 5 月,谷歌公司发布的了 Alpha 版本的 Flutter; 2018 年底 Flutter Live 发布的 1.0 版本;2019年7月发布1.5版本,截止今日(2020年2月)已经发布了v1.14.6 Beta版本。 在Flutter诞生之前,已经有许多跨平台UI框架的方案如Cordova、ReactNative、weex、uni-app、Hippy等,常见的需要处理兼容的终端平台也包括android、ios、web、Iot等,但是在大前端的浪潮下,对于企业和开发者来说开发效率和使用体验都十分重要,传统的做法莫过于分不同的团队开发不同的终端项目,如果还要继续向其他平台,拓展的话,我们需要付出的成本和时间将成倍增长。正因为如此,在这样的背景下,Flutter等跨端框架的兴起,从本质上讲,帮助开发者增加业务代码的复用率,减少因为要适配多个平台带来的工作量,从而降低开发成本、提高开发效率。 纵观已有的跨端方案,可以分为三类:Web 容器、泛 Web 容器、自绘引擎框架。 基于web容器即基于浏览器的跨平台也做得越来越好,自然管线也越来越短,与native的一些技术手段来实现性能上的相互补充。比如Egret、Cocos、Laya这些游戏引擎,它们在跨平台方面的做法多以Typescript编写,在iOS和安卓平台的各种浏览器中轻松的运行HTML5游戏,并在不同平台浏览器里提供近乎一致的用户体验,比如Egret还会提供高效的 JS-C Binding 编译机制,以满足游戏编译为原生格式的需求,不过大多数HTML游戏引擎也属于web容器这个范畴内。web容器框架也有一个明显的致命(在对体验&性能有较高要求的情况下)的缺点,那就是WebView的渲染效率和JavaScript执行性能太差。再加上Android各个系统版本和设备厂商的定制,很难保证所在所有设备上都能提供一致的体验。 泛 Web 容器框架比如ReactNative和Weex,即上层通过面向前端友好的UI,下层通过native的渲染形式,虽然同样使用类HTML+JS的UI构建逻辑,但是最终会生成对应的自定义原生控件,以充分利用原生控件相对于WebView的较高的绘制效率,同时H5与native相互补充来达到更好的用户体验,这也是一种很好的解决方案。缺陷也很明显,随着系统版本变化和API的变化,开发者可能也需要处理不同平台的差异,甚至有些特性只能在部分平台上实现,这样框架的跨平台特性就会大打折扣。 自绘引擎框架这里专指Flutter框架,从底层就承担跨端的任务和渲染方式,从目前来看,从技术的实现和方案的成熟度、产品的性能方面比较,Flutter有很大可能成为下一代主流跨平台框架。 Flutter与其他跨端框架的不同点之一就是自带渲染引擎,Flutter渲染引擎依靠跨平台的Skia图形库来实现,Skia引擎会将使用Dart语言构建的抽象的视图结构数据加工成GPU数据,交由 OpenGL 最终提供给 GPU 渲染,至此完成渲染闭环,因此可以在最大程度上保证一款应用在不同平台、不同设备上的体验一致性。 而开发语言选用的是同时支持 JIT和 AOT的 Dart语言,Dart本身提供了三种运行方式,应对web环境,用Dart2js编译成JavaScript代码,运行在常规浏览器中;使用DartVM直接在命令行中运行Dart代码;AOT方式编译成机器码,例如Flutter App框架。而且Dart 避免了抢占式调度和共享内存,可以在没有锁的情况下进行对象分配和垃圾回收,在性能方面表现相当不错,不仅保证了开发效率,代码性能和用户体验也更卓越。因此,Flutter在各类跨平台移动开发方案中脱颖而出。同时在去年2019的Google IO大会上,备受关注的Fuchsia系统虽然并没有发布,但是宣布了 Flutter除了支持开发 Android 和 iOS 程序之外,现在还支持开发Web程序了,在 I/O 大会上,谷歌发布了 Web 版 Flutter 的首个技术预览版,宣布 Flutter 将为包括 Google Home Hub 在内的 Google Smart Display 平台提供技术支持,并迈出利用 Chrome 操作系统支持桌面级应用的第一步。 很多JS开发者会思考Google Flutter团队至于为啥选择Dart而不是JS,其实Google 公司给出的原因很简单也很直接:Dart 语言开发组就在隔壁,对于 Flutter 需要的一些语言新特性,能够快速在语法层面落地实现;而如果选择了 JavaScript,就必须经过各种委员会(TC39等)和浏览器提供商漫长的决议。 Flutter绘制原理 在计算机系统中,图像的显示需要 CPU、GPU 和显示器一起配合完成:CPU 负责图像数据计算,GPU 负责图像数据渲染,而显示器则负责最终图像显示。 CPU 把计算好的、需要显示的内容交给 GPU,由 GPU 完成渲染后放入帧缓冲区,随后视频控制器根据垂直同步信号(VSync)以每秒 60 次的速度,从帧缓冲区读取帧数据交由显示器完成图像显示。 操作系统在呈现图像时遵循了这种机制,而 Flutter 作为跨平台开发框架也采用了这种底层方案。下面有一张更为详尽的示意图来解释 Flutter 的绘制原理。可以看到,Flutter 关注如何尽可能快地在两个硬件时钟的 VSync 信号之间计算并合成视图数据,然后通过 Skia 交给 GPU 渲染:UI 线程使用 Dart 来构建视图结构数据,这些数据会在 GPU 线程进行图层合成,随后交给 Skia 引擎加工成 GPU 数据,而这些数据会通过 OpenGL 最终提供给 GPU 渲染。 Skia原理 Skia 是一款用由C++ 开发的2D 图像绘制引擎。在2005 年被 Google 公司收购后被广泛应用在 Android和其他等核心产品上,Skia 目前是Android 官方的图像渲染引擎,因此 Flutter Android SDK 无需内嵌 Skia 引擎就可以获得天然的 Skia 支持;而对于 iOS 平台来说,由于 Skia 是跨平台的,因此它作为 Flutter iOS 渲染引擎被嵌入到 Flutter 的 iOS SDK 中,替代了 iOS 闭源的 Core Graphics/Core Animation/Core Text,这也正是 Flutter iOS SDK 打包的 App 包体积比 Android 要大一些的原因。 底层渲染能力统一了,上层开发接口和功能体验也就随即统一了,开发者再也不用操心平台相关的渲染特性了。也就是说,Skia 保证了同一套代码调用在 Android 和 iOS 平台上的渲染效果是完全一致的。 Flutter架构 Framework底层是Flutter引擎,引擎主要负责图形绘制(Skia)、文字排版(libtxt)和提供Dart运行时,引擎全部使用C++实现,Framework层使我们可以用Dart语言调用引擎的强大能力。Flutter 架构采用分层设计,从下到上分为三层,依次为:Embedder、Engine、Framework。 Embedder 是操作系统适配层,实现了渲染 Surface 设置,线程设置,以及平台插件等平台相关特性的适配。从这里我们可以看到,Flutter 平台相关特性并不多,这就使得从框架层面保持跨端一致性的成本相对较低。 Engine 层主要包含 Skia、Dart 和 Text,实现了 Flutter 的渲染引擎、文字排版、事件处理和 Dart 运行时等功能。Skia 和 Text 为上层接口提供了调用底层渲染和排版的能力,Dart 则为 Flutter 提供了运行时调用 Dart 和渲染引擎的能力。而 Engine 层的作用,则是将它们组合起来,从它们生成的数据中实现视图渲染。 Framework 层则是一个用 Dart 实现的 UI SDK,包含了动画、图形绘制和手势识别等功能。为了在绘制控件等固定样式的图形时提供更直观、更方便的接口,Flutter 还基于这些基础能力,根据 Material 和 Cupertino 两种视觉设计风格封装了一套 UI 组件库,开发者可以直接使用这些组件库。 Flutter运行流程 页面中的各界面元素(Widget)以树的形式组织,即控件树。Flutter 通过控件树中的每个控件创建不同类型的渲染对象,组成渲染对象树。在Flutter界面渲染过程分为三个阶段:布局、绘制、合成,布局和绘制在Flutter框架中完成,合成则交由引擎负责。 Flutter 采用深度优先机制遍历渲染对象树,决定渲染对象树中各渲染对象在屏幕上的位置和尺寸。在布局过程中,渲染对象树中的每个渲染对象都会接收父对象的布局约束参数,决定自己的大小,然后父对象按照控件逻辑决定各个子对象的位置,最终完成布局过程。这里只需要注意一点,无论布局还是绘制,都是父子间的遍历关系:父Widget的布局需要依赖子Widget的布局结果;而绘制则反过来(子Widget需要盖在父Widget上),布局是后续遍历,绘制是前序遍历,他们都是深度优先遍历。 Flutter生命周期 可以看到,Flutter中State 的生命周期可以分为 3 个阶段:创建(插入视图树)、更新(在视图树中存在)、销毁(从视图树中移除)。接下来,我们一起看看每一个阶段的具体流程。 第一步创建 State 初始化时会依次执行 :构造方法 -> initState -> didChangeDependencies -> build,随后完成页面渲染。构造方法是 State 生命周期的起点,Flutter 会通过调用StatefulWidget.createState() 来创建一个 State。我们可以通过构造方法,来接收父 Widget 传递的初始化 UI 配置数据。这些配置数据,决定了 Widget 最初的呈现效果。 initState,会在 State 对象被插入视图树的时候调用。这个函数在 State 的生命周期中只会被调用一次,所以我们可以在这里做一些初始化工作,比如为状态变量设定默认值。 didChangeDependencies 则用来专门处理 State 对象依赖关系变化,会在 initState() 调用结束后,被 Flutter 调用。 build,作用是构建视图。经过以上步骤,Framework 认为 State 已经准备好了,于是调用 build。我们需要在这个函数中,根据父 Widget 传递过来的初始化配置数据,以及 State 的当前状态,创建一个 Widget 然后返回。 第二步更新 Widget 的状态更新,主要由个方法触发:setState、didchangeDependencies、didUpdateWidget。 setState:我们最熟悉的方法之一。当状态数据发生变化时,我们总是通过调用这个方法告诉 Flutter:“我这儿的数据变啦,请使用更新后的数据重建 UI!” didChangeDependencies:State 对象的依赖关系发生变化后,Flutter 会回调这个方法,随后触发组件构建。哪些情况下 State 对象的依赖关系会发生变化呢?典型的场景是,系统语言 Locale 或应用主题改变时,系统会通知 State 执行 didChangeDependencies 回调方法。 didUpdateWidget:当 Widget 的配置发生变化时,比如,父 Widget 触发重建(即父 Widget 的状态发生变化时),热重载时,系统会调用这个函数。一旦这三个方法被调用,Flutter 随后就会销毁老 Widget,并调用 build 方法重建 Widget。 第三步销毁 比如组件被移除,或是页面销毁的时候,系统会调用 deactivate 和 dispose 这两个方法,来移除或销毁组件。 Flutter生态圈及其常用框架 一项技术一个框架是否流行,最直观的体现就是它的生态圈是否活跃,下面列举了一些Flutter开发中常用的库工具。 参考文献 1、[Flutter原理与实践](https://tech.meituan.com/2018/08/09/waimai-flutter-practice.html) 少杰 2、[Flutter框架技术概览](https://flutter.dev/docs/resources/technical-overview) 3、[Flutter中文官网](https://pub.dartlang.org/flutter/) 4、[Flutter插件仓库](https://pub.dev/flutter/packages)

罗思雨 2020-02-27 11:47:50 0 浏览量 回答数 0

问题

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

小太阳1号 2019-12-01 21:25:48 4942 浏览量 回答数 3

问题

程序员报错QA大分享(1)

问问小秘 2020-06-18 15:46:14 8 浏览量 回答数 1
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 企业信息查询 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站 阿里云双十一主会场 阿里云双十一新人会场 1024程序员加油包 阿里云双十一拼团会场 场景化解决方案 阿里云双十一直播大厅