首页 文章 精选 留言 我的

精选列表

搜索[初体验],共248篇文章
优秀的个人博客,低调大师

豆包MarsCode 初体验,用React创建一个最经典的贪吃蛇游戏

以下是「 豆包MarsCode 体验官」优秀文章,作者Find。 背景 在人工智能快速发展的时代,大模型(LLM)只要有足够的算力和数据就可以做到任何的事情,甚至可以模拟出另一个地球。LLM作为一个革命化的科技,可以取代很多岗位,甚至可以让人类达到"躺着领钱的时代"。Marscode作为一个新推出的IDE,紧跟时代的潮流,拥抱AI,顺应时代的潮流。 各种各样的语言,都会有一个贪吃蛇的游戏去作为一个里程碑,我也完完全全用这个IDE去编写贪吃蛇游戏这个小demo。 创建项目 在这个IDE创建一个贪吃蛇的项目 生成了一个这样的项目目录 因为我还没学ts,就再用npm init vite去初始化了一个JavaScript的React项目 输完项目名称,cd project-name和npm i切换到你的项目目录和下载依赖就完成了vite脚手架的安装 npm run dev把项目跑起来 很方便直接能网页预览 设计项目 提出自己的需求给AI assistant 设计这个游戏的组件 但是它好像不是很能理解上下文,我这两句话是放在一起写的。只能再给出一份更详细的设计要求 给出了四份组件,那就去项目中创建文件。 创建好对应的目录和文件。询问AI代码 以下过程一样,找AI去生成一份相关组件的代码 当然因为我是分开要的组件代码,所以就产生了一些错误。看到还有AI fix的功能 我果断尝试了 这里AI fix 左右两边分别表示之前的代码和修改后的代码,你可以去看它修改后的代码是否正确去选择是否接受 对于这个问题,AI fix似乎跟个人机一样,根本解决不了 最大的感受就是这个AI fix感觉就是给你改错,然后用错去改你的错,有一点拆东墙补西墙的感觉,毕竟还是AI,可能并不能很好去理解bug本质所在,只会通过bug存在的原因去机械的给你改bug。 解决完所有的bug 代码也是成功跑不出来 有些涉及AI生成的代码中有些属性并未被初始化等等问题,改来改去最后还是把页面跑出来了 代码 GameBoard.jsx import React, { useState, useEffect, useRef } from 'react'; import Snake from './Snake'; import Food from './Food'; import Score from './Score'; const GameBoard = () => { const [snakeBody, setSnakeBody] = useState([]); const [food, setFood] = useState({}); const [direction, setDirection] = useState('right'); const [isGameOver, setIsGameOver] = useState(false); const [score, setScore] = useState(0); const gameBoardRef = useRef(null); useEffect(() => { gameBoardRef.current.focus(); initializeGame(); }, []); useEffect(() => { if (snakeBody.length) { const timer = setInterval(moveSnake, 300); return () => clearInterval(timer); } }, [snakeBody, direction]); const initializeGame = () => { const initialSnake = [{ x: 200, y: 200 }]; setSnakeBody(initialSnake); setFood(getRandomPosition()); setDirection('right'); setIsGameOver(false); setScore(0); }; const getRandomPosition = () => { const x = Math.floor(Math.random() * 20) * 20; const y = Math.floor(Math.random() * 20) * 20; return { x, y }; }; const moveSnake = () => { let newHead; switch (direction) { case 'right': newHead = { x: snakeBody[0].x + 20, y: snakeBody[0].y }; break; case 'left': newHead = { x: snakeBody[0].x - 20, y: snakeBody[0].y }; break; case 'up': newHead = { x: snakeBody[0].x, y: snakeBody[0].y - 20 }; break; case 'down': newHead = { x: snakeBody[0].x, y: snakeBody[0].y + 20 }; break; default: return; } if (isCollisionWithWall(newHead) || isCollisionWithSelf(newHead)) { setIsGameOver(true); return; } const newSnakeBody = [newHead, ...snakeBody.slice(0, -1)]; if (isCollisionWithFood(newHead)) { setFood(getRandomPosition()); setScore(score + 1); newSnakeBody.push({}); } setSnakeBody(newSnakeBody); }; const isCollisionWithWall = (head) => { return head.x < 0 || head.x >= 400 || head.y < 0 || head.y >= 400; }; const isCollisionWithSelf = (head) => { return snakeBody.some((segment) => segment.x === head.x && segment.y === head.y); }; const isCollisionWithFood = (head) => { return head.x === food.x && head.y === food.y; }; const handleKeyDown = (event) => { if (event.keyCode === 37 && direction !== 'right') { setDirection('left'); } else if (event.keyCode === 38 && direction !== 'down') { setDirection('up'); } else if (event.keyCode === 39 && direction !== 'left') { setDirection('right'); } else if (event.keyCode === 40 && direction !== 'up') { setDirection('down'); } }; return ( <div> <div ref={gameBoardRef} tabIndex="0" onKeyDown={handleKeyDown} className="game-board" > {!isGameOver && <Snake snakeBody={snakeBody} />} {!isGameOver && <Food position={food} />} </div> <Score score={score} /> {isGameOver && <div>Game Over!</div>} </div> ); }; export default GameBoard; App.jsx和App.css import React from 'react'; import GameBoard from './components/GameBoard'; import './App.css'; function App() { return ( <div className="app"> <h1>贪吃蛇游戏</h1> <GameBoard /> </div> ); } export default App; .app { text-align: center; } ------------------css------------------ .game-container { display: flex; justify-content: center; align-items: flex-start; } .game-board { position: relative; width: 400px; height: 400px; border: 1px solid black; overflow: hidden; margin-right: 20px; } .score-board { margin-top: 20px; } Snake.jsx import React from 'react'; const Snake = ({ snakeBody }) => { return ( <> {snakeBody.map((segment, index) => ( <div key={index} style={{ width: '20px', height: '20px<p align=center>',</p> backgroundColor: index === 0 ? 'green' : 'black', position: 'absolute', left: `${segment.x}px`, top: `${segment.y}px`, }} /> ))} </> ); }; export default Snake; Food.jsx import React from 'react'; const Food = ({ position }) => { return ( <div style={{ width: '20px', height: '20px', backgroundColor: 'red', position: 'absolute', left: `${position.x}px`, top: `${position.y}px`, }} /> ); }; export default Food; Score.jsx import React from 'react'; const Score = ({ score }) => { return <div className="score-board">Score: {score}</div>; }; export default Score; 个人感受 做个这个小项目后,最大的感受就是如果你掌握了代码底层逻辑、编程思想等,通过这类有智能化AI的IDE一键生成会让你代码速度提升一个层次。可能有些人觉得AI只能搭建起一个简单的框架,事实上,在你搭建好了框架后,你还可以去按照你的需求去逐步完善你的项目,就拿这个贪吃蛇举例而言,如果我后续需要提升难度,根据我吃球后速度提升、设置障碍物等等,我都可以单独拎出这些需求告诉AI助手,就算它并不能完全帮你写完代码,但也能八九不离。CSS样式、页面切片这种,通过tailwindcss框架和语义化标签,AI已经有理解图像的能力,可以很好完成此类工作。当然随着大模型数据不断的喂养,慢慢等到资本的介入,算力不断提高,AI理解能力的提高,也会使这种AI IDE越来越厉害,也许真有一天普通人掌握编程思想不会编程语言也能编程。豆包Marscode正是有这种强大的功能的IDE,我相信豆包Marscode 会越来越好!!! 本文由博客一文多发平台 OpenWrite 发布!

优秀的个人博客,低调大师

JDK17+ZGC初体验|得物技术

1 前言 垃圾回收器的暂停问题一直是Java工程师关注的重点,特别是对实时响应要求较高的服务来说,CMS和G1等主流垃圾回收器的数十毫秒乃至上百毫秒的暂停时间相当致命。此外,调优门槛也相对较高,需要对垃圾回收器的内部机制有一定的了解,才能够进行有效的调优。 为了解决此类问题,JDK 11开始推出了一种低延迟垃圾回收器ZGC。ZGC使用了一些新技术和优化算法,可以将GC暂停时间控制在10毫秒以内,而在JDK 17的加持下,ZGC的暂停时间甚至可以控制在亚毫秒级别! 2 ZGC ZGC相关介绍、原理,网上已经有很多类似文章,这里只做简单介绍。 2.1 设计目标 ZGC 最初在 JDK 11 中作为实验性功能引入,并在 JDK 15 中宣布为生产就绪。作为一款低延迟垃圾收集器,旨在满足以下目标: 8MB到16TB的堆大小支持 10ms最大GC暂时 最糟糕的情况下吞吐量会降低15%(低延时换吞吐量很值,吞吐量扩容即可解决) 2.2 ZGC 内存分布 ZGC与传统的CMS、G1不同、它没有分代的概念,只有类似G1的Region概率,ZGC 的 Region可以具有如下图所示的大中下三类容量: 小型 Region(Small Region):容量固定为2MB,用于放置小于 256KB的小对象。 中型 Region(Medium Region):容量固定为 32MB,用于放置大于 256KB但是小于 4MB的对象。 大型 Region(Large Region):容量不固定,可以动态变化,但必须为 2MB的整数倍,用于放置 4MB或以上的大对象。每个大型 Region中会存放一个大对象,这也预示着虽然名字叫“大型 Region”,但它的实际容量完全有可能小于中型Region,最小容量可低至4MB。大型 Region在ZGC的实现中是不会被重分配的(重分配是ZGC的一种处理动作,用于复制对象的收集器阶段)因为复制大对象的代价非常高。 2.3 GC工作过程 与CMS中的ParNew和G1类似,ZGC也采用标记-复制算法,不过ZGC通过着色指针和读屏障技术,解决了转移过程中准确访问对象的问题,在标记、转移和重定位阶段几乎都是并发执行的,这是ZGC实现停顿时间小于10ms目标的最关键原因。 从上图中可以看出,ZGC只有三个STW阶段:初始标记,再标记,初始转移。 具体转移过程,网上有大量类似文章,这里不做详细介绍,大家有兴趣可以参考以下文章: 新一代垃圾回收器ZGC的探索与实践 ZGC 最新一代垃圾回收器 | 程序员进阶 3 为什么选择JDK17呢? JDK 17于9月14日发布,是一个长期支持(LTS)版本,这意味着它将在很多年内得到支持和更新。这也是第一个LTS版本,其中包含了一个可用于生产环境的ZGC版本。回顾一下,ZGC的实验版本已经包含在JDK 11(之前的LTS版本)中,而第一个可用于生产环境的ZGC版本出现在JDK 15(一个非LTS版本)中。 4 升级过程 从JDK8+G1升级到JDK17+ZGC,主要是在代码层面和JVM启动参数层面的做适配。 4.1 JDK下载 首先jdk17选择的是openjdk,下载地址:https://jdk.java.net/archive/,选择版本17 GA 4.2 代码适配 JDK11移除了 Java EE and CORBA 的模块 项目中如果用到javax.annotation.*、javax.xml.*等等开头的包,需要手动引入对应依赖 <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> </dependency> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> </dependency> maven相关依赖版本升级 <!-- 仅供参考 --> <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version> <maven-assembly-plugin.version>3.3.0</maven-assembly-plugin.version> <maven-resources-plugin.version>3.2.0</maven-resources-plugin.version> <maven-jar-plugin.version>3.2.0</maven-jar-plugin.version> <maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version> <maven-deploy-plugin.version>3.0.0-M1</maven-deploy-plugin.version> <maven-release-plugin.version>3.0.0-M1</maven-release-plugin.version> <maven-site-plugin.version>3.9.1</maven-site-plugin.version> <maven-enforcer-plugin.version>3.0.0-M2</maven-enforcer-plugin.version> <maven-project-info-reports-plugin.version>3.1.0</maven-project-info-reports-plugin.version> <maven-plugin-plugin.version>3.6.1</maven-plugin-plugin.version> <maven-javadoc-plugin.version>3.3.0</maven-javadoc-plugin.version> <maven-source-plugin.version>3.2.1</maven-source-plugin.version> <maven-jxr-plugin.version>3.0.0</maven-jxr-plugin.version> Lombok版本升级https://projectlombok.org/changelog <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <!-- <version>1.16.20</version>--> <version>1.18.22</version> </dependency> Java9 模块化后,不允许应用程序查看来自JDK的所有类,会影响部分反射的运行,需要通过以下命令解决 --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED 本地使用了transmittable-thread-local-2.14.2.jar后启动报错 在agent后面加上日志输出即可解决,至于原因,猜测是跟类加载顺序有关系 -javaagent:/Users/admin/Documents/transmittable-thread-local-2.14.2.jar =ttl.agent.logger:STDOUT 以上内容仅针对彩虹桥项目升级遇到的问题,不同的业务代码适配的情况可能不一样,需要根据实际情况寻找解决方案。 4.3 JVM参数替换 下面是一些通用GC参数和ZGC特有参数以及ZGC的一些诊断选型,来自官网:Main - Main - OpenJDK Wiki 具体每个参数的含义,这里不做介绍,可参考官网文档The java Command,里面有详细说明。 JKD8+G1的启动参数: -server -Xms36600m -Xmx36600m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+PrintReferenceGC -XX:+ParallelRefProcEnabled -XX:G1HeapRegionSize=16m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/apps/errorDump.hprof -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -XX:+PrintGCApplicationConcurrentTime -verbose:gc -Xloggc:/opt/apps/logs/${app_name}-gc.log JDK17+ZGC的启动参数如下: -server -Xms36600m -Xmx36600m #开启ZGC -XX:+UseZGC #GC周期之间的最大间隔(单位秒) -XX:ZCollectionInterval=120 #官方的解释是 ZGC 的分配尖峰容忍度,数值越大越早触发GC -XX:ZAllocationSpikeTolerance=4 #关闭主动GC周期,在主动回收模式下,ZGC 会在系统空闲时自动执行垃圾回收,以减少垃圾回收在应用程序忙碌时所造成的影响。如果未指定此参数(默认情况),ZGC 会在需要时(即堆内存不足以满足分配请求时)执行垃圾回收。 -XX:-ZProactive #GC日志 -Xlog:safepoint=trace,classhisto*=trace,age*=info,gc*=info:file=/opt/logs/gc-%t.log:time,level,tid,tags:filesize=50M #发生OOM时dump内存日志 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/apps/errorDump.hprof 5 压测结果 直接上图 正如 ZGC 设计目标所描述,它将 GC 暂停时间从过去的几十毫秒降低到了令人惊叹的亚毫秒级别。然而,这种超低延迟表现也需要一定的代价,因为在实现低延迟的同时,ZGC 会占用一定的 CPU 资源。通常情况下,ZGC 占用的 CPU 比例不会超过 15%。在彩虹桥项目中,使用以上推荐的 JVM 参数后,ZGC 占用的 CPU 资源为 6% 左右。 6 ZGC日志 6.1 输出ZGC日志 GC日志中包含有关 GC 操作的详细信息,可以帮我们分析当前GC存在的问题。先来看一下上面JVM参数中关于GC日志的参数 -Xlog:safepoint=trace,classhisto*=trace,age*=info,gc*=info:file=/opt/logs/gc-%t.log:time,level,tid,tags:filesize=50M safepoint=trace:记录关于 safepoint 的 trace 级别日志。 Safepoint 是 JVM 中一个特殊的状态,它用于确保所有线程在特定操作(如垃圾回收、代码优化等)之前进入安全状态。 classhisto*=trace:记录与类的历史相关的 trace 级别日志。 age*=info:记录与对象年龄(在新生代中存在的时间)相关的 info 级别日志。 gc*=info:记录与垃圾回收相关的 info 级别日志。 file=/opt/logs/gc-%t.log:将日志写入到 /opt/logs/ 目录下的文件中,文件名为 gc-%t.log,其中 %t 是一个占位符,表示当前时间戳。 time,level,tid,tags:在每个日志记录中包含时间戳、日志级别、线程 ID 和标签。 filesize=50M:设置日志文件的大小限制为 50MB。当日志文件大小达到此限制时,JVM 将创建一个新的日志文件并继续记录。 更详细的gc日志配置可以参考:https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html#enable-logging-with-the-jvm-unified-logging-framework 6.2 STW关键日志 其中我们重点关注的就是GC的STW情况,以下是一些关键字代表GC STW阶段 最基本的STW三阶段,初始标记:日志中Pause Mark Start,再标记:日志中Pause Mark End,初始转移:日志中Pause Relocate Start。 内存分配阻塞:这一般是因为垃圾生产速度大于回收速度,垃圾来不及回收,垃圾将堆占满时,线程会阻塞等待GC完成,关键字是Allocation Stall(被阻塞的线程名称) 如果出现此类日志,可以尝试如下方法解决: -XX:ZCollectionInterval 该配置含义:两个 GC 周期之间的最大间隔(单位秒)。默认情况下,此选项设置为 0(禁用),可以适当调小该配置,让GC周期缩短、提升垃圾回收速度,但这会提升应用CPU占用。 -XX:ZAllocationSpikeTolerance官方的解释是 ZGC 的分配尖峰容忍度。其实就是数值越大,越早触发回收。可以适当调大该配置,更早触发回收,提升垃圾回收速度,但这会提升应用CPU占用。 安全点:所有线程进入到安全点后才能进行GC,ZGC定期进入安全点判断是否需要GC。先进入安全点的线程需要等待后进入安全点的线程直到所有线程挂起。日志关键字safepoint ... stopped dump线程、内存:比如jstack、jmap命令,一般是手动dump导致,日志关键字HeapDumper 7 Linux大页内存 在openjdk的官网上也能看到,开启Linux大页内存后会提升应用的性能。 开启方式见官网文档https://wiki.openjdk.org/display/zgc/Main#Main-EnablingLargePagesOnLinux,注意除了修改系统配置外,还需要在进程JVM启动参数中新增-XX:+UseLargePages配置 经过几轮压测实际测试下来,发现在开启Linux大页后,CPU有8%左右的下降,但是由于大页面会提前预留指定大小的内存,会导致机器的内存使用率较高。而且目前生产环境没有其他应用开启此配置,稳定性有待考究,生产环境自行评估是否开启。 8 总结 在本篇文章中,我们探讨了如何升级到JDK 17,并使用最新一代垃圾回收器ZGC。经过实践和测试,我们发现升级后的系统在垃圾回收方面表现出色,暂停时间被有效控制在1毫秒内。尽管这一优化过程可能会消耗额外的CPU资源,但所获得的超低GC暂停时间显然是非常值得的。总之,相比其他垃圾回收器,ZGC 的性能和稳定性已经非常优秀,而且不需要太多的调优。在大多数情况下,使用 ZGC官方推荐的默认设置即可获得优秀的性能表现。对于那些RT敏感型应用,升级到JDK 17并采用ZGC是一个明智的选择。 文: 新一 本文属得物技术原创,来源于:得物技术官网 未经得物技术许可严禁转载,否则依法追究法律责任!

优秀的个人博客,低调大师

从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十六 ║ Vue前篇:ES6初体验 & 模块化编程

缘起 昨天说到了《[从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十五 ║ Vue前篇:JS对象&字面量&this](https://www.cnblogs.com/laozhang-is-phi/p/9580807.html)》,通过总体来看,好像大家对这一块不是很感兴趣,嗯~~这一块确实挺枯燥的,不能直接拿来代码跑一下那种,不过还是得说下去,继续加油吧!如果大家对昨天的小demo练习的话,相信现在已经对JS的面向对象写法很熟悉了,如果嵌套字面量定义函数,如何使用this关键字指向。今天呢,主要说一下ES6中的一些特性技巧,然后简单说一下模块化的问题,好啦,开始今天的讲解~ 还是老规矩,一言不合就是上代码 str1 = 'Hello JS!'; function fun1() { var str1 = 'Hello C#!'; } fun1(); alert(str1); 大家猜猜,最后会弹出来哪一句话? 零、今天要完成浅紫色的部分 一、什么是传说中的ES6 这些定义网上一大堆,不过还是粘出来,大家可以统一看一下,简单了解了解: 1、定义 ECMAScript 6是JavaScript语言的下一代标准,在2015年6月正式发布。它的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。 标准的制定者有计划,以后每年发布一次标准,使用年份作为标准的版本。因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015。也就是说,ES6就是ES2015,下一年应该会发布小幅修订的ES2016。 2、有哪些新的变化 编程语言JavaScript是ECMAScript的实现和扩展,由ECMA(一个类似W3C的标准组织)参与进行标准化。ECMAScript定义了: 语言语法– 语法解析规则、关键字、语句、声明、运算符等。 类型– 布尔型、数字、字符串、对象等。 原型和继承 内建对象和函数的标准库–JSON、Math、数组方法、对象自省方法等。 ECMAScript标准不定义HTML或CSS的相关功能,也不定义类似DOM(文档对象模型)的Web API,这些都在独立的标准中进行定义。ECMAScript涵盖了各种环境中JS的使用场景,无论是浏览器环境还是类似node.js的非浏览器环境。 3、ECMAScript和JavaScript的关系 1996年11月,JavaScript的创造者Netscape公司,决定将JavaScript提交给国际标准化组织ECMA,希望这种语言能够成为国际标准。次年,ECMA发布262号标准文件(ECMA-262)的第一版,规定了浏览器脚本语言的标准,并将这种语言称为ECMAScript,这个版本就是1.0版。 该标准从一开始就是针对JavaScript语言制定的,但是之所以不叫JavaScript,有两个原因。一是商标,Java是Sun公司的商标,根据授权协议,只有Netscape公司可以合法地使用JavaScript这个名字,且JavaScript本身也已经被Netscape公司注册为商标。二是想体现这门语言的制定者是ECMA,不是Netscape,这样有利于保证这门语言的开放性和中立性。 因此,ECMAScript和JavaScript的关系是,前者是后者的规格,后者是前者的一种实现 二、var、let 与 const 块作用域 这里先说下,作用域的问题 1、ES6之前,JavaScript 并没有块级作用域,所谓的块,就是大括号里面的语句所组成的代码块,比如 function blog(bl) { if (bl) { var foo = "Blog"; } console.log(foo); } blog(true); //=> Blog 2、虽然变量变量foo位于if语句的代码块中,但是 JavaScript 并没有块级作用域的概念,因此被添加到了当前的执行环境 - 即函数中,在函数内都可以访问到。 因此:var 定义的变量是函数级作用域,作用范围是在函数开始阶段和函数执行完成之前内都是存在的; 并且如果该函数内部还存在匿名函数等特殊函数,这个 var 出的变量在匿名函数中任然可以用; 3、在ES出现后,定义了一个新的命名方式 let function Blog(bool) { if (bool) { let foo = "Blog"; } else { console.log(foo); } } Blog(false); //这里会报错 Uncaught ReferenceError: foo is not defined 因此,使用 let,上述问题完全解决,let出的变量作用域是块作用域,在离开某一代码块,该变量就会被销毁不存在 应当尽可能的避免用 var,用 let 来代替,除非你需要用到变量提升。 4、随着面向对象思维的出现,JS也出现了常量的定义 const const 与 let 的基本用法相同,定义的变量都具有块级作用域,也不会发生变量提升。不同的地方在于,const 定义的变量,只能赋值一次。 const foo='Blog'; function Blog(bool) { if (bool) { foo = "Vue"; } else { console.log(foo); } } Blog(true); //这里会报错 Identifier 'foo' has already been declared 因此const多用作不发生变化的变量定义,比如定义月份,或者,星期等:constmonths = []; 三、箭头函数 还记得昨天的那个小demo么,今天再说一个地方 var obj = { data: { books: "", price: 0, bookObj: null }, bind() {//**注意!**ES6 中,可以使用这种方法简写函数,等价于 bind: function () { var that = this; //普通函数 //$(".ok").click(function () { // console.log(this);//这个时候,this,就是 .ok 这个Html标签 // var bookItem = that.data.bookObj; // var _parice = $(bookItem).data("price"); // var _book = $(bookItem).data("book"); // that.data.books += _book + ","; // that.data.price += parseInt(_parice); // that.show(); //}); //箭头函数 $(".ok").click(() => { var bookItem = this.data.bookObj;//在箭头函数中,this指向的是定义函数时所在的对象 var _parice = $(bookItem).data("price"); var _book = $(bookItem).data("book"); this.data.books += _book + ","; this.data.price += parseInt(_parice); this.show(); $(".bg,.popupbox").hide(); }); }, } 在普通的click函数中 this 指向对象 $(".ok") ,因此,我们如果想要获取定义的对象中的数据(obj.data),那我们只能在 click 方法前,就去用一个 that 自定义变量来保存这个 this , 但是在箭头函数中就不一样了,this始终指向定义函数时所在的对象(就是 obj 对象); 是不是更方便些! 在Vue中,也经常使用 vue实例,或者this来获取相应的值 var vm = new Vue({ el:'#root', data:{ tasks:[] }, mounted(){ axios.get('/tasks') .then(function (response) { vm.tasks = response.data;//使用Vue实例 }) }, mounted2(){ axios.get('/tasks') .then(response => this.tasks = response.data);//箭头函数 this } }); 四、参数默认值 && rest参数 1、 在ES6中,可以像C#那样定义默认参数 function buyBook(price, count = 0.9){ return price * count; } buyBook(100); //甚至可以将方法的值赋给参数 function buyBook(price, count =GetCount()){ return price * count; } function GetCount(){ return 100; } buyBook(200); 2、不仅如此,还可以快速获取参数值 //ES6之前是这样的 function add(a,b,c){ let total = a + b + c; return total; } add(1, 2, 3); //ES6你可以这么操作,提供了 rest 参数来访问多余变量 function sum(...num) { let total = 0; for (let i = 0; i < num.length; i++) { total = total + num[i]; } return total; } sum(1, 2, 3, 4, 6); 五、ES6中的表达式 1、字符串表达式 在之前我们都是这样使用字符串表达式 var name = 'id is ' + bid+ ' ' + aid + '.' var url = 'http://localhost:5000/api/values/' + id 在ES6中我们有了新语法,在反引号包裹的字符串中,使用${NAME}语法来表示模板字符: var name = `id is ${aid} ${bid}` var url = `http://localhost:5000/api/values/${id}`//注意是反引号,英文输入下下的,Tab键上边的那个 2、还有就是多行表达式的写法 //之前我们都是这么写的 var roadPoem = '这个是一个段落' + '换了一行' + '增加了些内容' + 'dddddddddd' //但是在ES6中,可以使用反引号 var roadPoem = `这个是一个段落 换了一行 增加了些内容, dddddddddd 结尾,` 六、模块化定义 1、什么是模块化开发 模块化开发是基于一定的语法规范,通过代码书写设计,使代码耦合度降低,模块化的意义在于最大化的设计重用,以最少的模块、零部件,更快速的满足更多的个性化需求。因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。 用阮一峰大神的说法就是: 今天的Web网页越来越像桌面程序,网页上加载的javascript也越来越复杂,前端工程师不得不开始用软件工程的思维去管理自己的代码。Javascript模块化编程,已经成为一个非常迫切的需求。理想情况下,开发者只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块。但是,Javascript不是一种模块化编程语言,它不支持"类"(class),更别提"模块"(module)了。(正在制定中的ECMAScript标准第六版将正式支持"类"和"模块",但还需要很长时间才能投入实用 就这样,Node.js 就出现了,一个用来开发服务器端的js框架,基于commonJs的模块化。当然中间还有CMD,AMD(这个东西我还需要慢慢研究下); 2、模块化在代码中是如何体现的呢 1、首先我们先看看普通的定义一个类是如何写的 新建一个index.js 文件 class Student { constructor(homework= []) { this.homework= homework; } study() { console.log(this.homework); } } const st = new Student ([ 'blog', 'api', 'vue' ]); st.study(); 然后新建一个index.html页面,引用该js文件 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script src="index.js"></script> </body> </html> 然后就可以得到结果: 这是一个很简单的,定义一个Student 类,然后定义一个方法,通过传递一个数组参数,来实例化。 这样虽然很简单,但是却无法复用,无法作为一个零件来使用。而且如果有一个地方要修改,多处都需要修改,这个面向对象的思想,没有发挥出来; 这个时候你可能会说,把这个拆成两个问题,就可以复用了,嗯~试试 2、我们把这两个文件分开 新建一个Student.js ,定义处理Student类;然后新建一个main.js方法,来调用实例化该类,就可以使用 然后在 index.html 页面里去引用这两个文件 <body> <script src="Student.js"></script> <script src="main.js"></script> </body> 当然结果是一样的,这样虽然实现了分隔开,也可以去不同的地方调用; 但是,从上文中你也看的出,如果不是自己写的代码,一般不太容易看的明白,到底是什么意思,直观性不是很好,我们将无法看到彼此间的关联(main.js 加载 Student.js), 3、我们用模块的写法设计这个调用 ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。 我们直接修改之前的代码 然后在 index.html 页面中,只需要引用 就行 4、因为浏览器现在还不能直接运行模块化代码,所以我们需要打包,打包工具有很多,比如webpack 注意:这里用到打包概念,之后会讲到,这里就先略过,以后会讲到,步骤是 首先安装npm,或者阿里镜像cnpm(npm其实是Node.js的包管理工具,这个在我们之后的Node.js环境配置中,自动随带安装)全局安装 rollup.js $ cnpm install --global rollup cd 当前文件夹$ rollup main.js --format iife --output bundle.js 然后只需要引用生成的 5、这里我因为测试,已经生成好了,打包出来的bundle.js 是这样的,是不是兜兜转转又回到了之前的写法,其实ES6的模块开发,就是导入的代码块儿 (function () { 'use strict'; class TaskCollection { constructor(tasks = []) { this.tasks = tasks; } dump() { console.log(this.tasks); } } const tc = new TaskCollection([ 'blog', 'api', 'vue' ]); tc.dump(); }()); 总结来说:模块化的好处和问题 可维护性 灵活架构,焦点分离 方便模块间组合、分解 方便单个模块功能调试、升级 多人协作互不干扰 可测试性,可分单元测试; 性能损耗 系统分层,调用链会很长 模块间通信,模块间发送消息会很耗性能 其实说白了,就是JS在作为一个开发语言来说,越来越靠近了后端服务器语言。 七、每天一个小Demo 这里是一个特别特别简单的关于ES6的留言板,大家可以看一看 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2>简易留言板</h2> <input type="text" placeholder="请输入内容" size="30" id="msg"> <input type="button" value="留言" id="btn"> <div id="msg-div"></div> <script> //let 定义块级变量 let oBtn = document.getElementById('btn'); let msg = document.getElementById('msg'); let content = document.getElementById('msg-div'); oBtn.onclick = () => { let ovalue = msg.value; let ali = document.createElement('p'); //ES6模板字符串 //多行表达式 ali.innerHTML = `${ovalue}<span style="color:red;"> 删除</span>`; var aspan = content.getElementsByTagName('p'); if (aspan.length > 0) { content.insertBefore(ali, aspan[0]); } else { content.appendChild(ali); } msg.value = ''; var oSpan = content.getElementsByTagName('span'); for (let i = 0; i < oSpan.length; i++) { //ES6箭头函数 oSpan[i].onclick = function () { content.removeChild(this.parentNode);//注意this的指向 }; } }; </script> </body> </html> 八、结语 通过这两天的学习,大家了解到了,JS的一些特性和变化:嵌套字面量的定义,面向对象的封装,类和模块化的使用,ES6的日益成熟,通过打包进行发布等等,都能表现出JS在向一个服务器端语言快速迈进的冲动,也是极大的推动了,MVVM的到来,从而实现像Node.js 这种,可以脱离浏览器环境也能运行的不一样视角。好啦,关于JS高阶,这两讲已经差不多了,当然还有其他的,大家可以自行学习了解,其实这两篇都懂的化,已经差不多了,明天咱们就开始正式进入Vue入门篇,通过引用Vue.js 实现栗子。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册