JavaScript 实现二分搜索和快速排序

二分搜索 在计算机科学中,二分搜索(binary search)是一种在有序数组中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半 利用递归实现 /** * 二分查找,递归实现 * @param {*} arr * @param {*} target * @param {*} low * @param {*} high */ function binarySearch(arr, target, low = 0, high = arr.length - 1) { if (low > high) { return -1 } const mid = parseInt((low + high) / 2) if (target < arr[mid]) { return binarySearch(arr, target, low, mid - 1) } if (target > arr[mid]) { return binarySearch(arr, target, mid + 1, high) } return mid } 非递归实现...

April 22, 2019 · 2 min · vdorchan

使用 vue 开发项目遇到的问题总结

开发的项目为:https://github.com/vdorchan/vue-movie,最初使用 vue-cli 2 作为脚手架工具,后又使用 vue-cli 3 重构。 开发过程还是遇到了一些问题,现在试着回想并记录下来。 1、请求接口跨域 接口跨域可以通过 webpack 配置 API 代理解决 webpack 是借助 webpack-dev-server 插件提供开发服务器的,而 webpack-dev-server 使用 http-proxy-middleware 实现跨域代理。 const devWebpackConfig = merge(baseWebpackConfig, { // ... devServer: { // ... proxy: { '/api': { target: 'http://api.douban.com/v2', // 代理的API地址,就是需要跨域的API地址 changeOrigin: true, // 代理的API地址如果是域名就要加这个 pathRewrite: { '^/api': '', }, } } } }) 上面代码涉及到的参数说明: target 为代理的API地址,就是需要跨域的API地址 代理的API地址如果是域名就要加多个参数 changeOrigin: true pathRewrite 是路径重写,也就是说会修改最终请求的API路径,原本访问的是 http://api.douban.com/v2/api/xx,上面代码重写路径后最终访问 http://api.douban.com/v2/xx 2、第二次进入页面不刷新 应用使用了 vue-router,为了避免每次路由变化的时候都重新渲染组件,便配合用上了 keep-alive 组件。...

April 19, 2019 · 1 min · vdorchan

使用 Travis-CI 完成高级的自动化部署

会啰嗦几句简单介绍下然后实战 写代码经常要花很多时间在构建和部署上面,像是我的个人网站、博客系统或者是一些小项目,每次有些改动就得去重新构建生产代码,改完之后还要把它弄上服务器,更新到线上去。 项目一多,改动一多,懒惰的我,就会把它“堆起来”,等一个比较长的开发周期结束之后,再去更新线上。虽然这样减少了更新的次数,但依然还是又累又耗费时间。身为高贵的程序员不能再总是浪费生命干这种活了,必须要找个苦力给我搞定它。 通过 Google 发现 Travis CI 是最合适的选择。 什么是 CI CI 即持续集成服务,是 Continuous Integration 的简称,而 Travis CI 是提供这种服务里面市场份额最大的那个。 之前开发 Electron 应用,需要 windows 环境构建,但因为 Travis CI 不支持 windows 环境,还一起用过 appveyor。appveyor 也是提供 CI 服务的。不过后来看到新闻,说 Travis CI 开始支持 windows 了,不过我还没试过。 持续集成就是在团队开发的时候,成员们持续(频繁)将代码改动集成到主干上去。而每次集成都是通过自动化的构建(包括编译,发布,自动化测试)来验证。 持续集成的好处在于,每次代码的小幅变更,就能看到运行pt addo结果,从而也能尽早的发现集成错误。这样子就能不断累积小的变更,而不是在开发周期结束时,一下子合并一大块代码。 Travis CI 和 Github 账号绑定,你可以选择需要持续集成的项目,之后只要这个项目有代码变动,就会自动抓取,然后提供一个运行环境,执行测试,完成构建,然后也能部署到服务器上去。 .travis.yml 在 官网,点击右上角的个人头像,可以使用 Github 账户登入 Travis CI。然后便可以选择需要同步的项目。 这个同步的项目必须要有一个 .travis.yml 文件,是 Travis.yml 的配置文件,文件格式是 YAML 格式。它指定了 Travis 的行为。该文件必须 push 到 Github 仓库里面,一旦代码仓库有新的 Commit,Travis 就会去找这个文件,执行里面的命令。一般它是下面这样的...

April 18, 2019 · 3 min · vdorchan

通过 certbot 给网站部署 Let’s Encrypt SSL 安全证书

http 不安全 当部署完网站,你迫不及待打开 chrome,输入网站域名,敲下回撤,页面便展现在你的眼前。这时候可能会注意到域名的左边,赫然显示着“不安全”。这太难看了,没法忍。 chrome 显示不安全的其中一个原因就是网站没有配置安全证书,使用的是 HTTP 而不是 HTTPS。 http 是一个传输网页内容的协议,本身不带加密,是明文传输的。而 https 可以理解为“ HTTP over SSL/TLS ”,这是为了安全,为 http 协议上加了一层 SSL/TLS 安全协议。 SSL/TLS 是什么? SSL( Secure Sockets Layer) 和 TLS(Transport Layer Security) 是同一个东西的不同阶段,可以理解为一个东西,都是安全协议。 Secure Sockets Layer 翻译为“安全套接层”,所以 HTTP over SSL/TLS ” 就是带“安全套接层”的 http 协议”,既然带上了“安全套”,那肯定是安全得多了。 如何部署 https ? 部署 https 不仅仅是为了安全,各大互联网企业和一些相关的基金会也在推,可以给一个网站部署 https 几乎是必须的。那么要怎么部署呢? 你只需要有一张被信任的 CA ( Certificate Authority )也就是证书授权中心颁发的 SSL 安全证书,并且将它部署到你的网站服务器上。一旦部署成功后,当用户访问你的网站时,浏览器会在显示的网址前加一把小绿锁,表明这个网站是安全的,当然同时你也会看到网址前的前缀变成了 https ,不再是 http 了。 以前比如 Godaddy 、 GlobalSign 等机构签发的证书一般都很贵,为了推进 https 的普及,EEF 电子前哨基金会、 Mozilla 基金会和美国密歇根大学成立了一个公益组织叫 ISRG ( Internet Security Research Group ),这个组织从 2015 年开始推出了 Let’s Encrypt 免费证书...

April 1, 2019 · 2 min · vdorchan

让人脑壳疼的继承与原型链

JavaScript 的继承是基于原型链实现的。虽然在 ES2015/ES6 中引入了class关键字,但那仅仅是语法糖。 原型链是一种机制,指的是 JavaScript 每个对象都有一个内置的 __proto__ 属性指向创建它的构造函数的 prototype (原型)属性。 比如 function Person() { } var person = new Person() console.log(person.__proto__ === Person.prototype) // true 函数也是对象 普通对象是这样子的: var o1 = {} var o2 = new object() 凡是像下面代码使用 function 关键字或 Fucntion 构造函数创建的对象都是函数对象。只有函数对象才拥有 prototype (原型)对象。 function f1 () {} var f2 = function (){} var f3 = new Function('str', 'console.log(str)') 构造函数和 prototype ECMAScript 中提供了构造函数来创建新对象。构造函数本身就是一个函数,它和普通函数没有任何的区别。 前面示例代码中的 Person 就是一个构造函数,首字母大写并不是它被称为构造函数的原因,这是管理,但不是必须的。 而是因为函数被 new 关键字调用时就是构造函数。 那么当 Person 构造函数被 new 关键字调用的时候都发生了什么呢?...

March 27, 2019 · 4 min · vdorchan

git 提示无法 pull 仓库(refusing-to-merge-unrelated-histories)

背景 在本地完成了一个项目,并使用 git 完成了初始化。 然后想同步到 github 上去,便在 github 上 new repository 创建了一个新的库,并勾选了 Initialize this repository with a README,也就是这个仓库初始化的时候将自动带有一个 Readme.md 文件。 在 github 上创建好 repo 后,接下来的操作自然是将本地仓库 push 到远程仓库上。 因为 github 上的 repo 带有 Readme.md,而本地的没有,所以就需要先将 github 上的 pull 下来。 在执行 git pull 命令后,便出现了一条合并失败的提示。 fatal: refusing to merge unrelated histories 提示的意思是,拒绝合并不相关的历史。 解决 Google 了一下后得知,两个仓库(本地和远程)都有 commit,但是却没有相关联的 commit,因此 git 认为用户应该是填错了 origin,两个仓库并无关联。 这个时候只要给命令加个选项便可以解决问题了(–allow-unrelated-histories)。 git pull origin master --allow-unrelated-historie

November 12, 2018 · 1 min · vdorchan

从 svn 迁移到 git,并保留 commit 日志

之前为公司做了个基于 yeoman 的脚手架工具,公司是使用 svn 做版本控制的,所以这个工具也就使用了 svn 来记录版本。 近期想做个迁移,把它放到 github 上去,这里对迁移过程做个简单的记录。 首先,svn 地址是 http://svn.com.cn/svn/generator-pczt/ (非真实 svn 地址,这里做个举例) 该项目位置在 svn 中的 base repository,因此不涉及到 tags,branches,trunk。 用户映射 按照网上文章,先创建个文件(users.txt),做个用户映射,将 svn 的用户和 git 上的用户关联起来。 chenwudong = vdorchan <vdorchan@gmail.com> git svn clone 按照文档中的命令 # --stdlayout 跟踪标准的Subversion存储库 # -authors-file 指定用户映射的文件 git svn clone --stdlayout --no-metadata -authors-file=users.txt http://svn.com.cn/svn/generator-pczt/ generator-pczt 输入上述的命令后,在 generator-pczt中创建了一个空的 git 仓库,但并没有将文件从 svn 拉下来,并且命令行输出了以下的一些信息。 Initialized empty Git repository in /Users/vdorchan/Documents/www/Learn-Yeoman/generator-pczt/.git/ Using higher level of URL: http://svn.com.cn/svn/generator-pczt => http://svn.com.cn/svn W: Ignoring error from SVN, path probably does not exist: (160013): Filesystem has no item: File not found: revision 100, path '/generator-pczt' W: Do not be alarmed at the above message git-svn is just searching aggressively for old history....

November 9, 2018 · 1 min · vdorchan

Learn-ES6-class-extends

1.简介 Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多 class Point { } class ColorPoint extends Point { } 上面代码,ColorPoint 继承了 Point,因为没有部署代码,所以两个类是完全一样的。 子类必须在 constructor 中调用 super 方法,否则会出错。因为子类没有自己的 this 对象,所以需要 super 方法继承父类的 this 对象。 class ColorPoint extends Point { constructor(x, y, color) { super(x, y) this.color = color; } } ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。 作为子类的默认 constructor 方法 class ColorPoint extends Point { } class ColorPoint extends Point { constructor(...args) { super(...args) } 下面代码中,实例对象cp同时是ColorPoint和Point两个类的实例,这与 ES5 的行为完全一致。 let cp = new ColorPoint(25, 8, 'green'); cp instanceof ColorPoint // true cp instanceof Point // true 最后,父类的静态方法,也会被子类继承。...

March 9, 2018 · 2 min · vdorchan

Learn-ES6-Class

1.简介 JavaScript 语言中,传统的生成实例对象的方法是通过构造函数 。 function Person(name, age) { this.name = name this.age = age } Person.prototype.say = function () { console.log('my name is ' + this.name + ', i am ' + this.age + ' years old') } var person = new Person('kobe', 30) person.say() // my name is kobe, i am 30 years old ES6 引入了 Class (类)这个概念,通过 class 关键字可以定义类,写法和其它传统语言类似,可以看作是一个语法糖,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法。 class Person { contructor(name, age) { this.name = name this....

March 8, 2018 · 5 min · vdorchan

Learn-ES6-generator

1. generator Generator 函数可以理解成是一个状态机,封装了多个内部状态。 执行 Generator 函数可以返回一个遍历器对象,所以说,Generator 函数还是一个遍历器对象生成函数。返回的bi an li qi

February 26, 2018 · 1 min · vdorchan