粉丝5.0万获赞22.5万

c 语言中重要的关键字有很多, static, const, extent 我们之前都讲过,还有一个在面试中出现的,频率也比较高。 register, register 翻译过来就是寄存器的意思,可以在定义变量的时候加在前面,我们把它称作寄存器变量。寄存器变量的作用在于提高程序的运行效率,我们经常会用到存储戒指,大概有这么几种,硬盘内存缓存。寄存器 越往上速度越快,当然价格也越高。运营程序的时候,计算机会把大部分的数据存放在内存中,然后 cpu 会从内存中读取需要的数据。虽然访问内存的速度比访问硬盘来的快,但是跟 cpu 的速度比起来还是慢了很多,于是 c 员就有了 regis 的关键字。 被 register 修饰的变量很有可能存放在计算器中,这样 cpu 就能直接从计算器中读取变量,提高程序的运行效率。 对于需要频繁访问的变量,可以把它声明成计算器变量,写个代码试试,随便一个否循环,循环一千万次,而作为循环变量会被频繁访问。先是不加 register, 变异的时候不优化,如果不加这个刚欧选项,有些变异器很有可能把这样的否循环当做废话优化掉 运行的时间大概是这样的,然后修改代码,在 id 前面加上 register, 再次便于运行,时间确实会缩短很多。 关于 register 关键字,有个经典的面试题,就是寄存器变量能不能做取地址操作。 c 元中的取地址操作取的是内存的地址变量,放在寄存器中不存在地址这一说法,如果强行取地址变异就会报错。 最后给大家留个问题,既然计存器变量能提高程序的运行速度,能不能把所有的变量都定义成计存器变量?这样做合不合适?如果你知道,欢迎在评论区交流。

很多人凭直觉认为,只要一个对象被声明为 const, 在 多现成环境下读取该对象就应该是安全的。这是一个常见却危险的误解。首先给出结论, const 与现成安全没有直接关系。 const 仅能保证一件事,通过当前接口,你无法修改这个对象,它约束的是程序员,而不是现成。 在多现成场景下,我们真正关心的核心问题有三个,是否存在数据竞争操作是否具备原子性,以及内存是否可见,而 const 对 这三个均无法保证。 举个简单例子,一个县城正在写入某个变量,同时另一个县城通过 cost 引用获取该变量,这段代码能正常翻译且看起来是安全的,因为它只做读取不做写入。但这恰恰是标准定义中典型的数据竞争场景,其行为是未定义的。 即便是在 cost 成员函数中,如果读取的是未同步的非原子性的成员变量,在多现成环境下仍可能出现问题,因为 cost 成员函数仅能保证 你无法通过。 this 指真修改成员变量,但其他现成完全可以通过非 const 成员函数修改这些变量。此外,读取操作本身也可能既不具备原子性,也不具备内存可见性。所以请记住, const 是 给程序员看的,现成安全是给 cpu 和内存模型看的。

大家好,这里是马学未来 c 加加编程技术的分享时间,今天继续给大家分享构造函数相关的内容。在进入正题之前,先回复网上一些朋友。针对上期视频中的疑问, 有朋友问 area 函数中的 cons 有 什么作用?一个函数使用 cons 关键字进行修饰,就表示这是一个常量成员函数,其作用是保证函数不修改对象状态。 具体到本程序代码中,在 area 函数体内,任何试图修改类成员变量位和 high 的 操作都会导致翻译错误, 这里我们来做一个 with 属性的复制操作,然后翻译一下,看到没有,这里报错了。这个错误提示信息说的很明白, rectangle 类下面的 with 属性是指读的, 这里说明一下。在我们的 area 函数中,虽然函数内部访问了 with 和 h, 但仅用于计算并返回值,未作修改,因此是符合函数定义的。我们在定义函数时,使用函数关键字进行修饰后, 就是明确向调用者声明该函数是只读的,不会影响对象内部状态,达到提高代码安全性与清晰度的作用。 接下来回到我们今天的主题构造函数上来。首先我们梳理一下整个程序的执行流程是怎样的。我们知道程序的执行是从 main 开始的,因此我们先来到 main 函数的内部, 这里先是创建类对象并传递参数五于三,类对象创建成功后,就会自动调用构造函数,这里的 w 等于五, h 等于三, 在执行函数体后为等于五, high 等于三,这样我们的两个私有属性就有值了。然后继续执行文中的代码,通过类对象 r 调用 area 方法, 此方法是返回 width 和 height 的 乘积,前面通过构造函数使得 width 等于五, height 等于三了,所以这里就返回了五乘三等于十五这个结果。这样一个流程走下来,我们就能准确知道程序是如何运行的。 接下来我们再将重心放到构造函数上面来,我们这个构造函数的功能是在构造函数体内进行私有成员的复制, 他的执行顺序有两步,先使成员位和 high 默认出式化。这里是指进入构造函数体之前,并一起自动对位和 high 进行默认出式化。 对于 in 的 类型,默认出式化就是什么都不做了,保持未定义的随机值,再使执行构造函数体复制,即在构造函数体内用参数 w 合理是给他们复制。 这样的传统模式在效率方面还是不够高效,这里跟大家分享,并强烈推荐使用成员出使花列表的方式来做。 语法是用一个冒号来衔接,后面跟属性与变量变量需要用小括号包裹住一个属性变量是一组,每组之间用逗号分隔,这样我们的成员出使花列表代码就写好了。 最后我们把这里的传餐纸改一下,改成九与七八,同时把被注视掉的这两行代码也删除掉。接下来我们先翻译走一波, 翻译结果来了,零错误,零警告,没有问题,赶紧让程序跑起来。嗯, 是我们期待的结果,你学会了吗?今天的分享就到此结束了,关注我,交一个懂编程的朋友!

好,我们来看这道面试题啊, const 定义的变量可以修改吗?呃,我们先分析一下啊, const 的 保证并不是变量的值不能改动,而是变量指向的那个内存地址不能改动。 对于基本数据类型的数据啊,其值就保存在变量指向的那个内存地址,因此等同于常量。呃,所以基基本数据类型啊,它是, 嗯,不可以修改的啊。对于引用类型的数据,主要是对象和宿主来说,变量指向数据内存地址保存的只是一个指向, cos 的, 只能保证这个指向是固定不变的。 至于他指向的数据结构是不是,嗯,是,是不是可变的就完全不能控制了啊。所以我们得出结论啊。嗯,这道题的答案是不能或引用类型不能啊。好,下课。

当被面试官问到 var net cons 的 区别是什么的时候,并且呢,让你在作用域,变量提升等这个各个方面去说明一下它的细节。怎么去回答呢?同样大家先要知道考察点, 这个其实考察的是在 es 六里面的一个核心特性啊,就是作用域,变量,声明周期,还有底层的一个理解。那我们都知道啊,常规的 申明呢,有三个方式,三种方式,比如说 var, let 和 const, 它是加括号中用来去申明变量的三种方式,并且呢, let 和 const 是 当下用得最多的, 它是为了解决 var 存在一些问题,所以大家其实学习的时候回答的时候有技巧,就是用 net 和 console 来去对比这个 var 啊,解决了 var 的 什么问题?就好像大家去面试的时候被问到了 view 三,然后呢,其实你要回答 view 三相比于 view 二有哪些优势 好,那整个核心的区别呢?我给大家去整理一张表,大家可以对比一下,不管是从作用域,变量提升,还有呢暂时性死区这些概念,包括呢,还有重复申明问题几个点啊,来去理解。另外修改值是否能修改和局对象的属性对比的一个情况, 比如说 varlet, const, 它们在作用域这一块呢, var 它是属于函数作用域,并且呢,可以把它理解成是属于那种变量型作用域。而 let 和 const 呢,我们给大家前面说过,它是属于词法作用域,也把它理解成它叫快捷作用域, 变量提升, var 是 存在变量提升的,而 let 呢和 const 呢,虽然有声明提升,但是不做出实质化处理 啊,那这个其实好理解,我们通过代码施力呢,给大家做一个演示,比如说我现在在这里 console 点 lock 来打印一下 name, 而我的 name 的 声明呢,是在下面通过 name 来去声明了一个合一。 好,那我们直接通过 node 来执行一下这个 test, 其实可以发现它是完全可以执行的,它会打印一个 andify, 就是 它只是没有数据啊,那如果你把它提到前面去,这样来去打印呢?它能够打印出来合一这个结果 啊,可以打印出来这个合一这个结果。好,那这个其实就是存在的那个变量提升的这个点,那我们怎么样去优化它呢?因为有时候其实这个变量提升它不是一个好事啊,就是 提升了之后,后续的代码定义呢,有影响。那我们可以通过 net 来声明一个会计 作用域的变量啊,或者说叫做词法环境中的变量,我们再来执行一下,这个时候你就会发现报错了啊,这种是属于正常现象, 你们你不能够去获得这个内蒙属性啊,或者说这个变量,因为它还没有驶驶化啊,所以呢,对比就是 war, 它会提升驶驶化为 andify, 这两个呢?不提升啊,暂时性死区会存在吗? war 没有这两个呢?有 那个同学不理解,什么是暂时暂时性死区呢?我给大家一个逻辑给大家讲明白啊,比如说我现在呢有一个负循环, 然后呢,直接来一个 var a 等于零, i 呃 a 小 于一十,然后呢?或者我们少一点啊,小于三, i 呃 a 加加, 好,在这个里面呢,我们来一个 send timeout, 假设啊,我们直接当一秒钟以后来去执行,可以吧?好,假设呢,在这儿来打印一下这个 a, 这个结果,同学们来猜一猜等于多少啊?当然上面这个呢,我们把它改成 word, 如果是。 net 的 话,它没有办法声明 这个结果。毫无疑问啊,这个很能肯定,很多同学都了解过,那都会打印三,是为什么呢?因为它所存储的环境 叫变量环境,他的逻辑是存在变量环境里面。变量环境呢,我们可以通过一张图给大家来去做一个理解啊。好比如说我现在有一个,呃,数据,接下来呢,要去 压站,压进来之后,那所有的当前执行上下文会分为两个类别,第一个是属于变量存储区,还有一个叫此法变量存储空间。那像这个沃尔声明的,它其实都是存东,存在这一个公共区域,它不形成 会计的这种效果,或者是我们说的暂时性死区,也就是说,那你接下来再去执行 set them out, 一 秒钟以后,这三个函数拿到的都是那同一个变量空间里面的值。也所以说它会打印 三,全部都打印三,那怎么解决呢?两种方式来解决。第一种通过。 net 的 方式,这种是最好解决,最容易解决的。 那零一二没问题吧,这是其中最简单的一种,它会形成一个叫暂时性死区。啊,暂时性死区叫 t d z 这个术语的话,那如果不用这种方式,有没有别的方式呢?有,在这个 set time out 里面。 set time out 里面,我们定义一个极调函数, 在极调函数里面呢,我们传一个 i 进去,然后呢,这里传一个 i 进去。好,同学们注意,通过这种写法就能够人为的去给它创建一个 b 包环境,那在这个环境里面的内容呢?它是一个单独的作用域, 每次执行 a 等于零的时候传进去, a 等于一的时候传进去, a 等于二的时候传进去,相当于它有三个作用域,然后呢,承载了三个不同的数据,这个时候我们再丢进去打印这个 i 的 结果,你就会发现 没有问题了啊,当然它这里打印说是 i, 我 们把 i 传进去, i 从这里传进去,然后呢,得到这个 i 保存一下,我们再来执行。 哦,这里写错了,传 a 啊,再执行,可以看到吧,零一二啊,这个结果 传进去,把这个 i 的 结果传进去,一次,两次,三次,它是单独隔离开的三个重域啊,好。 作用域呢?其实通过 var 声明的话,它是单独存在一个变量区域里面,那 net 和 const 呢?它是在单独的会计作用域中间。这就像我们像我们刚才给大家绘制的这张图一样,这个是一个叫做执行上下文环境啊,这个叫执行上下文环境, 那执行上下文环境里面的数据存储不一样,向 var 声明的单独在变量环境。 那如果是。 net 和那个 const 呢?它们在词法环境,这个其实就跟翻译相关的挂钩了啊,我们之前跟大家说过,翻译的流程是什么样子的?先是 passer 转换器转换对应的逻辑,然后呢,再到这个 transformer, 也就是代码生成 好,这是整个流程代码的执行和代码解析的流程。 paster, transformer 跟 generator, 那 我们这里说的词法分析呢?其实就是在 paster 这个阶段通过解析 token 来得到对应的数据啊, 我们说的这个 token 就是 词法,词法环境,其实也就是 token 的 对应环境啊,这是执行上下文对于它的一个理解。 变量提升,这个刚才给大家说到了啊,就比如说按照这种形式,那变量呢?会提升上去,但是。 net 和 const 不 会暂时性死区,就是我们刚才给大家去理解的。 那我们对于 console 来说呢?它除了。 net 相关的这种特性以外,它还有一旦出场就不能够再被重新赋值。这种一般用在像常量的场景非常有用啊,比如 pi 等于三点一四,那你声明了这个 pi 等于三点一四,后续你就不能够再去修改它了。 最终我们总结一下,优先使用的话,如果没有其他的场景的说明和特殊的一些逻辑的话,优先全部用 const 啊,全部用 const 就是 你确定这个数它不会变化,那默认就用 const。 第二,如果这个变量可能在在将来某一天会赋值复制成一个新的数据,那你就用。 net 不要用 var 啊,不要用 var, 所以 优先 const 其次。 net 而不要用 var 啊,所以这就是我们总结的最佳实践。

concept 在 c 加加中远不止是一个类型修饰符。别以为它只是用来定义常量,它浓缩了 c 加加程序语言设计的核心哲学, 在给予程序员强大控制力的同时,通过 b a 时检查提供安全性。在追求高性能的同时,通过明确的契约增强代码的可读性和可能性。它是 c 加加平衡效率、灵活性与安全性思想的完美立正。 第一,他信任程序员,但同时提供保护,让可控性与安全性并存。 c 加加给予程序员极大的控制权,允许直接操作内存、指真等底层机制,但这很容易导致意外修改。 cost 提供了一种轻量级的保护机制,他告诉变 e 器,这个值不应该改变,变 e 器会在变 e 期间强制执行,防止无意中的修改。 这种设计体现了 c 家家的哲学,信任程序员的能力,但同时提供工具帮助程序员避免错误,而不是像毛宗元那样完全限制能力。 第二,它是零开销的抽象。 cos 的 限定作用只在编意时检查,无任何运行时负担。 c 家家的设计原则之一就是只为用到的共同付出代价,而且不会为抽象增加不必要的运行时开销。 cos 的 完全符合这一原则,它纯粹是编意期的约束, 不会生成额外的代码或降低运行效率。 cons 还可以帮助编辑器进行优化,进一步提升性能。 这体现了 c 加加对高效抽象的追求,让程序员写出安全的代码,同时保持与 c 语言相当的效率。第三,它体现着接口及器约,明确表达设计意图。在内设计中, cons 的 成员函数承诺不会修改对象状态,这是接口器乐的重要组成部分。 用户看到 cost 的 成语函数就知道可以放心调用,不必担心对象被改变。这种显示表达意图的做法让代码更具有可读性和可维护性,也体现了 c 加加对接口设计与语义明确性的重视。 同时,通过 cost 引用传递参数,可以避免不叫的拷贝,同时保证原对象不被修改,这正是现代 c 加加推崇的存餐方式。第四,它提供渐进学习与兼容性, 让程序员可以在 c 的 基础上改进。 c 加加从 c 语言继承了 cost, 在 c 中, cost 更多只是作为一种指读提示,实际仍可能被修改。在 c 加加中, cost 与类型系统紧密结合,还引入了 cost e s p r, 支持编意式求值, 这反映了 c 加加在兼容 c 的 同时不断强化类型安全和表达能力的哲学指语言既能附用现有 c 代码,又能提供更高级的抽象。第五,它提供了多范式支持,可适应不同编程风格。 concept 在 不同编程范式中都有体现, 一、面向过程 cos 的 参数 cos 的 前景乘量。二、面向对象, cos 的 成员函数, cos 的 对象。三、范型编程,在模板中通过 cos 的 引用传递参数确保通用性。四、函数式 cos 的 espr 支持纯函数式的变易式计算, 这体现了 c 加加不强制单一范式,而是让程序员根据实际场景选择合适的风格,而 console 是 贯穿其中的统一工具。第六,变异时尽可能做更多的事情,将错误消灭。在早期, c 加加推崇在变异期发现错误,而不是等到运行时, console 将不变性地保证提前到变异期。 任何试图修改 cos 的 对象的代码都会导致变异错误,这比运行式崩溃或逻辑错误更早暴露问题。这种思想也体现在 cos 的 espr 模板、圆编程等特性中,体现了 c 加加追求变异式计算和检查的倾向。 这就是 cos 的 一个小小的类型限定符,却藏着如此强大的力量,它背后是 c 加加刻进骨子里的设计哲学,是这门语言独有的思考方式与取舍智慧。这份藏在细节里的内核,你体会到了吗?

前面课程中变量我讲漏了个东西,这个坑我自己也踩过。我是老霍,二十五年的 c 家家老兵,自学出身,讲了变量之后,有人问我老霍变量能改,那有没有不能改的,有就叫常变量。 你去超市买了瓶矿泉水,标签上写着五百五十毫升,这个五百五十是固定的,你不能把它改成六百,它就是个常量,谁家家里也一样。你用 cost 这个关键字就告诉程序这个值定了,谁也别想改, 变异器会直接打你的手,不许改。你写代码定了个数字,三点一四到处用,突然有一天要改成三点一四一五九,你得找遍整个文件,一个一个改,改漏一个就是 bug。 用了 cost 只改一个地方,全部搞定,这就是老货踩过的坑,现在白送给你。好,知道了是什么为什么用。现在讲两个细节,不知道这两个你照样会报错。细节一,必须初步化, 你买了个保险箱,锁上之前必须先放东西进去,空着就锁上,里面啥都没有,这箱子就废了。 cost 一 样,声明的时候必须赋值,普通变量可以先声明再赋值。 cost 不 行,一开始没给值,后面也改不了,永远是废的。 细节二,类型要写对,常变量也是变量, int, double 差都能用,存整数就写 int, 存小数就写 double, 存字母就写差,类型写错,编辑器照样骂你。这个别偷懒 好,给你划重点就三条,第一, cos 的 锁值谁也改不了。第二,声明时必须赋值,不然是废的。第三,类型要匹配,不能乱写,把这三条刻进脑子里,后面遇到坑你就能绕开关注,老货少走。

hi, 欢迎回来,那么上集呢,我们已经完成了所有功能的开发,那么这一集呢,我们来就来进一步的改进当前这个项目的一些项目结构,并且呢去优化我们整体的代码逻辑。那么首先呢,我们要在 forecast 的 这里呢, 很明显,我们应该去优化一下这里请求数据的部分,把它抽象成一个 hook, 大 概就是这么多,对吧。我们复制直接来到 hook 文件夹, 我新建 use broadcast weather js 这样一个文件,导出 default function, 粘贴,我们导入相应的东西。 那这里的 position 呢?我们就通过参数列表的方式呢给它传进来,然后要用到的所有的东西呢,我们全部都给它导出出去,这里的 filter 播 test data list, 还有这里的 a r, 我 们也可以给它导出出去, 确保没问题。之后呢,我们就可以来替换掉这里所有的东西了,直接注视在上面去使用我们的 hook use forecast the weather, 传入我们的 position 结构我们需要的东西,这里应该是 battery data list。 好, 我们只需要这一个就行了,把上面不需要的通通给它删掉。 ok, 一 切就绪,我们来看一下我们的应用,它有什么问题, 这里它提示我 forecast weather feature 没有定义是吧,就是我们这里的 use s w r 的 第二个参数,这里我们要重新导入一下,我们手写一下 forecast weather feature 这里的路径的话稍微有点麻烦,应该是在 youtube 下面的 feature g s, 这样应该没问题了,我们试一下好功能,没有任何问题。那此时呢,我们就成功地抽象好了一个 hook, 那 光是抽象好一个 hook 之后呢,我们再看这里的组建呢,下面的 j, s, x 的 部分呢,依然是比较的麻烦的,对吧?我们还可以把这里的 list item 单独地抽象出来,复制来到我们的 components 这里, 我们再新建一个 forecast, 下面的自组键,我们就叫 forecast list item 直接 six, 我 们使用这样一个 snippets 快 速生成,直接粘贴,那么它需要接受一个 props 叫做 weather forecast, 对 吧?同时呢, 我们需要导入这样一些来自 material ui 的 这样一些组建,我们来逐个给它导入进去,这里因为缺少对应的类型,所以呢,我们这里要手动的一个一个导入所有的组建,如果是 type script 的 话呢,这里我们就可以直接一键让它帮我们导入。完成之后呢,我们看一下, 应该是没有缺少的东西了,对吧?只要保证我们传入了这样一个 props 就 可以了。回到我们的 forecast, 把这里的 list item 给它去掉,取而代之的就是我们刚才抽象好的组组键 forecast list item 啊,需要注意,我们要传入我们的 weather forecast 这样一个 props weather forecast, 同时啊,别不要忘了这里是列表渲染,那么列表渲染的每一个子项我们都要绑定它的 key, 那 这里的 key 对 应的值就是 weather forecast 的 点 id 啊,就和这里的写法呢,一定要保持一致,我们把这里的注置呢给它删掉。修改完一点之后呢,我们就再去测试一下我们的功能, 确保每次修改呢我们都进行一次完整的测试,这样才能够保证呢我们的修改不会造成什么破坏性的更新, ok, 把这里多余的导入通通给它删掉,这样就简单多了,对吧?那还有一个部分呢,就是这里的这个浮动按钮, floating action button, 我 们也可以给它抽象一下, 复制,在左边新建一个组键,这里呢,我就叫它 floating button 吧,我就把中间那个 action 给它省略掉,不然的话可能会导致这个组键名重名。导入一下这里的 fab, 我 们需要导入这里的 fab style, 对 吧?那刚好呢,这个 style 放在我们的 forecast 的 里 就显得有些奇怪,这样我们就可以给它正大光明的拿过来,那这里的 style 我 们就可以直接给它删掉了,那这么一来,我们的 forecast 看起来就更简单了,对吧?那中间的内容呢?因为我们这个组建叫做 floating button, 而不是叫做 floating back home button, 所以呢,按理来说,这个按钮它应该是不关心 它到底会实现怎样的功能的,因此呢,这里的 icon 我 们应该是可以随意的更改的,那这里我们要实现中间的内容随意更改的话,那干脆我们就使用 children 来代替它,这样能够让我们的整个 floating button 组建呢变得更加的灵活。回到我们的 forecast, 把这个地方呢,替换成我们刚才抽象好的 floating button, 那 中间传入我们的 home icon, ok, 把这个导入给它去掉。但是呢,这里它调用了 set is home, 或者说这里的 unclick, 它需要绑定对应的这样一个事件处理函数,那这个事件处理函数呢?我们之前的做法是通过传入这里的 set is home, 然后呢再再通过 set is home 构建一个临时的匿名函数给它传进去,那这里呢,我们想要真正的让我们的 floating button 作为一个 不关心具体功能实现的一个通用组件的话,那这里我们不应该在 floating button 这里呢去定义这个函数内容,我们应该把这里的整个函数内容呢给它抽象到外面去,也就是说呢,定义这个函数的部分呢,我们给它抽象到我们的 forecast 的 组件中, 我叫它 handle click back home, 这里的内容呢很简单, set is home 给它设置成 true 就 行了,然后把整个这个函数呢作为一个 props 传到我们的 floating button 这里, 它的 props 呢,我们也要给它的名字抽象一下,我就教它 unclick, 也就是说呢,我们的 floating button 它不关心传入来的这个函数是什么,它只把这个函数呢当做一个 click 事件的事件处理函数就行了,这样给它绑定进去,那这样一来的话呢, 我们定义这样一个按钮对应的处理函数的时候呢,它的定义的逻辑全部都放在这个 floating button 的 外面,它不关心 这个按钮到底触发了怎样的逻辑,它只关心把这个逻辑呢绑定在按钮的点击事件上就行了,这样的话,我们的 floating button 它就真正的成为了一个通用的组建。此时呢,再来看我们的 forecast, 它就变得非常的简单了, ok, 那 么到此的话呢,我们就成功的完成了这里的 hook 还有组建的一些抽象,但是可以发现我们抽象出来这样一些更细致的组建之后呢,这里的 components 中间的这些内容呢, 已经开始变得越来越复杂了,比起上一节的话,已经开始变得有些不可控了。要是未来我们进一步加功能的话,那岂不是这里 components 里面组建的数量它就直接爆炸了? 那很明显,我们要对这里 components 里面所有的组建呢,再进一步的做一些划分,那这个划分的依据是什么?我们又该如何进行划分呢?那这里呢,带各位看一篇 blog 啊,这也是我在我之前的很多课程中都会带各位看的一篇 blog, 或者呢,你去搜索前端应用项目最佳实践, 你应该也能够搜到这样一篇来自 medium 的 这个 blog。 那 这篇 blog 呢,就简单讲述了一下基于 wit 的 一个项目,它的一个项目结构是怎样的。可以看到它这里所展示的第一个 这个叫做 default project structure, 也就是默认的项目结构这个过程中的。那虽然它是以 view 为例子,但是呢, view 和 react 现在都是基于 wit 来构建的嘛,所以呢,大家的结构其实是一样的, 可以看到它的结构和我们现在的结构就很像,所有的组建呢,都写在 components 里面,那这么做的话显然是不行的,所以呢,它下面提出了另外一种方法,这里举了 x 的 例子和就是之前的 twitter。 那 么这里 x 的 例子呢,就是把整个页面上的不同的功能区域作为划分的依据,然后来划分我们的组建。 这里啊,它划分出来之后,可以看到是这个样子的,它划分出来了这么多的文件夹,可以看到有些文件夹我们之前是见过的,比如这里的 services, 还有这里的 components, 但是呢,有些我们没见过,比如这里的 features。 那 这里呢,我们不关心啊, 我们只关心的是它到底划分的依据到底是什么。而这里呢,它划分的主要的依据其实是根据我们的功能来划分的,所以呢,它这里主要划分的这个文件夹叫做 features, 那 features 呢,就是按照不同的功能来划分的,我们把不同的组建放到不同的功能区里面就行了,大概就是这个样子。 然后其他的这些文件夹的话呢,它是对应着其他的场景,因为我们目前的应用呢,只用到了最核心的 react 功能,没有用到其他的一些功能,所以呢, 暂时用不到其他的这样一些文件夹,那我们就直接参照它这里的例子啊,我们在 s r c 下面新建一个文件夹,叫它 features 啊,我再强调一遍,这只是我个人比较推崇的划分方式,你有其他的见解的话,或者说你自己的工作过程中呢,有其他的要求, 完全可以不参照我这里的做法,我这里只是提供一个参考。那这里写好 features 之后呢,我们看一下我们的整个应用它有哪些功能?那我们来到 app js, 可以 看到它其实就两个功能,一个是 home, 一个是 forecast, 所以呢,我们干脆就创建两个子文件夹 home, 然后是 forecast, 那 相应的把 home 对 应的组建呢,给它放进去,首先呢是我们的 home js, 然后 home 子键下面呢有这个 welcome, 我 们把 welcome 也给它放进去,然后还有我们的 current weather, 那 对应的还有它的样式文件全部给它放进去,还有这里的 day 也给它放进去。我们的 vsco, 它是会自动地更改这里的路径导入的,所以大家不用操心,当然待会儿我们可能还是需要手动地去修复一下。 ok, 那 剩下的呢?除了这里的 container 之外,剩下的这些全部都给它放到 forecast 里面,这样的话划分就比较简单了。那剩下的部分呢?这里的 components 呢?我个人更喜欢把它叫做 ui, 我 给它重命名一下,可以看到 ui 这个文件夹的图标和之前的 components 的 图标是一样的,说明它们俩的定位在这个很大程度上都是相同的。这里呢,为什么我个人喜欢叫它 ui 呢? 因为所有的 ui 组件呢,可以发现它有一个特点,就是它里面没有具体的这个功能逻辑,它没有具体的这个 state 状态变量的定义,以及对 state 状态变量的这样一些操作。那这种组件呢,很明显不只是我们的 container 组件有这个功能,还有我们的 welcome, 它也是这样的, 可以看到它没有任何的这个操作逻辑,所以呢,我们的 welcome 也可以给它放过来。还有什么呢?还有我们的 floating button, 这里我刻意的保证不在我们的 floating button 中去操心,去操作任何的状态变量,所以呢,我们的 floating button, 它也符合我们的 ui 组建这样一个标准。 ok, 此时呢,我们要解决这样一些导入的问题了,这样划分好了之后呢,我们的应用它可能会出现一些问题啊,我们看一下它提示找不到了是吧? 首先呢是这里的 app gt x 这里,而这里的导入呢,肯定会发生一些问题,首先是这里的 forecast, 那 我们干脆给它重新导入一下 forecast, 这里是有提示的,这样还稍微好一点。然后是这里的 forecast 的 组建,下面导入这个 hook 的 地方啊,应该是这样啊,这样应该就对了。 ok, 我 们来试一下功能,一切正常是吧,那我们的 vsco 还是比较智能的,帮助我们解决了大多数的这样一些路径的问题,那顺便呢,我们也稍微打理一下,我个人的建议呢,是把 我们自定义的 hook 放在导入语句的最下面,然后呢第三方库的这样一些组建,或者是一些核心库的这样一些内置的 hook 或者说功能的话,全部放在最上面,我们自定义的组建呢,就放在中间啊,这是我个人的划分方式, 当然你还可以划分的更加的细致。 ok, 那 么到此的话,可以看到我们整个项目呢就划分的井井有条了,至少呢,你可以直接通过 features 文件夹 直接告诉另一个和你来写作的人,让他能快速的理解我们这个项目呢有哪些功能,然后每个功能点下面有哪些组建, 同时呢也能够通过 ui 这个文件夹看到哪些组建呢,是和我们的操作逻辑无关的,这样的话,比如你在带实习生的时候,你就可以把维护这个 ui 组建的部分呢交给他, 因为他不关心传进来的逻辑是什么,他只关心这里的 u i 展示,这样的话就能够将我们的逻辑还有我们的 u i 展示的部分呢,进一步地完成相应的分离, 而不像最开始那样把所有的组建呢全部都揉杂在我们的 components 中。只不过呢,这里还是有一个小问题啊,大家发现没有,在我们的导入的部分呢,比如这个 forecast 的 组建这里,我们这样进行组建的划分之后呢,我们在进行导入的时候,这里难免会出现一些相对路径的导入设置, 可以看到这些相对路径写起来会非常的复杂,非常的麻烦。如果我们的编辑器他在提示的过程中呢,出现了一些问题,没有办法很好的提示的话,我们去手动的导入 很明显是一个非常非常难受的过程。那有没有什么方法能够将我们从这个繁琐的过程中解放出来,或者说有什么更好的简写方法呢?啊,这个部分呢,我们就留到下一集的,我们就留到下一集再解。那么以上就是本期视频的所有内容,希望你能关注或点入我的频道,感谢你的观看,我们下期视频再见!

好的,那么各位啊,我们接下来讲一下 cos 修饰成员函数啊,那么 cos 修饰成员函数呢,就有两种,一种是长函数,一种是长对象啊。 我们先讲理论,在长函数当中,成员函数后加 cos, 注意啊,是成员函数后加 cos 的, 我们称之为长函数,长函数内是不可以修改成员属性的,成员属性声明时加关键字 multiple, 之后在长函数中依然可以修改。 这是第一个长函数,第二个长对象声明对象前加 cos, 称该对象为长对象,那么长对象呢?只能调用长函数。来,我们举个例子说明一下,有点太过于抽象。 demo 十四 demo 十四啊,来添加啊,在这里呢,我们把一些标准的这个就是框架啊,给它复制一下来,比如说把它删掉, 然后呢,嗯,把这里面的内容删掉,其他的都应该不会改变,都都不变,我们仍然讲的还是这个类啊,还是这个类啊。首先第一个我们定义的是两个变量,嗯,那么在这里的话呢,我们就一律统称为 public。 好 吧,来,我们在这里啊, m 下滑线 a n d 呃, m m 下滑线加一个 b 定 b 量,然后在这里呢,我们定一个构造函数啊。 pos, 一 样的有构造,我们待会要注意,也要定义这个 c 购函数, 保持我们这个代码的这个见状性,是吧, m 下滑线 b 也要等于零。好,那么定完之后养成好习惯,直接紧跟上 c 购函数 pos 嗯,结果函数不要去赋任何值就行。好,那么这就是这一块。然后呢,现在我们要写上一个长函数和不是长函数的例子来,注意, show 一个 perse 啊, show 一个 perse 啊,然后呢?哎,我们走个这个是吧?那么在这里呢,我们要注意啊, 我们让这个 this 点 m 向后边 b 啊,给它复制成一百, 好,我再写一个函数,叫 my f u n c, 对 吧?一样的道理,我让这个 this 点 m a 也等于这个一万。好,那么现在呢,我去测试案例测试一下, 比如现在啊,我就去通过这个 person 啊, person 调用一下 person 吧。好,现在我要干嘛呢?首先第一步注记, 第一步我们 c o u t 一下啊,比如说啊,调用函数吧,比如说 percent, 现在两个函数都能调,是不是?嗯,比如说我可以调用这个,就这个 show percent, 然后呢, percent 呢?我可以调用这个叫什么?调用这个叫做 my function。 好, 这个时候代码都是一切正常的,那么最后呢,运行也是有结果的, 肯定是一切正常的情况了,是吧?一切正常啊,好,那么接下来我的问题就来了, 第一个部分,我们要测的是我要把一个函数变成长函数,那么长函数内是不可以修改程序的, 比如说来看,怎么修改呢?首先你注意,比如说我要将这个函数变成长函数,怎么办?在这个函数之后,我们加上 const 关键字即可,那么它就是一个什么长函数啊,我做出是它就是我们所说的长函数, 那么好,那么它一旦是长函数了,那么这个对象还能不能修改?不能修改,那么如果说我硬要让它修改呢?硬要让它修改呢? 怎么办?我又要让他修改呢 啊,兄弟们 怎么办?还记得吗?我加上关键词不就行了吗?那加上哪个关键词?这 mutiple 啊,来 mutiple, 加个关键字不就行。来哦,这里是 m b 是 吧? ctrl c 一下, ctrl v 一下。好,它是不是可以修改了?这是第一个我要讲的东西,第二个注意听我要讲的东西在这里,比如说我在这里再用 mb 等于一千,可不可以呢? 将这时针指向 mb 等于一千,可不可以?这不也行啊? 好,那么接下来呢,我要输出一句话啊,你看,我首先不调用这个函数了,我直接调用它,那么由于啊,我 this 给 m a 初值值是零零,我现在给 m a 复制成一万,又给 mb 复制成一千,那么我现在问一下,我现在让这个叫什么?我现在让这个 m a 啊 加加。操作,当调用完我整个 my functions, 由于你 z 这个关键字是指向 m a 的, m a 要加加,那么你现在 m b 的 值是多少? 然后再问你 m a 的 值到底是多少?来吧,我们试试看啊,或者说我这里添加 m b 吧,用 m b 的 值加加,我问你 m a, m b 到底是多少?来,我们输出一下,我们检测一下,好吧, c o d 一下, m 向外延 a 这个,嗯嗯啊,是 person, 忘忘点了 person 点 ma, 等下,然后呢,搜一下这个 person, 点这个 m b 等下,那我们来测试一下。走, 我们看一下啊。首先来看 m a, m a 是 一万,没问题吧? mb 是 一千零一吧, 这很好理解吧,它的值是一万,它的值是一千零一,对吧?这都非常清楚的事情,但是你要注意啊,在我们 this 指征里头啊,你要知道, this 指征的本质是,其实在 this 所有的指向当中,它的本质都是一个指征场量,指的指向是不可以修改的, 也就是说你在这里创建了一个 person 对 象,那么你这个 z 就 永远指向的是 person 对 象,它不会指向你。另外创建一个 person 二对象不会的 啊,所以它首先是有指正常量啊,那么你现在的话呢,你在这个指正常量之前又加了个 cos, 说明它又是一个常量,指征数据又不能发生改变,但如果你硬要发生改变,你加个关键字就可以了,是不是这个道理?好, 这就是我们长函数需要注意一些事项,那么接下来看长对象,长对象呢?比如说我们在这里当中啊,我加一个,把后面的全部删了啊, 我在这里加一个 const c, n, s, t, 那 么这个时候就是长对象,那么长对象只能调用长函数,比如说它只能调用 show person, 这个是合法,但是 长对象它是不能调用非长函数,这个时候就会报错,因为它不是什么,哎,不是这个长函数啊,不是这个长函数,那么它不是长函数啊,哎,不行啊,所以这就是什么注意这几个注意事项, 好吧,那么这一讲呢,就注意一些这些,那么下一章呢,我们要进行有缘的一个学习了,好吧。

这个视频将介绍关键字 declare type。 关键字 declare type 的 英文全称是 declare type, 使用 declare type 的 语法格式,如这里所示, 它以关键字 declare type 引导,然后是一对圆括号,在圆括号内部是一个表达式,这样编辑器在编辑时将推导并返回这个表达式的数据类型, 但不会计算这个表达式的值。与关键字 auto 相比,采用关键字 declare type 的 数据类型推导 将会更加精确,它将保留数据类型的 conson 和引用等等的属性。 这里介绍采用关键字 declare type 的 数据类型推导规则。 其中第一个数据类型推导规则是变量规则。如果需要进行类型推导的表达式直接就是单个变量,这里的变量也包括函数、行参变量和成员变量, 那么变异器返回的数据类型就是这个变量的数据类型,而且保留在数据类型中的 constant 和引用等等的属性。 第二个数据类型推导规则是表达式规则。如果表达式不是单个变量, 那么就采用这里的表达式规则。表达式规则又可以细分为四条子规则,其中第一条子规则是函数调用规则。 如果表达式是函数调用,那么编辑器返回的数据类型是这个函数的返回值的数据类型,而且会保留其中的引用属性。第二条子规则是左值表达式规则。 如果表达式是左值,那么变异器返回这个表达式的左值引用类型。第三条子规则是右值表达式规则。如果表达式是字面常亮等右值, 那么编辑器返回这个表达式的不带有引用的数据类型。第四条子规则是圆括号规则。 如果表达式是一个圆括号,而且在圆括号内部是单个变量,那么编辑器返回这个变量所对应的左值引用类型。 根据这四条子规则,我们可以得到这样的结论,如果表达式不是单个变量,那么变异器返回的数据类型不会是又指引用类型。 这里给出了关键字 declare type 的 第一组代码示意。我们看,在从变量 b 一 到 b 五的定义中, 以关键字 declare type 引导的类型推导表达式都是单个变量,因此这些变量的数据类型就是在类型推导表达式中的 变量的数据类型。这样,因为 a 一 的数据类型是 int 类型,所以变量 b 一 的数据类型是 int 类型。因为 a 二的数据类型是 constint, 所以变量 b 二的数据类型也是 const int。 因为变量 a 三的数据类型是 int 类型的左值引用, 所以变量 b 三的数据类型是 int 类型的左值引用。因为 a 四的数据类型是 const int 类型的左值引用, 所以变量 b 四的数据类型是 const int 类型的左值引用。因为 a 五的数据类型是 int 类型的右值引用, 所以变量 b 五的数据类型是因此类型的。又指引用变量 b 六的定义需要用到关键字 declare type 类型推导的原括号规则。 这样,因为 a 一 的数据类型是 in, 所以 变量 b 六的数据类型是 in 类型的左值引用。在变量 b 七的定义中, 以关键字 declare type 引导的类型推导表达式是 in 类型的右值,所以变量 b 七的数据类型是 in。 这里需要强调一下,变量 b 七的数据类型不是 in 类型的右值引用,这是非常容易犯的错误。 这里给出了关键字 declare type 的 第二组代码,示意这里将采用函数调用规则。在这里的变量 b 一 和变量 b 二的定义中, 以关键字 declare type 引导的类型推导表达式都是函数调用。请注意,这里要求是函数调用,因此不能将这里的 g b sum 二、三 写成为 g b sum, 否则无法通过翻译。同样不能将这里的 g b i d 一 写成为 g b i, 否则也无法通过翻译。根据函数调用规则,因为函数 g b sum 的 返回值的数据类型是 int, 所以变量 b 一 的数据类型是 int。 因为函数 g b i 的 返回值的数据类型 是 int 类型的阻值引用,所以变量 b 二的数据类型 是因此类型的左值引用。因此,这里的变量 b 二实际上只是变量 b 一 的别名,这样,变量 b 一 和变量 b 二都拥有相同的值。 从这里输出的结果也可以看出,变量 b 一 和变量 b 二确实也都拥有相同的值。 这部分内容就介绍到这里,感谢您的支持!