言川

Results 54 issues of 言川

收集已经上线的案例,定期更新到官网上,案例地址:http://lihongxun945.github.io/jquery-weui/cases 回复的时候,最好包含以下三个内容: 1. 公众号名称,或者链接 2. 图标或者首页截图 3. 简单的一句话介绍

help wanted

## 数组不是数组 为什么数组不是数组呢?因为JS中一切皆对象,所以数组其实是对象。当然这只是个段子。这里说的数组不是数组的含义是:**JS数组在内存中的存储方式不同于我们在数据结构课程上学习的数组**。 数据结构中的数组是指**存储在一个连续的内存空间中的具有相同类型的数据集合**。 首先我们可以看看TC39中对数组的定义: > Arrays are exotic objects that give special treatment to a certain class of property names > 数组是一个对一类属性做了特殊处理的奇异对象 > https://tc39.es/ecma262/#sec-array-objects 简化一下,可以理解为“**数组是对象**”,不过这个对象是“奇异对象”。这也比较符合我们的直观理解,因为我们可以给数组存放不同类型的数据,也可以随意添加属性,这些显然是一个对象的性质,比如: ```javascript const a =...

## Vue3响应式系统设计理念 先说点题外话,`Vue3` 正式发布之后,我面试的时候如果发现对方简历写有“精通Vue”之类的话,一般都会问一问`Vue3`相对`Vue2`有哪些变化,很多人只能答上来一点就是响应式从 `defineProperty`变成了 `proxy`。其实`Vue3`是一次比较大的重构,变化的地方非常多,举几个重要的点: - mono repo 设计:源码分成了十几个比较独立的模块,减少了代码耦合,部分模块可以独立使用也可以换成其他的实现版本 - 编译时优化:在编译阶段对模板中动态内容和静态内容进行打标,并对动态内容进行分块(block),在运行时仅更新分块之后的动态部分,大幅提升更新效率 - 组合式API:全新的组合式API,提供类似 React Hooks的全新语法 上面的题外话有助于理解接下来的内容。回到本文议题,在`Vue3`中响应式模块其实有两个层次的变化: 1. 内部实现从`definePropery`变成了 `proxy`,规避了一些老版本难以解决的bug 2. `reactivity`变成了一个功能完善的有明确API定义的独立模块,而不是耦合在Vue源码中,这就意味着我们可以在任何项目中引入 `reactivity`不需要依赖`Vue`框架 既然是一个独立的模块,那么它就会有自己完整的设立思路。响应式系统的设计思路是什么?总结为一句话就是:***在目标发生变化时,执行对应的函数***。顺着这个思路,我们就可以定义出响应式系统的几个要素: 1. 需要定义被监听的目标和执行的函数,我们统一把这两个对象称为`target`和 `effectFn` 2. 需要建立`target`和 `effectFn`之间的关联,当...

每周学习笔记

## 问题 前端同学们依然会有很多时候会碰到需要使用定时器的场景,比如轮播动画、轮询数据等。很多时候大家都是随手写一个 `setInterval` 来完成需求。 比如下面的一个典型的计时器场景: ```typescript function App() { const [count, setCount] = useState(0); useEffect(() => { setInterval(() => { setCount(count + 1); }, 1000); }, []); return (...

每周学习笔记

## 认识javascript modules `Vite` 主要是用了 `js modules`,在认识 `vite` 之前,我们先简单学习一下 `javascript modules`。 MDN 的 `javascript modules` 文档 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#aside_%E2%80%94_.mjs_versus_.js 简单的说,支持`javascript modules`的浏览器,可以通过`script`标签引入一个 `esm` 模块,并且支持其中的`import`和 `export`语法,在解析到对应的语法后会在浏览器中动态加载对应的js文件。 我们写一个简单的测试应用来理解什么是 `javascript modules`,代码都在这里 https://github.com/lihongxun945/javascript-modules-test 入口文件 `index.html`,通过`script`标签加载一个模块: ```js ```...

每周学习笔记

# 剪枝是必须的 上一篇讲了极小化极大值搜索,其实单纯的极小化极大值搜索算法并没有实际意义。 可以做一个简单的计算,平均一步考虑 50 种可能性的话,思考到第四层,那么搜索的节点数就是 `50^4 = 6250000`,在我的酷睿I7的电脑上一秒钟能计算的节点不超过 5W 个,那么 625W 个节点需要的时间在 100 秒以上。电脑一步思考 100秒肯定是不能接受的,实际上最好一步能控制在 5 秒 以内。 顺便说一下层数的问题,首先思考层数必须是偶数。因为奇数节点是AI,偶数节点是玩家,如果AI下一个子不考虑玩家防守一下,那么这个估分明显是有问题的。 然后,至少需要进行4层思考,如果连4四层都考虑不到,那就是只看眼前利益,那么棋力会非常非常弱。 如果能进行6层思考基本可以达到对战普通玩家有较高胜率的水平了(普通玩家是指没有专门研究过五子棋的玩家,棋力大约是4层的水平),如果能达到8层或以上的搜索,对普通玩家就有碾压的优势,可以做到90%以上胜率。 # Alpha Beta 剪枝原理 Alpha Beta 剪枝算法是一种安全的剪枝策略,也就是不会对棋力产生任何负面影响。它的基本依据是:棋手不会做出对自己不利的选择。依据这个前提,如果一个节点明显是不利于自己的节点,那么就可以直接剪掉这个节点。 前面讲到过,AI会在MAX层选择最大节点,而玩家会在MIN层选择最小节点。那么如下两种情况就是分别对双方不利的选择:...

五子棋AI教程第二版

# AI没有找到最优解 按照前面的所有算法实现之后,会发现一个比较严重的问题,就是电脑在自己已经胜券在握的情况下(有双三之类的棋可以走),竟然会走一些冲四之类的棋来`调戏`玩家。这种走法出现的本质就是因为现在的AI只比较最终结果,并没有考虑到路径长短。所以很容易出现在6层搜索到一个双三,其实在4层的时候也有一个双三,因为分数一样,AI会随机选择一个走法。就导致了明明可以两步赢的棋,AI非要走3步,对玩家来说,感觉就是在调戏人。 所以这里我们定义一个`最优解`的概念:分数最高的走法中路径最短的那一个走法。那么现在问题就是我们如何找到最优解。 # 迭代加深 我们通过AB搜索能够找到所有的最高分走法,一个直观的想法就是我们把所有走法都找到,然后比较他们的长度,选择长度最短的走法。 这确实是一个方法,但是我们可以有效率更高的做法,就是通过`迭代加深` 来优先找到最短路径。 所谓迭代加深,就是从2层开始,逐步增加搜索深度,直到找到胜利走法或者达到深度限制为止。比如我们搜索6层深度,那么我们先尝试2层,如果没有找到能赢的走法,再尝试4层,最后尝试6层。我们只尝试偶数层。因为奇数层其实是电脑比玩家多走了一步,忽视了玩家的防守,并不会额外找到更好的解法。 所以实现这个算法是非常简单的: **negamax.js** ```js var deeping = function(board, deep) { deep = deep === undefined ? config.searchDeep : deep; //迭代加深 //注意这里不要比较分数的大小,因为深度越低算出来的分数越不靠谱,所以不能比较大小,而是是最高层的搜索分数为准...

五子棋AI教程第二版

## 复现问题 从一个最简单的demo开始,计算按钮的点击次数: ```javascript function App() { const [count, setCount] = useState(0) const update = () => { setCount(count+1) } return ( COUNT: {count} + ) } ``` 这样肯定是没有问题的,点击按钮可以正常计数。如果这个时候我们将需求改一下,每秒钟要自动计数一次,那么代码就变成这样了: ```javascript...

每周学习笔记

# 为什么出第二版 在 2016年2月的时候,我写了第一版的五子棋AI教程。当时是边写代码边写博客,因此出现了一些理解上有偏差的地方,以及文章中的代码片段和最终的代码有很多不一致的地方。经过两年多的时间,断断续续更新了好多次代码,电脑的棋力更强了,我对AI的理解也更深入了,期间也学习了一些神经网络的知识。因此,我就打算把陈旧的教程完整的更新一遍,主要目的是更新其中的一些错误,以及加入一些新的知识。因为这是我已经完成了代码后写的,所以质量会比之前一边摸索一遍写要高出很多。无论你有没有看过我的第一版的教程,都推荐你看看这个新版教程。 第一版教程的地址:https://blog.csdn.net/lihongxun945/article/category/6089493 本文章的所有代码都是开源的,代码地址: https://github.com/lihongxun945/gobang 我的五子棋AI在线地址,任何现代浏览器打开地址就可以玩: http://gobang.light7.cn/ ![ss](https://raw.githubusercontent.com/lihongxun945/myblog/master/images/gobang/ss.PNG) # 教程大纲 这篇教程主要会讲解如下几个方面: 1. 博弈算法基础知识 2. 局势评估 3. 极小化极大值搜索 4. Alpha-Beta 剪枝 5. 迭代加深 6. Zobrist缓存 7. 启发式评估函数 8. 算杀...

五子棋AI教程第二版

这里分析的是当前(2018/07/25)最新版 `V2.5.16` 的源码,如果你想一遍看一遍参阅源码,请务必记得切换到此版本,不然可能存在微小的差异。 ![](https://raw.githubusercontent.com/lihongxun945/myblog/master/images/vue2/vue-tree.png) 大家都知道,我们的应用是一个由Vue组件构成的一棵树,其中每一个节点都是一个 Vue 组件。我们的每一个Vue组件是如何被创建出来的,创建的过程经历了哪些步骤呢?把这些都搞清楚,那么我们对Vue的整个原理将会有很深入的理解。 从入口函数开始,有比较复杂的引用关系,为了方便大家理解,我画了一张图可以直观地看出他们之间的关系: ![modules](https://raw.githubusercontent.com/lihongxun945/myblog/master/images/vue2/modules.png) # 创建Vue实例的两步 我们创建一个Vue实例,只需要两行代码: ```js import Vue from ‘vue' new Vue(options) ``` 而这两步分别经历了一个比较复杂的构建过程: 1. 创建类:创建一个 `Vue` 构造函数,以及他的一系列原型方法和类方法 2. 创建实例:创建一个 `Vue` 实例,初始化他的数据,事件,模板等 下面我们分别解析这两个阶段,其中每个`阶段`...

Vue2.x源码解析系列