-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
168 lines (168 loc) · 49.3 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[node爬虫的简单实现方式]]></title>
<url>%2F2018%2F10%2F14%2Fnode%E7%88%AC%E8%99%AB%E7%9A%84%E7%AE%80%E5%8D%95%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F%2F</url>
<content type="text"><![CDATA[目的:获取安卓和苹果的AppStore热门应用图标数据来源:talkingdata苹果市场,华为安卓应用市场用到的模块:superagent,cheerio 并分别针对后台渲染和前台渲染两种情况进行了处理1,后台渲染只能通过后台生成的html页面获取数据,借助cheerio解析页面dom成特定数据格式,后期用类jQuery形式处理dom,需要手动更改url参数(page分页);2,前端渲染直接对接口返回数据进行处理,接口数据抓取是自动分页执行 Github地址 最终下载的图标:]]></content>
<tags>
<tag>node</tag>
<tag>爬虫</tag>
</tags>
</entry>
<entry>
<title><![CDATA[深入理解JavaScript中call的this指向]]></title>
<url>%2F2018%2F06%2F09%2FJavaScript%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3call%E4%B8%ADthis%E6%8C%87%E5%90%91%2F</url>
<content type="text"><![CDATA[想要深入了解 JavaScript 这门语言,一个必须掌握的知识点就是对 this 的理解。其中, call 和 apply 又与 this 有着密切的联系。趁现在有空,在网上看了一些教程之后,自己根据印象将其整理在这篇博文中。 this 是什么this 是 JavaScript 中的一个关键字。它用在对象的方法中。 this 总是指向调用该方法的对象。举个最简单的例子: 当 this 在对象的方法中12345678var obj = { name : 'object', sayName : function () { alert(this.name); }};obj.sayName(); // object 可以看出,当对象 obj 调用 sayName 这个方法时,this 指向的是 obj 。故 alert(this.name)结果会是 object。即,当 this 出现在对象的方法中时,执行该方法时 this 指向的是这个对象本身。接下来看看另外一个例子。 当 this 在函数里面12345var test = function () { this.message = 1;}test(); alert(window.message); //1 可以看出,在直接调用函数时,函数内部的 this 指向的是全局对象。在这个例子中,全局对象是 window ,也就是这个例子是在浏览器中的情况。将例子稍微变形一下,可以更直观地看出 this 是指向全局对象。1234567var message = "hi";var test = function () { alert(this.message);}test(); // hi 上面的例子展示了当直接调用函数时,函数内部 this 的指向总是指向全局对象。接下来来看看构造函数中的 this 指向的是什么。 当 this 在构造函数里面1234567var name = "global"; function Person () { this.name = "someone";}var sam = new Person(); alert(sam.name); // someone 以上代码很清楚的展示了构造函数中 this 的指向问题。当声明一个构造函数的实例时,构造函数内部的 this 都会指向新的实例。所以,在执行 var sam = new Person() 这条语句时, this 指向 sam,所以此时 sam.name = “someone”。 this 出现的位置大概有以上几种情况。另外,JavaScript 中的 call 和 apply 方法也和 this 有着密切的联系。接下来来看看 call 和 apply 的情况。 call 与 apply 是什么call 方法应用于 Function 对象。语法为1call([thisObj[,arg1[, arg2[, [,.argN]]]]]) 参数 解释thisObj 可选项。将被用作当前对象的对象。arg1, arg2, , argN 可选项。将被传递方法参数序列。 说明:call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。 apply和call两者在作用上是相同的,但两者在参数上有区别的。对于第一个参数意义都一样,但对第二个参数:apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,而call则作为call的参数传入(从第二个参数开始)。如 func.call(func1,var1,var2,var3)对应的 apply 写法为:func.apply(func1,[var1,var2,var3])。本文以 call 为例。 上面的文字应该可以很好的理解。但是想真正的掌握 call 还是得认真地研究一下才行。来看例子: 在 call 传入对象123456789var sayName = function () { alert(this.name);}var peter = { name: "peter"}sayName.call(peter); //peter 上面这个例子可以很直观地理解 call 的工作原理。也就是说,当在函数中调用 call 这个方法时,函数内部的 this 对象会自动指向 call 方法中的第一个参数。在上面这个例子中也就是 peter 这个对象了。所以在执行 sayName.call(peter) 时,函数内部的 this.name 则会自动指向 peter.name 。故最终结果为 peter。这是一个非常好理解的例子。接下来来看较为复杂的情况。12345678910111213141516function Person1 () { this.name = "person1"; this.sayName = function () { alert(this.name); }}function Person2 () { this.name = "person2";}var sam = new Person2();Person1.call(sam);sam.sayName(); //person1 以上例子中,最关键的是 Person1.call(sam) 这一步。我们来看看在里面究竟发生了什么事。当调用 call这个方法时,函数 Person1 内部的 this 指向 sam 这个对象。相当于,给 sam 这个对象执行这两条语句:1234this.name = "person1"; this.sayName = function () { alert(this.name)} 故在此重写了原来 sam 对象中的 name 属性。而且获得了一个新的方法。所以可以成功的调用 sam.sayName() 而且结果返回 person1 。 在 call 中传入函数12345678910111213function class1 () { this.message = "yeah";}function class2 () { this.sayMessage = function () { alert(this.message); }}class2.call(class1); alert(class1.sayMessage); class1.sayMessage(); //undefined 上述例子中,我们调用了 class2 函数的 call 方法,传入了 class1 这个函数。结果 class1 拥有了 sayMessage 这个方法。但是直接调用这个方法返回的结果却是 undefined 而不是我们期望的 yeah 。这是为什么呢?为了搞清楚这里面的 this 指向,我们作如下修改:1234567891011121314151617181920var message = "hi";function class1 () { this.message = "yeah";}function class2 () { this.message = "hello"; this.sayMessage = function () { alert(this.message); }}class2.call(class1); alert(class1.sayMessage); class1.sayMessage(); // helloclass1.message = "msg";class1.sayMessage(); //msg 第一次调用 sayMessage 方法,返回 hello 。我们再来看一下 class2.call(class1) 这个过程。当执行这个方法时,class1 获得 class2 的 message 属性和 sayMessage 方法。所以此时有 class1.message = “hello” ,class1.sayMessage = function () {alert(this.message)}。因此执行 sayMessage 时返回 hello。当我们手动修改 class1.message 时,再调用这个方法,返回的值为我们修改的值。这证明了我们上面的推理是正确的。 我们再来看前一个例子。12345678910111213function class1 () { this.message = "yeah";}function class2 () { this.sayMessage = function () { alert(this.message); }}class2.call(class1); alert(class1.sayMessage); class1.sayMessage(); //undefined 这个例子中并没有定义 class1.message 这个属性。所以执行 sayMessage 方法时,返回为未定义。有个比较容易混淆的地方是, class1中定义的 this.message 并不是 class1.message 。而是 class1 的实例才拥有这个 message 属性。 类似的例子还有下面这个:123456789function Class1(){ this.showTxt = function(){alert(this.name)}}function Class2(){ this.name = 'class2';}var class1 = new Class1(); class1.showTxt.call(Class2);//undefined alert(Class2.showTxt);//undefined 原因与上面的例子一样。 Class2 并没有定义 name 这个属性。 Reference阮一峰:Javascript的this用法 郭培:Javascript中call的使用]]></content>
</entry>
<entry>
<title><![CDATA[ES6转ES5小记]]></title>
<url>%2F2017%2F09%2F03%2FES6%E8%BD%ACES5%E5%B0%8F%E8%AE%B0%2F</url>
<content type="text"><![CDATA[ES6解决了ES5的好多坑,项目中也用了很多ES6语法,就是有些语法浏览器不支持。所以想用ES6只能转,我项目用的gulp构建,所以首先就想到用gulp实现自动将ES6转成ES5,转换的过程通过babel来实现,gulp负责实时监听代码变化并调用babel完成转换任务,于是有了下面的一个方案: gulp + babel 编译1. 安装gulp, gulp-babel, babel-core, babel-preset-es2015,1npm install --save-dev gulp 1npm install --save-dev gulp-babel 1npm install --save-dev babel-core 1npm install --save-dev babel-preset-es2015 2. 配置gulp,在根目录下新建gulpfile.js文件12345678910var gulp = require("gulp"); var babel = require("gulp-babel"); gulp.task("default", function () { return gulp.src("js**/*.js")// ES6 源码存放的路径 .pipe(babel({ presets: ['es2015'] })) .pipe(gulp.dest("dist")); //转换成 ES5 存放的路径 }); ES6例子:12let arr = [{a:1,b:2},{a:3,b:2}]let targetItem = arr.find((item) => item.a == 1) 转换后的es5:1234var arr = [{ a: 1, b: 2 }, { a: 3, b: 2 }];var targetItem = arr.find(function (item) { return item.a == 1;}); 至此,已经能实现项目中大部分ES6转成ES5的需求,但是还有一些新的api,babel是不转换的,细心的你肯定已经发现,上述例子中babel只是转换了let和箭头函数,并没有转换ES6为Array新增的find()函数,类似这样的api还有很多,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。如果想让这些没转换的方法运行,需要使用babel-polyfill,为当前环境提供一个垫片。polyfill相当于用来实现浏览器不支持原生功能的代码 3. babel-polyfill扩展新的API安装命令:1$ npm install --save babel-polyfill 然后,在脚本头部引入123import 'babel-polyfill';// 或者require('babel-polyfill'); 这样在项目中就可以愉快的书写ES6代码了,由于babel-polyfill并不是真正意义上将ES6转换成ES5,引入的体积也比较庞大,所以不推荐用polyfill,正常到第2步就可以了。]]></content>
</entry>
<entry>
<title><![CDATA[常用Git命令汇总]]></title>
<url>%2F2017%2F07%2F09%2F%E5%B8%B8%E7%94%A8Git%E5%91%BD%E4%BB%A4%E6%B1%87%E6%80%BB%2F</url>
<content type="text"><![CDATA[Git常用的就那几个命令,本来不需要特地总结,但偏也有没按套路走瞎折腾的时候,这时候就会用到其他一些不常用命令来补救,不常用的就爱忘,省的每次都到处找。就都总结在这里吧,以后遇到不常用但有场景用过的就来更新一次。 首先还是常用的那几个1, git init 仓库初始化12345$ git init //在当前目录新建一个Git代码库$ git init [project-name] //新建一个目录,将其初始化为Git代码库$ git clone [url] //下载一个项目到本地 2, git add 文件添加到暂存区,等待提交12345$ git add [file] //添加指定文件到暂存区$ git add [dir] //添加指定目录到暂存区,包括子目录$ git add * //添加当前目录的所有文件到暂存区 3, git commit 代码提交123$ git commit [file] -m [message] //提交暂存区的指定文件到仓库区$ git commit -m [message] //提交暂存区所有文件到仓库区 4, 远程同步123456789$ git remote -v //显示所有远程仓库$ git remote add [name] [url] //新增一个远程仓库,并命名$ git pull [remote] [branch] //更新同步远程仓库,与本地分支合并$ git push [remote] [branch] //推送本地指定分支到远程仓库$ git push [remote] --all //推送本地所有分支到远程仓库 特殊场景重置当前Git仓库配置,需要删除.git文件,再重新生成.git123$ ls -a //查看当前仓库文件,-a包含隐藏的 .文件$ rm -rf .git //删除当前.git$ git init //重新生成新的.git文件,就是一个新的git仓库了,然后该提交提交 不小心添加add,或者add了不想提交的文件夹,撤销之后再重新add123$ git status //查看当前提交状态$ git reset . //撤销前一次提交操作$ git status //查看当前提交状态,然后该提交再提交]]></content>
<tags>
<tag>Git</tag>
</tags>
</entry>
<entry>
<title><![CDATA[浙西峡谷两日探游]]></title>
<url>%2F2017%2F06%2F12%2F%E6%B5%99%E8%A5%BF%E5%A4%A7%E5%B3%A1%E8%B0%B7%E4%B8%A4%E6%97%A5%E6%8E%A2%E6%B8%B8%2F</url>
<content type="text"><![CDATA[]]></content>
<tags>
<tag>世界之旅</tag>
</tags>
</entry>
<entry>
<title><![CDATA[不给生活挖坑的机会]]></title>
<url>%2F2017%2F06%2F11%2F%E6%B0%B8%E8%BF%9C%E4%B8%8D%E8%A6%81%E7%BB%99%E7%94%9F%E6%B4%BB%E6%8C%96%E5%9D%91%E7%9A%84%E6%9C%BA%E4%BC%9A%2F</url>
<content type="text"><![CDATA[做事不留下隐患,不给生活挖坑的机会。 ——— 记一个杯子的两次丢失 第一次是出去吃饭,外带馕的时候把杯子放在了桌子上方便自己装馕,当时想,装完记得拿杯子记得拿杯子,然后装完就忘记拿杯子开心的走了。后面想起来已经很晚了(还是朋友的提醒),不过好在杯子被老板帮我收好放起来了,回去拿上了,第一次失而复得。 第二次是随公司出去玩,早上吃早饭的时候又把杯子放在了宾馆的窗台上,当时也在想,待会要记得拿,记得拿,不能像上次那样忘记了。嗯好放心吃吧。然后吃完早饭开心的跑去旁边商店买了一些零食。回来直接随公司同事上车一起走了……车上了高速才想起来我遗忘在窗台的。。。好在后面找了宾馆电话帮忙把杯子寄到家,第二次虽然折腾了些,不过最终也算是失而复得。 这两次的经历实在是太过于深刻惨痛了,让我不得不思考怎么避免此类事情的发生。其实生活中有太多这样的事,我们往往可以多做一些事来避免一些潜在的坏事情发生,比如杯子我可以倒完水放到书包里,但是我们却总是觉得没问题,应该不会犯错的。殊不知每次这样做都给后面走路的自己挖了一个隐藏的坑,虽然很多时候可能不会踩到,但这样的坑慢慢多了,总会有不小心掉进去的时候。当然我们完全可以通过小心翼翼的走路来避免掉进这样那样的坑,但是如果一开始就不挖坑,从根源上解决的话,我们便可以放心大胆的走而不用担心会掉坑里了。]]></content>
<tags>
<tag>生活</tag>
</tags>
</entry>
<entry>
<title><![CDATA[先满足你的胃]]></title>
<url>%2F2017%2F06%2F09%2F%E5%85%88%E6%BB%A1%E8%B6%B3%E4%BD%A0%E7%9A%84%E8%83%83%2F</url>
<content type="text"><![CDATA[如果你要去购物商场或者超市,千万不要空腹去。而是,先吃点东西,然后再去。理由是,当你满足了你的胃,你的精神也会得到满足,这将防止你去买一些你并不需要的东西。你将会买那些需要的商品,因为你已经感觉良好了。我曾经试过很多次,每当我和我的女朋友要去商场前,我更倾向于先去餐馆。 感同身受]]></content>
<tags>
<tag>生活</tag>
<tag>常识</tag>
</tags>
</entry>
<entry>
<title><![CDATA[记一次打球的意外之旅]]></title>
<url>%2F2017%2F06%2F04%2F%E8%AE%B0%E4%B8%80%E6%AC%A1%E5%91%A8%E6%9C%AB%E6%89%93%E7%90%83%E7%9A%84%E6%84%8F%E5%A4%96%E4%B9%8B%E6%97%85%2F</url>
<content type="text"><![CDATA[如果周末很想打球,又觉得体育馆太贵的话,有一个好去处便是附近大学的体育馆。 出门,127路,终点三江学院。一下车,旁边应该就是学校的特色小吃一条街,几十个小吃摊位满满当当的在路边一字排开,一直延伸到学校侧门口。朋友说这应该叫堕落街,我觉得再合适不过。 进到校园,上了一个斜坡便直奔体育馆,一路走来明显感觉到这是一所建在山上的学校,有很多斜坡,所以也导致各种楼梯比较多,不过一路上经过的足球场,篮球场感觉都不错,要是离住的地方再近一些,真想天天晚上过来跑步。 打完球天已经快黑了,这时绕着学校转了一圈才发现这所学校很漂亮也很浪漫,浓郁的绿树,优雅浪漫的长廊,幽静的小道,还有那砖红与灰白相间的欧式建筑撑起了校园的主色调,让人仿佛置身于欧洲的城堡。 1号主体教学楼,这每天上课都要先爬三层楼梯啊,果然求学的道路还是艰辛的。 到了上面有一个大大的露天花园,视野突然开阔,好像天空之城…,看来求学道路上的一切艰辛也是值得的。]]></content>
<tags>
<tag>生活</tag>
<tag>杂记</tag>
</tags>
</entry>
<entry>
<title><![CDATA[时间戳精确转换为指定格式]]></title>
<url>%2F2017%2F06%2F01%2F%E6%97%B6%E9%97%B4%E6%88%B3%E7%B2%BE%E7%A1%AE%E8%BD%AC%E6%8D%A2%E4%B8%BA%E6%8C%87%E5%AE%9A%E6%A0%BC%E5%BC%8F%2F</url>
<content type="text"><![CDATA[月-日-时-分-秒向getMonthDate方法传递时间戳参数,返回对应格式的时间12345678910111213141516getMonthDate(time) { var now = new Date(parseInt(time)); var year=now.getFullYear(); var month=now.getMonth()+1; var date=now.getDate(); var hour=now.getHours(); var minute=now.getMinutes(); var second=now.getSeconds(); if (second < 10) { second = "0" + second; } if (minute < 10) { minute = "0" + minute; } return month+"-"+date+" "+hour+":"+minute+":"+second; } 年-月-日-时-分-秒向getFullTime方法传递时间戳参数,返回对应格式的时间12345678910111213141516getFullTime(time) { var now = new Date(parseInt(time)); var year=now.getFullYear(); var month=now.getMonth()+1; var date=now.getDate(); var hour=now.getHours(); var minute=now.getMinutes(); var second=now.getSeconds(); if (second < 10) { second = "0" + second; } if (minute < 10) { minute = "0"+minute; } return year+"-"+month+"-"+date+" "+hour+":"+minute+":"+second; }]]></content>
<tags>
<tag>javascript</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Vue源码学习笔记]]></title>
<url>%2F2017%2F05%2F24%2FVue%E6%BA%90%E7%A0%81%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%2F</url>
<content type="text"><![CDATA[Vue用了这么久,却一直没时间好好看看它的源码。最近正好工作不是那么忙,便饶有兴致的又把最新版 Vue.js 的源码学习了一下,觉得真心不错,整理一下我的学习笔记。 从package.json文件入手要看一个项目的源码,最好先去了解一下项目本身的元数据和依赖,所以我们在看源码之前第一个想到的应该是:package.json文件。在 package.json 文件中,我们最应该关注的就是 scripts 字段和 devDependencies 以及 dependencies 字段,通过 scripts 字段我们可以知道项目中定义的脚本命令,通过 devDependencies 和 dependencies 字段我们可以了解项目的依赖情况。 知道依赖并安装之后,便是看一下重要目录和文件的简单介绍(官网上有介绍)1234567891011121314151617181920212223242526├── build --------------------------------- 构建相关的文件,一般情况下我们不需要动├── dist ---------------------------------- 构建后文件的输出目录├── examples ------------------------------ 存放一些使用Vue开发的应用案例├── flow ---------------------------------- 类型声明,使用开源项目 [Flow](https://flowtype.org/)├── package.json -------------------------- 不解释├── test ---------------------------------- 包含所有测试文件├── src ----------------------------------- 这个是我们最应该关注的目录,包含了源码│ ├── entries --------------------------- 包含了不同的构建或包的入口文件│ │ ├── web-runtime.js ---------------- 运行时构建的入口,输出 dist/vue.common.js 文件,不包含模板(template)到render函数的编译器,所以不支持 `template` 选项,我们使用vue默认导出的就是这个运行时的版本。大家使用的时候要注意│ │ ├── web-runtime-with-compiler.js -- 独立构建版本的入口,输出 dist/vue.js,它包含模板(template)到render函数的编译器│ │ ├── web-compiler.js --------------- vue-template-compiler 包的入口文件│ │ ├── web-server-renderer.js -------- vue-server-renderer 包的入口文件│ ├── compiler -------------------------- 编译器代码的存放目录,将 template 编译为 render 函数│ │ ├── parser ------------------------ 存放将模板字符串转换成元素抽象语法树的代码│ │ ├── codegen ----------------------- 存放从抽象语法树(AST)生成render函数的代码│ │ ├── optimizer.js ------------------ 分析静态树,优化vdom渲染│ ├── core ------------------------------ 存放通用的,平台无关的代码│ │ ├── observer ---------------------- 反应系统,包含数据观测的核心代码│ │ ├── vdom -------------------------- 包含虚拟DOM创建(creation)和打补丁(patching)的代码│ │ ├── instance ---------------------- 包含Vue构造函数设计相关的代码│ │ ├── global-api -------------------- 包含给Vue构造函数挂载全局方法(静态方法)或属性的代码│ │ ├── components -------------------- 包含抽象出来的通用组件│ ├── server ---------------------------- 包含服务端渲染(server-side rendering)的相关代码│ ├── platforms ------------------------- 包含平台特有的相关代码│ ├── sfc ------------------------------- 包含单文件组件(.vue文件)的解析逻辑,用于vue-template-compiler包│ ├── shared ---------------------------- 包含整个代码库通用的代码 大概了解了重要目录和文件之后,我们就可以查看 Development Setup 中的常用命令部分,来了解如何开始这个项目了,我们可以看到这样的介绍:12345# watch and auto re-build dist/vue.js$ npm run dev# watch and auto re-run unit tests in Chrome$ npm run dev:test 现在,我们只需要运行 npm run dev 即可监测文件变化并自动重新构建输出 dist/vue.js,然后运行 npm run dev:test 来测试。不过为了方便,我会在 examples 目录新建一个例子,然后引用 dist/vue.js 这样,我们可以直接拿这个例子一边改Vue源码一边看自己写的代码想怎么玩怎么玩。]]></content>
<tags>
<tag>Vue</tag>
</tags>
</entry>
<entry>
<title><![CDATA[南京街头一日游]]></title>
<url>%2F2017%2F05%2F13%2F%E5%8D%97%E4%BA%AC%E8%A1%97%E5%A4%B4%E4%B8%80%E6%97%A5%E6%B8%B8%2F</url>
<content type="text"><![CDATA[]]></content>
<tags>
<tag>生活</tag>
<tag>南京</tag>
</tags>
</entry>
<entry>
<title><![CDATA[记近期电脑升级一事]]></title>
<url>%2F2017%2F04%2F22%2F%E8%AE%B0%E8%BF%91%E6%9C%9F%E7%94%B5%E8%84%91%E5%8D%87%E7%BA%A7%E4%B8%80%E4%BA%8B%2F</url>
<content type="text"><![CDATA[去年4月份买的dell台式机,到现在正好一年。但是最近发现开机变慢了很多,等半天很是伤,玩游戏也没以前流畅了,这才一岁啊,,其实最主要的原因还是女朋友直播游戏太卡了,,于是决定给电脑来一次全面升级,算是给它陪伴我们一年来的小小回报吧。原先配置:因特尔i5-4460 处理器,内存4G,GTX745的显卡(4G),1T机械硬盘,win7i5的处理器不打算升级,性能还好。主要是显卡和硬盘第一件物品 显卡,市场上 显卡 产品可谓琳琅满目,各有各的特色,网上搜刮了一圈后发现,好的太贵,便宜的又没升级必要,挑来挑去千元左右的显卡就剩下1050TI,别无他选。网上也很多说1050Ti性价比不咋咋的,但还是决定入手。说下1050Ti的优点吧 功耗和温度,大部分1050ti不需外接6pin,可以做得比较小,简直是小机箱的绝佳搭档。就是有类似于intel睿频的功能,玩游戏的时候可以从默频1500Mhz拉到1750Mhz 于是从某东买了新显卡GTX1050Ti(¥1199)显卡第二天就来了,一切顺利啊,晚上下班准备拆机装显卡比之前的大太多,装的时候费了些劲 就在我为自己的英明抉择佩服不已的时候,剧情发生了 360 ℃ 反转。猴急猴急测试显卡性能的时候,开机一直点不亮。。。折腾半天才发现之前dell的电源功率带不动新的显卡,,卧槽,早知如此,何必买那么好的。犯下如此低端错误,实在打脸。 于是又在某宝买了硬盘架(¥9.9),电源(¥80)总算能开机了,但是用了一天发现并没有快多少,玩游戏还是一样的卡,开机还是一样慢。。 早有耳闻说 SSD 如何如何的快,快到足够让旧设备重新焕发青春。于是下一件升级物品 SSD在某宝上看了半天,最后在闲鱼上买了换了硬盘重装完系统,重启,开机10s,完美如此一番,除了荷包渐瘦以外,其他都到位了。]]></content>
</entry>
<entry>
<title><![CDATA[科学上网工具]]></title>
<url>%2F2017%2F04%2F08%2F%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91%E5%B7%A5%E5%85%B7%2F</url>
<content type="text"><![CDATA[生命短暂,世界却那么大 今天发现一个科学上网神器,真是相知恨晚。虽然要经常更新密码,但对比之前收费还不稳定的服务器来说,这简直就是福利FREE SS 传送门]]></content>
<tags>
<tag>工具</tag>
</tags>
</entry>
<entry>
<title><![CDATA[最简易的评分组件]]></title>
<url>%2F2017%2F04%2F01%2F%E6%9C%80%E7%AE%80%E6%98%93%E7%9A%84%E8%AF%84%E5%88%86%E7%BB%84%E4%BB%B6%2F</url>
<content type="text"><![CDATA[12var rate = 1"★★★★★☆☆☆☆☆".slice(5 - rate, 10 - rate) 结果:”★☆☆☆☆”12var rate = 2"★★★★★☆☆☆☆☆".slice(5 - rate, 10 - rate) 结果:”★★☆☆☆”12var rate = 3"★★★★★☆☆☆☆☆".slice(5 - rate, 10 - rate) 结果:”★★★☆☆”12var rate = 4"★★★★★☆☆☆☆☆".slice(5 - rate, 10 - rate) 结果:”★★★★☆”12var rate = 5"★★★★★☆☆☆☆☆".slice(5 - rate, 10 - rate) 结果:”★★★★★”]]></content>
</entry>
<entry>
<title><![CDATA[对js闭包的理解及其应用]]></title>
<url>%2F2017%2F03%2F25%2F%E5%AF%B9js%E9%97%AD%E5%8C%85%E7%9A%84%E7%90%86%E8%A7%A3%E5%8F%8A%E5%85%B6%E5%BA%94%E7%94%A8%2F</url>
<content type="text"><![CDATA[闭包的概念简单来说,闭包指的是被持久化的函数以及它所保留的对外层变量的引用的组合。具体来说,闭包就是保留了对自由变量的引用的函数。与面向对象方式使用类属性来保留数据不同,闭包是通过词法作用域来保留对于变量的引用的。词法作用域的最基本特性是:在嵌套的作用域中,某个作用域可以访问本层定义的变量,也可以访问外层的变量,但是不能访问内层的变量。对于 js 语言来说,最常见的作用域层级就是 var 声明所对应的函数级别作用域。首先,由于外层作用域无法访问内层作用域的变量,因此自由变量肯定不会是内层变量。其次,对于本层定义的变量来说,函数执行完毕后,这些变量就会被销毁,留待垃圾回收,因此本层的变量不具备保留引用的特性。所以最后的结论已经很明确,保留引用的自由变量只能是外层的变量。因此,闭包是保留了对外层自由变量的引用的函数。如何保留对外层变量的引用?这要求函数能以某种方式被持久化保留。 来个例子:1234567891011121314function closure(){ var count = 0; return function(){ console.log(++count); }}var getCount = closure();getCount(); // 输出 1getCount(); // 输出 2getCount(); // 输出 3... 在这个例子中,调用 closure() 函数时,内层的匿名函数被作为返回值赋予了外部的 getCount 变量。由于内层的匿名函数需要使用外层的 count 变量,因此外层变量 count 就被匿名函数保留了引用。而每次调用 getCount() , count 变量的值都会被加一。在这个例子中,内层的匿名函数以及它所保留的对于外层变量 count 的引用就构成了闭包。 如果内层函数没有用任何方式持久化,那么它也无法保留对于外层变量的引用。例如:12345678910111213function noClosure(){ var count = 0; function inner(){ console.log(++count); } inner();}noClosure(); // 输出 1noClosure(); // 输出 1noClosure(); // 输出 1 由于这个例子的 inner() 没有被持久化,调用时只能直接调用外层函数 noClosure() 。此时内层的 inner() 每次被调用后就结束了生命周期,相关的作用域也被销毁,因此 count 变量也不会被保留引用,这样每次调用 noClosure() 都只会输出 1 。由此可以进一步总结闭包的概念:闭包是以某种方式被持久化、并保留了对外层自由变量的引用的函数。实际的闭包指的是被持久化的函数以及它所保留的对外层变量的引用的组合。由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成”定义在一个函数内部的函数”。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。 闭包的用途闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。方便调用上下文的局部变量。 使用闭包的注意点1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。]]></content>
<tags>
<tag>javascript</tag>
<tag>每周学习笔记</tag>
</tags>
</entry>
<entry>
<title><![CDATA[前端框架和原生js的选择困惑]]></title>
<url>%2F2017%2F03%2F21%2F%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6%E5%92%8C%E5%8E%9F%E7%94%9Fjs%E7%9A%84%E9%80%89%E6%8B%A9%E5%9B%B0%E6%83%91%2F</url>
<content type="text"><![CDATA[最近用框架写东西有点多,快速开发用框架没错,毕竟用着也很爽,但问题是用框架开发,关键的技术前提给你预设好了,重要的技术决定也帮你做了,你做得最多的就是往里填展示逻辑,业务逻辑。而学习需要的是把技术掰开来,扯碎了再装起来,知道“原来如此”的过程。虽然遇到的问题基本都能解决,但写的越多总感觉自己不太深入,今天遇到一个问题,也印证了我的担忧,自己有些停在表面了,光解决问题没深入学习。回头看一下发现,最近每天工作用Vue,平时还写写React,小程序什么的。但是原生js写的看的很少。就像在武侠里练武是一样的,只学了一些“花拳绣腿招式”,但是“内功修养”还不到家,感觉不太妙。所以是时候要闭关修炼一段时间js了,回到基础知识中去,等有了扎实的“内功”基础,学任何框架也就只是概念迁移的事情,并没有特别要学的地方,拿起来用应该就行了。]]></content>
</entry>
<entry>
<title><![CDATA[事件冒泡和事件捕获]]></title>
<url>%2F2017%2F03%2F18%2F%E4%BA%8B%E4%BB%B6%E5%86%92%E6%B3%A1%E5%92%8C%E4%BA%8B%E4%BB%B6%E6%8D%95%E8%8E%B7%2F</url>
<content type="text"><![CDATA[一 事件阶段一般的,事件分为三个阶段:捕获阶段、目标阶段和冒泡阶段。 1 捕获阶段:事件的第一个阶段是捕获阶段。事件从最不精确的对象(文档根节点)开始触发,然后到触发最精确的对象(目标对象节点)结束。途中经过各个层次的DOM节点,并在各节点上触发捕获事件,直到到达事件的目标节点。当你使用事件捕获时,父级元素事件先触发,子级元素后触发。作用:捕获阶段的主要任务是建立传播路径,在冒泡阶段,事件会通过这个路径回溯到文档跟节点。 2 目标阶段:当事件到达目标节点的,事件就进入了目标阶段。事件在目标节点上被触发,然后会逆向回流,直到传播至最外层的文档节点。 3 冒泡阶段:事件按照从最精确的对象(目标对象节点)开始触发,一直到最不精确的事件目标(文档根节点)的顺序触发结束。事件在目标元素上触发后,并不在这个元素上终止。它会随着DOM树一层层向上冒泡,回溯到根节点。当你使用事件冒泡时,子级元素事件先触发,父级元素后触发。作用:冒泡过程非常有用。它将我们从对特定元素的事件监听中释放出来,如果没有事件冒泡,我们需要监听很多不同的元素来确保捕获到想要的事件。 二 冒泡阶段调用事件处理函数三 捕获阶段调用事件处理函数四 事件代理在传统的事件处理中,你按照需要为每一个元素添加或者是删除事件处理器。然而,事件处理器将有可能导致内存泄露或者是性能下降——你用得越多这种风险就越大。JavaScript事件代理可以把事件处理器添加到一个父元素上,这样就避免了把事件处理器添加到多个子元素上。 1 如何运作事件代理用到了两个JavaSciprt事件特性:事件冒泡以及目标元素。当一个元素上的事件被触发的时候,同样的事件将会在那个元素的所有祖先元素中被触发。这一过程被称为事件冒泡;使用事件代理,我们可以把事件处理器添加到一个元素上,等待一个事件从它的子级元素里冒泡上来,并且可以得知这个事件是从哪个元素开始的。 2 带来的好处比如说在一个10列、100行的HTML表格里,让其每一个单元格在被点击的时候变成可编辑状态。如果把事件处理器加到这1000个单元格会产生一个很大的性能问题,并且有可能导致内存泄露甚至是浏览器的崩溃。相反地,使用事件代理,你只需要把一个事件处理器添加到table元素上就可以了,这个函数可以把点击事件给截下来,并且判断出是哪个单元格被点击了。 五 阻止事件冒泡(stopPropagation)1 什么时候要阻止事件冒泡当父类也有同样类型的方法,但在调用子类方法的时候不想触发父类方法的时候要阻止冒泡。例如:document上有A事件,div有B事件,div里面的span有C事件,如果不给span和div加阻止事件冒泡的话,点击span时就会触发到div的B事件、document的A事件,当点击span时不想触发div和document的事件就要加上阻止事件冒泡,div也是一样的道理。如果不加阻止事件冒泡,便会由于事件冒泡,该DOM目标节点的所有父节点事件也会触发,执行了回调函数,这样就违背了最初的本意了。 2 如何阻止事件冒泡阻止事件冒泡有3种方法 (1) event.stopPropagation(); 事件处理过程中,阻止了事件冒泡,但不会阻击默认行为(它就执行了超链接的跳转) (2) return false; 事件处理过程中,阻止了事件冒泡,也阻止了默认行为(比如刚才它就没有执行超链接的跳转) (3) event.preventDefault(); 如果把它放在头部A标签的click事件中,点击“点击我”。 会发现它依次弹出:我是最里层—->我是中间层—->我是最外层,但最后却没有跳转到百度 它的作用是:事件处理过程中,不阻击事件冒泡,但阻击默认行为(它只执行所有弹框,却没有执行超链接跳转) 3 无法在捕获阶段阻止事件冒泡这里需要注意的是,我们无法在事件捕获阶段阻止事件冒泡。例如,我们在代码里加上true,如图所示,第一个li会触发事件。因为捕获是从根节点向目标节点触发,而冒泡是从目标节点向根节点触发。]]></content>
<tags>
<tag>javascript</tag>
</tags>
</entry>
<entry>
<title><![CDATA[自己封装的一个ajax函数]]></title>
<url>%2F2017%2F03%2F10%2F%E8%87%AA%E5%B7%B1%E5%B0%81%E8%A3%85%E7%9A%84%E4%B8%80%E4%B8%AAajax%E5%87%BD%E6%95%B0%2F</url>
<content type="text"><![CDATA[一共只留了五个参数,他们分别是发送方式(type)、发请求的url(url)、是否为异步请求(async)、发送的参数(data)、传输成功的回调函数(success) 函数代码如下: 12345678910111213141516171819202122232425262728293031323334353637383940414243/* 封装ajax函数 * @param {string}opt.type http连接的方式,包括POST和GET两种方式,默认使用GET * @param {string}opt.url 发送请求的url * @param {boolean}opt.async 是否为异步请求,true为异步的,false为同步的 * @param {object}opt.data 发送的参数,格式为对象类型 * @param {function}opt.success ajax发送并接收成功调用的回调函数 */function ajax(opt) { opt = opt || {}; var type = opt.type || 'GET'; type = type.toUpperCase() || 'GET'; var url = opt.url || ''; var async = opt.async || true; var data = opt.data || null; var success = opt.success || function () {}; var xmlHttp = null; if (XMLHttpRequest) { xmlHttp = new XMLHttpRequest(); } else { xmlHttp = new ActiveXObject('Microsoft.XMLHTTP'); } var params = []; for (var key in data){ params.push(key + '=' + data[key]); } var dataStr = params.join('&'); if (type === 'POST') { xmlHttp.open(type, url, async); xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8'); xmlHttp.send(dataStr); } else { xmlHttp.open(type, url + '?' + dataStr, async); xmlHttp.send(null); } xmlHttp.onreadystatechange = function () { if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { success(xmlHttp.responseText); } };} 使用实例:1234567891011ajax({ method: 'POST', url: 'test.php', data: { name1: 'value1', name2: 'value2' }, success: function (response) { // codes here }});]]></content>
<categories>
<category>前端</category>
</categories>
<tags>
<tag>javascript</tag>
<tag>ajax</tag>
</tags>
</entry>
<entry>
<title><![CDATA[常见算法的JS实现(持续更新)]]></title>
<url>%2F2017%2F03%2F06%2F%E5%B8%B8%E8%A7%81%E7%AE%97%E6%B3%95%E7%9A%84JS%E5%AE%9E%E7%8E%B0%2F</url>
<content type="text"><![CDATA[排序算法冒泡排序1234567891011121314151617function bubbleSort(arr){ var i = 0, j = 0; for(i=1; i<arr.length; i++){ for(j=0; j<=arr.length-i; j++){ var temp = 0; // ">" 从小到大排序 // "<" 从大到小排序 if(arr[j] > arr[j+1]){ temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } return arr;} 快速排序123456789101112131415161718192021222324function quickSort(arr,l,r){ if(l < r){ var i = l, j = r, x = arr[i]; while(i<j){ while(i<j && arr[j]>x) j--; if(i<j) //这里用i++,被换过来的必然比x小,赋值后直接让i自加,不用再比较,可以提高效率 arr[i++] = arr[j]; while(i<j && arr[i]<x) i++; if(i<j) //这里用j--,被换过来的必然比x大,赋值后直接让j自减,不用再比较,可以提高效率 arr[j--] = arr[i]; } arr[i] = x; quickSort(arr, l, i-1); quickSort(arr, i+1, r); }} 二路归并1234567891011121314151617181920function merge(left, right) { var result = [], il = 0, ir = 0; while (il < left.length && ir < right.length) { if (left[il] < right[ir]) { result.push(left[il++]); } else { result.push(right[ir++]); } } while(left[il]){ result.push(left[il++]); } while(right[ir]){ result.push(right[ir++]); } return result;} 字符串操作判断回文字符串123456789101112function palindrome(str){ // \W匹配任何非单词字符。等价于“[^A-Za-z0-9_]”。 var re = /[\W_]/g; // 将字符串变成小写字符,并干掉除字母数字外的字符 var lowRegStr = str.toLowerCase().replace(re,''); // 如果字符串lowRegStr的length长度为0时,字符串即是palindrome if(lowRegStr.length===0) return true; // 如果字符串的第一个和最后一个字符不相同,那么字符串就不是palindrome if(lowRegStr[0]!=lowRegStr[lowRegStr.length-1]) return false; //递归 return palindrome(lowRegStr.slice(1,lowRegStr.length-1));} 翻转字符串思路一:反向遍历字符串123456function reverseString(str){ var tmp = ''; for(var i=str.length-1; i>=0; i--) tmp += str[i]; return tmp} 思路二:转化成array操作123456789101112function reverseString(str){ var arr = str.split(""); var i = 0,j = arr.length-1; while(i<j){ tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; i++; j--; } return arr.join("");} 生成指定长度随机字符串12345678function randomString(n){ var str = 'abcdefghijklmnopqrstuvwxyz0123456789'; var tmp = ''; for(var i=0; i<n; i++) { tmp += str.charAt(Math.round(Math.random()*str.length)); } return tmp;} 统计字符串中次数最多字母12345678910111213141516171819202122function findMaxDuplicateChar(str) { if(str.length == 1) { return str; } var charObj = {}; for(var i = 0; i < str.length; i++) { if(!charObj[str.charAt(i)]) { charObj[str.charAt(i)] = 1; } else { charObj[str.charAt(i)] += 1; } } var maxChar = '', maxValue = 1; for(var k in charObj) { if(charObj[k] >= maxValue) { maxChar = k; maxValue = charObj[k]; } } return maxChar + ':' + maxValue;} 数组操作数组去重1234567891011function unique(arr){ var obj = {} var result = [] for(var i in arr){ if(!obj[arr[i]]){ obj[arr[i]] = true; result.push(arr[i]); } } return result;} 数组中最大差值123456789function getMaxProfit(arr){ var min = arr[0], max = arr[0]; for(var i = 0; i < arr.length; i++){ if(arr[i] < min) min = arr[i]; if(arr[i] > max) max = arr[i]; } return max - min;} 其他常见算法阶乘非递归实现123456789function factorialize(num) { var result = 1; if(num < 0) return -1; if(num == 0 || num == 1) return 1; while(num>1) { result *= num--; } return result;} 递归实现123456function factorialize(num) { var result = 1; if(num < 0) return -1; if(num == 0 || num == 1) return 1; if(num > 1) return num*factorialize(num-1);} 生成菲波那切数列强行递归实现123456789101112function getfib(n){ if(n == 0) return 0; if(n == 1) return 1; if(n > 1) return getfib(n-1) + getfib(n-2);}function fibo(len){ var fibo = []; for(var i = 0; i < len; i++){ fibo.push(getfib(i)); } return fibo;} 简约非递归实现12345678910111213function getFibonacci(n) { var fibarr = []; var i = 0; while(i < n) { if(i <= 1) { fibarr.push(i); } else { fibarr.push(fibarr[i - 1] + fibarr[i - 2]) } i++; } return fibarr;} 二分查找非递归实现123456789101112131415function binary_search(arr, key) { var low = 0, high = arr.length - 1; while(low <= high){ var mid = parseInt((high + low) / 2); if(key == arr[mid]){ return mid; }else if(key > arr[mid]){ low = mid + 1; }else if(key < arr[mid]){ high = mid -1; } } return -1;} 递归实现1234567891011function binary_search2(arr, low, high, key) { if(low > high) return -1; var mid = parseInt((low + high)/2); if(key == arr[mid]) { return mid; } else if(key > arr[mid]) { return binary_search2(arr, mid+1, high, key); } else if(key < arr[mid]) { return binary_search2(arr, low, mid-1, key); }}]]></content>
</entry>
<entry>
<title><![CDATA[vuejs 中如何优雅的获取 Input 值]]></title>
<url>%2F2017%2F02%2F27%2Fvuejs-%E4%B8%AD%E5%A6%82%E4%BD%95%E4%BC%98%E9%9B%85%E7%9A%84%E8%8E%B7%E5%8F%96-Input-%E5%80%BC%2F</url>
<content type="text"><![CDATA[vue 中获取 Input 值 我一般采取v-model或ref的方法1,双向绑定 v-model 分两种情况 input 默认为空。这种情况使用 v-model 最方便,通过 this.inputName 即可获取到对应的值。input 有默认值。即,设置了 value 属性的 Input。这种情况不能使用 v-model。否则 data 中的初始化值会把 value 的值覆盖掉。正确的姿势是使用 v-model, 然后通过 ajax 从后台拉取默认值,给对应的 vuejs 变量赋值。对于简单的后台渲染页面,这种方式略显复杂。 2,使用ref 在不适合使用 v-model 的时候,我更倾向于使用 ref.vuejs 2.0 之后,废弃了 vuejs 1.0 中的 this.$els,改用 this.$refs。即,使用 ref 属性来标识一个元素。 示例代码: demo.html:123456789101112131415161718192021222324252627<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>Index Page</title></head><body> <form action="" id="demo"> <input type="text" value="调试 vuejs 2.0" ref="input1"> <a href="javascript:void(0)" v-on:click="test1">测试</a> <br> <span>{{ result1 }}</span> <br> <input type="text" v-model="input2"> <a href="javascript:void(0)" v-on:click="test2">测试</a> <br> <span>{{ result2 }}</span> </form> <script src="http://cdn.bootcss.com/vue/2.0.3/vue.min.js"></script> <script type="text/javascript" src="demo.js"></script></body></html> demo.js:1234567891011121314151617181920212223new Vue({ el: "#demo", data: { result1: null, result2: null, input2: "" }, created: function() { // the created hook is called after the instance is created }, methods: { test1: function () { this.result1 = this.$refs.input1.value + " 成功!"; }, test2: function () { this.result2 = this.input2 + " 成功!"; } }})]]></content>
<categories>
<category>前端</category>
</categories>
<tags>
<tag>javascript</tag>
<tag>vue.js</tag>
</tags>
</entry>
<entry>
<title><![CDATA[为什么要写博客]]></title>
<url>%2F2017%2F02%2F27%2F%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E5%86%99%E5%8D%9A%E5%AE%A2%2F</url>
<content type="text"><![CDATA[写博客这个事情我计划了很久,但是太懒也怕写出来的东西质量不高没人看就一直藏在心里。不得不承认,建立技术博客的初衷是因为找工作,哈哈,说起来还是有点功利的性质的。最近刚好在看艾力的《人生的84000种可能》,产生了很多共鸣,没有人是完美的,但是可以通过不断的努力去接近完美,能在这世界中留下自己的印记,能证明自己在世界上存在过,这就足够我去挑战了,何况证明自己的同时,亦可助人,何乐而不为呢。这也许就是我要写博客的理由吧。]]></content>
</entry>
<entry>
<title><![CDATA[再回南京]]></title>
<url>%2F2016%2F12%2F25%2F%E5%86%8D%E5%9B%9E%E5%8D%97%E4%BA%AC%2F</url>
<content type="text"><![CDATA[时隔一年多,又回到了南京。南京什么都没变,还是红色的2号线,蓝色的1号线。感觉很亲切。下了飞机,我们像往常一样,拖着行李箱,上了地铁,只是这次,我们不再是去学校……收拾收拾准备明天去新公司报道,为了努力养活自己,更为了养活梦想,虽然改变不了生活,但也不被生活改变。]]></content>
</entry>
</search>