<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[qiyuancoder的博客]]></title><description><![CDATA[]]></description><link>https://blog.youkuaiyun.com/qiyuancoder</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; qiyuancoder]]></copyright><item><title><![CDATA[函数式编程（四）：函数组合、函子]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/112169249</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/112169249</guid><author>qiyuancoder</author><pubDate>Mon, 04 Jan 2021 11:33:43 +0800</pubDate><description><![CDATA[函数组合
纯函数和柯里化很容易写出洋葱代码 h(g(f(x)))，就是一个函数镶嵌另一个函数，多重组合，最终实现我们想要的功能，就像下面这个洋葱一样：

函数组合，就是利用多个函数，把细粒度的函数重新组合生成一个新的函数，从而实现我们想要的逻辑。
比如：获取数组的最后一个元素再转换成大写字母， .toUpper(.first(_.reverse(array)))
管道
下面这张图表示程序中使用函数处理数据的过程，给 fn 函数输入参数 a，返回结果 b。可以想想 a 数据通过一个管道得到了 b 数据：

当]]></description><category></category></item><item><title><![CDATA[函数式编程（三）：纯函数、柯里化]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/112135545</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/112135545</guid><author>qiyuancoder</author><pubDate>Mon, 04 Jan 2021 10:05:26 +0800</pubDate><description><![CDATA[纯函数
什么是纯函数呢？就是很纯的，没有副作用的函数… …
什么是副作用呢，就是那个，吃药的时候，说明书上写明可能产生副作用的那些不正常的作用，这个就是副作用…
好多的废话，看代码吧
简单的纯函数：
// 一个简单的纯函数
function add(a, b) {
    return a + b
}

// 调用
let sum = add(1, 2)

上面的函数，无论怎么调用，都不会对其他地方产生影响，且对于相同的输入，永远都有相同的输出。
这个就是纯函数。
那么不纯的函数是什么样呢，大概有以下几种：]]></description><category></category></item><item><title><![CDATA[函数式编程（二）：闭包]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/112132956</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/112132956</guid><author>qiyuancoder</author><pubDate>Sun, 03 Jan 2021 15:27:53 +0800</pubDate><description><![CDATA[闭包这词估计已经听烂了，这里随便再复习下它的概念。
闭包 (Closure)：函数和其周围的状态(词法环境)的引用捆绑在一起形成闭包。
特点1：可以在另一个作用域中调用一个函数的内部函数并访问到该函数的作用域中的成员。
上文提到的，函数作为返回值和那个支付的例子，就是闭包：
function makeFn() {
    let msg = 'Hello function'
    return function () {
        console.log(msg)
    }
} 
const fn]]></description><category></category></item><item><title><![CDATA[函数式编程（一）：前言、高阶函数]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/112122350</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/112122350</guid><author>qiyuancoder</author><pubDate>Sun, 03 Jan 2021 11:34:06 +0800</pubDate><description><![CDATA[前言
什么是函数式编程呢？ennn…，其实就是一种编程思想，和面向对象编程、面向过程编程是一样的，这玩意一开头说一大堆也不好，先来说说为毛要学函数式编程。
因为将来要学习 React 和 vue 以及剖析其源码，避免不了和函数式编程思想接触。
那函数式编程到底有什么好处呢，主要有如下几点：

不容易产生bug，方便测试和并行处理；
可以抛弃this，避免被this指向弄晕；
打包过程中可以更好的利用 tree shaking 过滤无用代码；
有很多库可以帮助我们进行函数式开发，比如经典的lodash。

来]]></description><category></category></item><item><title><![CDATA[JavaScript异步编程（五）：async、宏任务、微任务]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/112116566</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/112116566</guid><author>qiyuancoder</author><pubDate>Sat, 02 Jan 2021 20:35:41 +0800</pubDate><description><![CDATA[Promise 虽然主要是用来处理异步任务的，但我们深入理解 Promise 并不是纯为了来处理异步任务，因为在 ES7 里的 async 和 wait 能更简单的处理异步任务：
// 一个异步任务，在time毫秒后返回一个状态为reject的Promise对象
function ajax(time) {
    return new Promise((resolve, reject) =&gt; {
        setTimeout(() =&gt; {
            resolve(`完成]]></description><category></category></item><item><title><![CDATA[JavaScript异步编程（四）：并行执行、超时处理]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/112103320</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/112103320</guid><author>qiyuancoder</author><pubDate>Sat, 02 Jan 2021 18:47:19 +0800</pubDate><description><![CDATA[并行执行
或许，可能有遇到过这样的需求：

一个接口的参数是由其他三个接口的返回值组合而成，因此这个接口必须要保证在另外三个接口完成之后才能被调用；
在echarts的图表中，一个图表中可以有好几组数据，每组数据都由一个接口返回，根据echarts使用规则，必须得这几个接口都请求完成之后才渲染图，比如下面这个，有四组数据在同一个echarts表里：

以上两种情况，都是需要在某几个接口请求完毕之后再执行另一个接口。
这个涉及到并行执行的概念，Promise.all() 刚好可以解决这个问题。
上代码：
//]]></description><category></category></item><item><title><![CDATA[JavaScript异步编程（三）：Promise异常处理]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/112099408</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/112099408</guid><author>qiyuancoder</author><pubDate>Sat, 02 Jan 2021 16:12:34 +0800</pubDate><description><![CDATA[异常处理
接上文，Promise中的方法没法保证不出错误，一旦报错，我们必须捕获错误来观察是哪里出了错。
我们故意不传参，制造一个错误来看看：
function ajax(param) {
    return new Promise((resolve, reject) =&gt; {
        setTimeout(() =&gt; {
            if (param) {
                resolve(param)
            } else {
     ]]></description><category></category></item><item><title><![CDATA[JavaScript异步编程（二）：Promise基础回顾]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/112071651</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/112071651</guid><author>qiyuancoder</author><pubDate>Sat, 02 Jan 2021 13:22:49 +0800</pubDate><description><![CDATA[Promise相关概念和用法简要回顾：
Promise语义理解为承诺，承诺一件事情，这件事情，要么成功，要么失败。放在ajax的处理上，就是ajax请求成功了，
最基本的示例：
let promise = new Promise((resolve, reject) =&gt; {
    let flag = true
    if (flag) {
        resolve('成功了')
    } else {
        reject('失败了')
    }
})

promise.the]]></description><category></category></item><item><title><![CDATA[JavaScript异步编程（一）：同异步执行原理过程]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/112063923</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/112063923</guid><author>qiyuancoder</author><pubDate>Fri, 01 Jan 2021 21:31:15 +0800</pubDate><description><![CDATA[JavaScript（以下简称js）是单线程语言，也就是说在js代码执行环境中，执行代码的线程只有一个，因为设计初衷就是为了操作DOM元素，假设js是多线程语言，那么如果两个线程任务同时操作一个DOM元素，一个修改一个删除，浏览器将不知道以哪个为准。
既然js是单线程语言，所以有多个任务时（先不考虑异步），只能排队一个个按顺序执行。
优点：安全简单；缺点：一个任务耗时阻塞，后面的任务都会只能在等待，无法执行。
为解决异步请求、文件加载等耗时长的任务阻塞后边任务的问题，js执行模式分为同步模式和异步模式。
同]]></description><category></category></item><item><title><![CDATA[手写Promise源码（一）]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/112061792</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/112061792</guid><author>qiyuancoder</author><pubDate>Fri, 01 Jan 2021 18:02:05 +0800</pubDate><description><![CDATA[驱蚊器二]]></description><category></category></item><item><title><![CDATA[history详解]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/109697218</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/109697218</guid><author>qiyuancoder</author><pubDate>Sun, 15 Nov 2020 13:40:33 +0800</pubDate><description><![CDATA[history 对象包含用户在浏览器中访问过的页面的URL，自带的属性和方法如下：
history.length
历史页面的URL数量，最小为1，最大为，即只能存50个历史页面记录。
history.back()、history.forward()、history.go()
分别表示跳转至上一个页面、下一个页面、指定的上下某个页面，history.go(-1) 等同于 history.back()，history.go(1) 等同于 history.forward()，history.go(0) 等同于当前]]></description><category></category></item><item><title><![CDATA[路由（Router）原理极简说明]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/109687477</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/109687477</guid><author>qiyuancoder</author><pubDate>Sat, 14 Nov 2020 19:46:48 +0800</pubDate><description><![CDATA[在各种框架中，路由的实现主要有两种方式：

用 hashchange 事件监听 url 来实现；
用 history.pushState() + popstate 来实现。

先看第一种，用 hashchange 实现路由相当简单：
// html
&lt;a href="#/"&gt;首页&lt;/a&gt;
&lt;a href="#/blog"&gt;博客&lt;/a&gt;
&lt;a href="#/college"&gt;学院&lt;/a&gt;

当点击 a 标签，hash 值发生变化，触发事]]></description><category></category></item><item><title><![CDATA[用人话说清bind]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/109684261</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/109684261</guid><author>qiyuancoder</author><pubDate>Fri, 13 Nov 2020 23:54:28 +0800</pubDate><description><![CDATA[bind 常见应用情形主要有两种：

改变 this 指向；
参数固化（又叫偏函数，可理解为函数柯里化的简单应用）。

第一种情形很简单，demo如下：
const cat = {
    name: 'xiaoJu',
    say: function () {
        console.log(this.name)
    }
}

cat.say();	  // xiaoJu

const otherCat = {
    name: 'daHuang'
};
cat.say.bind(oth]]></description><category></category></item><item><title><![CDATA[v-for 和 v-if 同时使用的问题]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/109607677</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/109607677</guid><author>qiyuancoder</author><pubDate>Tue, 10 Nov 2020 23:25:00 +0800</pubDate><description><![CDATA[假设有如下数组，需要将数组中的num渲染至页面中，同时遵循条件：对应的show值为true才渲染，为false就不渲染。
numArr: [
	{ num: 1, show: true },
	{ num: 2, show: false },
	{ num: 3, show: true },
	{ num: 4, show: true },
	{ num: 5, show: false },
	{ num: 6, show: true },
	{ num: 7, show: false },
	{ num:]]></description><category></category></item><item><title><![CDATA[textarea实现高度自适应的理解]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/109540643</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/109540643</guid><author>qiyuancoder</author><pubDate>Fri, 06 Nov 2020 23:53:49 +0800</pubDate><description><![CDATA[今天遇到个需求：要求 textarea 初始只显示一行，当用户输入内容过多引起换行，或者手动敲回车键换行时，textarea 内容区域自动撑开。
这个简单，于是我敲下大致如下代码：
// html
&lt;textarea id="codePath" rows="1"&gt;&lt;/textarea&gt;

// js
let codePath = document.getElementById('codePath');

codePath.addEventListener('input', funct]]></description><category></category></item><item><title><![CDATA[flex知识回顾]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/109522291</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/109522291</guid><author>qiyuancoder</author><pubDate>Thu, 05 Nov 2020 23:51:12 +0800</pubDate><description><![CDATA[先看几个小栗子：
1、在没有任何样式的情况下，常规布局下，有默认间距：

如果将 input 和 button 的父 div 设置 display: flex，则如下：

2、常规布局下，如果想让按钮局最右边，左边输入框自动填满剩余宽度，会有些麻烦：

flex 布局，只需父元素将按钮设置display: flex，input设置 flex: 1 即可：

3、常规布局：想做到图片和输入框无间距同高度，会有些麻烦：

flex 布局，只需父元素设置 display: flex 即可：

正文开始：
flex]]></description><category></category></item><item><title><![CDATA[如何编写高质量js代码]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/109497835</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/109497835</guid><author>qiyuancoder</author><pubDate>Wed, 04 Nov 2020 23:36:50 +0800</pubDate><description><![CDATA[本文纯属个人观点，想到什么写什么，自然也有不全面的地方，先流水账似的列一下，后续不定期更新，察觉漏了什么就补上。
1、命名要具有语义化

函数名用动词，比如 function getUserInfo(){ } ，能从名字上大体看出这个函数实现了什么逻辑；
变量用名词，比如 let sex = ‘男’，能从名字上看出这个变量代表什么；
布尔值用 is 开头，比如 let isLoaded = false ，能从名字上看出这个布尔值判断的是什么；

附：变量、对象、数组等在被声明的同时，最好赋一个初始值，字符串]]></description><category></category></item><item><title><![CDATA[Vue全局组件之install/use]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/109480433</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/109480433</guid><author>qiyuancoder</author><pubDate>Tue, 03 Nov 2020 23:34:16 +0800</pubDate><description><![CDATA[在vue项目里的main.js里，往往会见到vue.use(xx)的写法，比如司空见惯的路由模块：
import VueRouter from 'vue-router'
Vue.use(VueRouter)

其实路由也就是vue的一个插件，这里被use进来，便成了一个全局组件，全局组件可以在任何地方不需要import而直接使用。
相关知识点：用 install(){ } 和 vue.use() 配合来开发和引入全局组件，在 install(){ } 中vue.component(‘name’, compo]]></description><category></category></item><item><title><![CDATA[闭包中return的作用分析]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/109459245</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/109459245</guid><author>qiyuancoder</author><pubDate>Mon, 02 Nov 2020 22:58:45 +0800</pubDate><description><![CDATA[今日有入坑不久的小伙伴表示对闭包中return还不是很理解，这里用个简单的例子说明，先看下面的代码：
// html代码
&lt;input type="text" id="name" &gt;

// js代码
var input = document.querySelector('#name');
input.addEventListener('input', function () {
    console.log(this.value)
})

这里没有任何难理解的地方，就是监听input的输入事]]></description><category></category></item><item><title><![CDATA[基本数据类型和引用数据类型存储的方式及复制]]></title><link>https://blog.youkuaiyun.com/qiyuancoder/article/details/109409434</link><guid>https://blog.youkuaiyun.com/qiyuancoder/article/details/109409434</guid><author>qiyuancoder</author><pubDate>Sat, 31 Oct 2020 23:57:27 +0800</pubDate><description><![CDATA[看以下现象：
var obj = { a: 2 };
var obj2 = obj1;
obj2.a = 3;

obj		// { a: 3 }
obj2	// { a: 3 }

这种现象大家都不陌生，因为obj和obj2指向的是同一个对象，两者相互影响，那如果再往深处挖掘，这是一个什么样的过程呢，这个涉及到栈堆存储的概念。
在js中，按存储方式可将数据类型分为两种：一是基本数据类型（string、number、undefined、null、oolean），二是引用数据类型（object）。
基本数据类]]></description><category></category></item></channel></rss>