-
+
+
+
\ No newline at end of file
diff --git a/lesson7.html b/lesson7.html
new file mode 100644
index 0000000..9c4ca0e
--- /dev/null
+++ b/lesson7.html
@@ -0,0 +1,60 @@
+
+
+
+
+
+
第 7 课作业
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ word.name}}
+
{{ word.words}}
+
+
+
![]()
+
+
+
+
+
+
+
+
+
![]()
+
+
+
{{ word.name}}
+
+
{{ word.words}}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..6849c88
--- /dev/null
+++ b/package.json
@@ -0,0 +1,7 @@
+{
+ "name": "packages",
+ "dependencies": {
+ "axios": "0.16.2",
+ "jsonfile": "3.0.1"
+ }
+}
diff --git a/promises.js b/promises.js
new file mode 100644
index 0000000..5b7f6dd
--- /dev/null
+++ b/promises.js
@@ -0,0 +1,168 @@
+/* ES5 */
+
+var isMomHappy = Math.random() > 0.5;
+
+// 承诺
+var willIGetNewPhone = new Promise(
+ function (resolve, reject) {
+ if (isMomHappy) {
+ var phone = {
+ '品牌': '苹果',
+ '颜色': '亮黑'
+ };
+ resolve(phone); // 嗯,妈妈心情不错,给你买手机了,实现诺言了
+ } else {
+ var reason = new Error('妈妈不高兴');
+ reject(reason); // 妈妈不高兴,不要问为什么,不然揍你哦
+ }
+ }
+);
+
+// 执行承诺
+var askMom = function () {
+ willIGetNewPhone
+ .then(function (fulfilled) {
+ // 哈哈,妈妈真的买手机啦
+ console.log(fulfilled);
+ // 输出:'品牌': '苹果', '颜色': '亮黑色'
+ })
+ .catch(function (error) {
+ // 唉,妈妈没有买手机
+ console.log(error.message);
+ // 输出: '妈妈不高兴'
+ });
+};
+
+// 第二个承诺
+var showOff = function (phone) {
+ return new Promise(
+ function (resolve, reject) {
+ var message = '小伙伴们,我有新的' + phone['颜色'] + phone['品牌'] + '手机啦!';
+
+ resolve(message);
+ }
+ );
+};
+
+// 第二个承诺的迷你版
+var showOff = function (phone) {
+ var message = '小伙伴们,我有新的' + phone['颜色'] + phone['品牌'] + '手机啦!';
+
+ return Promise.resolve(message);
+};
+
+// 开始要求兑现承诺
+var askMom = function () {
+ willIGetNewPhone
+ .then(showOff) // 在这里进行链式调用
+ .then(function (fulfilled) {
+ console.log(fulfilled);
+ // 输出:'小伙伴们,我有新的亮黑色苹果手机啦!'
+ })
+ .catch(function (error) {
+ // 唉,妈妈果然还是没给我买手机
+ console.log(error.message);
+ // 输出: '妈妈不高兴'
+ });
+};
+
+// 开始要求兑现承诺
+var askMom = function () {
+ console.log('一会儿要问问妈妈买手机了没'); // 开始调用 promise 之前
+
+ willIGetNewPhone
+ .then(showOff) // 在这里进行链式调用
+ .then(function (fulfilled) {
+ console.log(fulfilled);
+ // 输出:'小伙伴们,我有新的亮黑色苹果手机啦!'
+ })
+ .catch(function (error) {
+ // 唉,妈妈果然还是没给我买手机
+ console.log(error.message);
+ // 输出: '妈妈不高兴'
+ });
+
+ console.log('问过妈妈了……'); // 开始调用 promise 之后
+};
+
+askMom();
+
+/* ES6 */
+const isMomHappy = Math.random() > 0.5;
+
+// 承诺
+const willIGetNewPhone = new Promise(
+ (resolve, reject) => { // 箭头函数
+ if (isMomHappy) {
+ const phone = {
+ '品牌': '苹果',
+ '颜色': '亮黑'
+ };
+ resolve(phone);
+ } else {
+ const reason = new Error('妈妈不高兴');
+ reject(reason);
+ }
+ }
+);
+
+const showOff = function (phone) {
+ const message = '小伙伴们,我有新的' + phone['颜色'] + phone['品牌'] + '手机啦';
+ return Promise.resolve(message);
+};
+
+// 开始要求兑现承诺
+const askMom = function () {
+ willIGetNewPhone
+ .then(showOff)
+ .then(fulfilled => console.log(fulfilled)) // 箭头函数
+ .catch(error => console.log(error.message)); // 箭头函数
+}
+
+/* ES7 */
+const isMomHappy = Math.random() > 0.5;
+
+// 承诺
+const willIGetNewPhone = new Promise(
+ (resolve, reject) => {
+ if (isMomHappy) {
+ const phone = {
+ '品牌': '苹果',
+ '颜色': '亮黑'
+ };
+ resolve(phone);
+ } else {
+ const reason = new Error('妈妈不高兴');
+ reject(reason);
+ }
+ }
+)
+
+// 第二个承诺
+async function showOff(phone) {
+ return new Promise(
+ (resolve, reject) => {
+ var message = '小伙伴们,我有新的' + phone['颜色'] + phone['品牌'] + '手机啦'; // 这里为什么用 var 而不是 const?
+ resolve(message);
+ }
+ )
+}
+
+// 开始要求兑现承诺
+async function askMom() {
+ try {
+ console.log('一会儿要问问妈妈买手机了没');
+
+ let phone = await willIGetNewPhone;
+ let message = await showOff(phone);
+
+ console.log(message);
+ console.log('问过妈妈了……');
+ } catch (error) {
+ console.log(error.message);
+ }
+};
+
+(async () => {
+ await askMom();
+});
\ No newline at end of file
diff --git a/public/css/style.css b/public/css/style.css
new file mode 100644
index 0000000..ee3514f
--- /dev/null
+++ b/public/css/style.css
@@ -0,0 +1,126 @@
+.navbar {
+ margin-bottom: 0;
+}
+
+.navbar-brand>img {
+ width: 20px;
+ /* height: 24px; */
+}
+
+.header {
+ padding: 40px 0 70px;
+ /* 后面尝试采用medium的方法,先加载一张模糊但是尺寸很小的缩略图,然后再加载原图
+ https://jmperezperez.com/medium-image-progressive-loading-placeholder/ */
+ background: url("../images/bg.jpg") no-repeat;
+ background-size: 100%;
+ box-sizing: border-box;
+}
+
+.header h1 {
+ color: #fff;
+ line-height: 2em;
+}
+
+.header img {
+ width: 40px;
+ border-radius: 18px;
+ vertical-align: top;
+ margin: 0 20px 0 0;
+}
+
+.teacher {
+ display: inline-block;
+}
+
+.teacher a,
+.teacher p {
+ margin: 0 0 3px;
+ color: #fff;
+}
+
+.main {
+ padding-top: 40px;
+}
+
+.col-md-8 .panel-default {
+ border-color: #BDDAF6;
+}
+
+.col-md-8 .panel-default>.panel-heading {
+ color: #fff;
+ background-color: #479fea;
+}
+
+.btn-primary {
+ background-color: #479fea;
+ border-style: none;
+}
+
+.milestone h3 {
+ text-align: center;
+}
+
+.milestone p {
+ text-align: center;
+ margin: 10px 0;
+}
+
+.carousel {
+ box-shadow: #479fea 0 0 5px;
+ margin-top: 10px;
+}
+
+.carousel-caption {
+ text-shadow: 0 0 5px rgba(0, 0, 0, .9);
+}
+
+.carousel-control {
+ background-image: none !important;
+ color: #007ae2;
+}
+
+.carousel-indicators {
+ bottom: 0;
+}
+
+.carousel-indicators>li {
+ border: 2px solid #007ae2;
+}
+
+.carousel-indicators>.active {
+ background-color: #007ae2;
+}
+
+h3.panel-title {
+ line-height: 2em;
+}
+
+.form-group label {
+ height: 30px;
+}
+
+.user-content label {
+ display: block;
+}
+
+.user-content textarea {
+ width: 100%;
+}
+
+.articles-list {
+ padding-left: 20px;
+}
+
+.articles-list>li {
+ line-height: 2.5em;
+}
+
+.to-do-list {
+ margin: 0;
+ padding-left: 17px;
+}
+
+.to-do {
+ padding: 10px 0;
+ margin: 0;
+}
\ No newline at end of file
diff --git a/public/css/style2.css b/public/css/style2.css
new file mode 100644
index 0000000..974db48
--- /dev/null
+++ b/public/css/style2.css
@@ -0,0 +1,23 @@
+#app {
+ width: 100%;
+ height: 100%;
+ background: url("https://raw.githubusercontent.com/Dream4ever/Pics/master/matrix-blur.jpg") no-repeat;
+ background-size: cover;
+ box-sizing: border-box;
+ animation: image_blur 8s;
+}
+
+
+/* https://stackoverflow.com/a/15409944/2667665 */
+
+@keyframes image_blur {
+ 0% {
+ -webkit-filter: blur(6px);
+ }
+ 50% {
+ -webkit-filter: blur(3px);
+ }
+ 100% {
+ -webkit-filter: blur(0px);
+ }
+}
\ No newline at end of file
diff --git a/public/images/bg.jpg b/public/images/bg.jpg
new file mode 100644
index 0000000..17ef775
Binary files /dev/null and b/public/images/bg.jpg differ
diff --git a/public/js/main.js b/public/js/main.js
new file mode 100644
index 0000000..c4dab33
--- /dev/null
+++ b/public/js/main.js
@@ -0,0 +1,216 @@
+// 让jshint支持es6,不再提示箭头函数的事情
+// https://stackoverflow.com/a/42870745/2667665
+/*jshint esversion: 6 */
+
+// 2017年09月11日更新:今天调用axios又没问题了……这是什么fuck?
+
+// 如果将js单独写在一个文件中,vue调用axios会失败,所以需要用import引入
+// 而import是ES6的语法,目前的浏览器并不支持,又需要用Babel将JS转码才行
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
+// 为了让Babel能自动转码,又需要Webpack,真折腾啊……
+// import axios from '/public/lesson9/axios.min.js';
+
+// 使用ES6的必要性
+// https://stackoverflow.com/a/39685721/2667665
+// How to Use ES6 for Universal JavaScript Apps
+// https://medium.com/javascript-scene/how-to-use-es6-for-isomorphic-javascript-apps-2a9c3abe5ea2
+// Trying out JavaScript ES6 using Babel
+// https://onsen.io/blog/trying-out-javascript-es6-using-babel/
+// 阮一峰的Babel介绍
+// http://es6.ruanyifeng.com/#docs/intro#Babel-转码器
+// 通过 Babel 使用 ES6 的 import
+// https://aotu.io/notes/2016/09/22/es6-import-with-babel/index.html
+// import - MDN
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
+
+// SOF上一篇非常到位的解答,说明了在JS文件中为什么要用IIFE将整个文件里的代码全部封装起来
+// https://stackoverflow.com/a/2421949/2667665
+(function () {
+
+ 'use strict';
+
+ // TODO
+ // API列表也改成从json文件中读取?
+
+ // API列表不采用数组形式而是采用对象形式,这样使用变量的时候从字面上就能够看出来调用的是什么接口
+ var api = {
+ 'words': 'course/1/words',
+ 'detail': 'course/1/detail',
+ 'catalog': 'course/1/catalog',
+ 'homework': 'course/1/homework',
+ 'teams': 'course/1/teams',
+ 'sayToMe': 'sayToMe'
+ };
+
+ var preFix = 'https://js.xinshengdaxue.com/api/v1/learnJS/';
+
+ // jshint提示不要使用for in?不过尝试一下别的遍历对象属性的方法也是蛮不错的
+ // https://stackoverflow.com/a/14379351/2667665
+ Object.keys(api).forEach(function (key) {
+ api[key] = preFix + api[key];
+ });
+
+ // 箭头函数中如果有大括号,就必须有return,如果没有大括号,比如下面的形式,可以不return
+ // 正确写法
+ // var apiList =
+ // ['course/1/words',
+ // 'course/1/detail',
+ // 'course/1/catalog',
+ // 'course/1/homework',
+ // 'course/1/teams',
+ // 'sayToMe']
+ // .map(api => preFix + api);
+
+ // 错误写法
+ // apiList =
+ // ['course/1/words',
+ // 'course/1/detail',
+ // 'course/1/catalog',
+ // 'course/1/homework',
+ // 'course/1/teams',
+ // 'sayToMe']
+ // .map(function (api) {
+ // // function中如果不主动return,返回值就是undefined
+ // api = preFix + api;
+ // });
+
+ var myWord = {
+ 'name': '何伟',
+ 'account': '15564866632',
+ 'content': '经过这九节课的学习,从最初研究 git 和 GitHub 的使用,到对编程中一些关键概念的思考、理解,包括回调函数、异步函数,一边看文章、看代码琢磨这些概念,一边自己动手写代码,并解决遇到的各种问题,在这个过程中,真正收获了成长。不同于以往的教科书式的学习,这次的课程,通过让大家以听课+自主学习的方式,去走完JS入门学习过程中的几个关键路径,这样能够对JS这门编程语言的方方面面,以及技术团队的实际工作流程及方法有自己的实操经验及领悟。虽然自己在编程方面已经不算是小白了,但是经过这几个星期的课程的学习,所带来的收获是受用终生的。一方面让自己逐渐开始养成了写技术文档的习惯,另外也让自己更加勇于尝试新技术,感觉在课程的学习过程中,渐渐地摸到了"学习的方法",这种感觉是很美妙的。最后,强烈期待徐老师的进阶课程,这几个星期的学习让自己已经沉迷在JS之中了,真的是停不下来~~~'
+ };
+
+ // TODO
+ // 编写函数从json文件中读取内容,并对不同的数据采用不同的处理方式
+ // 然后将本js中的links和articles删除
+
+ var vm = new Vue({
+ el: '#app',
+ data: {
+ wordsList: [],
+ name: '',
+ account: '',
+ content: '',
+ fetchStatus: false,
+ links: {
+ 'home': 'http://js.xinshengdaxue.com',
+ 'logo': 'https://o4a7cbihz.qnssl.com/picture/57140c0c-4ffa-4dde-9757-570b53f96796',
+ 'avatar': 'https://ws1.sinaimg.cn/large/006tKfTcgy1fi7s7vo8y0j30hs0hsaay.jpg',
+ 'github': 'https://github.com/xugy0926/',
+ 'my_github': 'https://github.com/Dream4ever/',
+ 'segmentfault': 'https://segmentfault.com/u/samsara0511/articles/',
+ 'new_index': './parallel.html'
+ },
+ teammates: [
+ {
+ 'name': '何伟',
+ 'github': 'https://github.com/Dream4ever/',
+ 'avatar': 'https://avatars2.githubusercontent.com/u/2596367?v=4&s=460'
+ },
+ {
+ 'name': '王颖',
+ 'github': 'https://github.com/MaggieWong27',
+ 'avatar': 'https://avatars3.githubusercontent.com/u/30827246?v=4&s=460'
+ },
+ {
+ 'name': '王沙沙',
+ 'github': 'https://github.com/shashawang',
+ 'avatar': 'https://avatars3.githubusercontent.com/u/20803305?v=4&s=460'
+ },
+ {
+ 'name': '谢泓升',
+ 'github': 'https://github.com/Risexie',
+ 'avatar': 'https://avatars1.githubusercontent.com/u/30618014?v=4&s=460'
+ },
+ {
+ 'name': '伍帆',
+ 'github': 'https://github.com/french5',
+ 'avatar': 'https://avatars3.githubusercontent.com/u/20951309?v=4&s=460'
+ }
+ ],
+ articles: {
+ '前端相关资源汇总': 'https://github.com/Dream4ever/Coding-Life/blob/master/Front-End/Front-End%20Resource%20Collection.md',
+ 'Git 实战笔记': 'https://github.com/xugy0926/getting-started-with-javascript/blob/master/topics/Git%E5%AE%9E%E6%88%98%E7%AC%94%E8%AE%B0.md',
+ '《JavaScript 权威指南》勘误表中文版': 'https://dream4ever.github.io/Chinese-Errata-for-JavaScript-The-Definitive-Guide/',
+ '茴字的七种写法 - 论 Web 页面中的相对路径': 'https://github.com/Dream4ever/JavaScript/blob/master/topics/relative-path.md',
+ 'VSCode 应用笔记': '#'
+ },
+ feature: {
+ '轮播图加链接': '#',
+ '我的GitHub里程碑': '#',
+ '展示团队成员': '#',
+ '上传所有用到的图片并改用相对路径': '#',
+ '所有数据统一放到单个json文件中': '#',
+ '犀牛书中的代码单独放到JS文件中': ''
+ }
+ },
+ methods: {
+ mounted: function() {
+ // $('.carousel-inner').first().children().addClass('active');
+ // $('.carousel').carousel();
+ },
+ fetch: function () {
+
+ // 尽量使用点运算符访问对象属性
+ // https://stackoverflow.com/a/13192501/2667665
+ axios.get(api.words)
+ .then(function (response) {
+ if (response.status.toString() === '200' && response.statusText.toString() === 'OK') {
+ vm.wordsList = response.data.words;
+ // this.fetchStatus = true;
+ } else {
+ // this.fetchStatus = false;
+ }
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ },
+ submit: function () {
+
+ // extract();
+ JSON.parse(JSON.stringify({
+ // 为什么必须用这种写法才能检测出空值?
+ 'name': this.name.trim() || myWord.name,
+ 'account': this.account.trim() || myWord.account,
+ 'content': this.content.trim() || myWord.content
+ }));
+
+ // TODO
+ // 增加对用户输入的检查,必须全部填写内容后才可发送
+
+ // TODO
+ // 用户发送成功或者失败,都要有反馈
+
+ axios.post(api.sayToMe, myWord)
+ .then(function (response) {
+ console.log('data posted:\n');
+ console.log(response);
+ })
+ .catch(function (error) {
+ console.log(error);
+ });
+ },
+ extract: function () {
+
+ // 字符串空值的检测在下面的myWord赋值语句中无效,放到前面这里才行,为什么?
+ // var user_name = this.name.trim() || myWord.name,
+ // user_account = this.account.trim() || myWord.account,
+ // user_content = this.content.trim() || myWord.content;
+
+ // 为什么必须先stringify再parse才能成功?不能直接parse?
+ // 因为axois接收的data是JSON字符串,而如果直接把对象传过去,
+ // axios就会先按照默认的行为将其转换成字符串,转换结果和stringify是不一样的
+ // 而且不再parse一下的话,就只是单纯的字符串而不是JSON,所以无法得到预期的结果
+ return JSON.parse(JSON.stringify({
+ // 为什么必须用这种写法才能检测出空值?
+ 'name': this.name.trim() || myWord.name,
+ 'account': this.account.trim() || myWord.account,
+ 'content': this.content.trim() || myWord.content
+ }));
+ }
+ }
+ });
+
+ vm.fetch();
+})();
diff --git a/public/js/main2.js b/public/js/main2.js
new file mode 100644
index 0000000..11ee83a
--- /dev/null
+++ b/public/js/main2.js
@@ -0,0 +1,23 @@
+(function () {
+ 'use strict';
+
+ var bg = 'https://raw.githubusercontent.com/Dream4ever/Pics/master/matrix.jpg';
+
+ var vm = new Vue({
+ el: '#app',
+ methods: {
+ mounted: function () {
+ axios.get(bg)
+ .then(changeBg())
+ .catch(err => console.log(err));
+ }
+ }
+ });
+
+ vm.mounted();
+
+ function changeBg() {
+ var rootDiv = $('#app');
+ rootDiv.css('background-image', 'url(' + bg + ')');
+ }
+})();
\ No newline at end of file
diff --git a/public/lesson7/content.json b/public/lesson7/content.json
new file mode 100644
index 0000000..60c941b
--- /dev/null
+++ b/public/lesson7/content.json
@@ -0,0 +1,842 @@
+[
+ {
+ "avatar": "http://tva2.sinaimg.cn/crop.558.0.1143.1143.180/670e76acgw1ehgchgijn2j21kw0vyqrf.jpg",
+ "name": "Andrea",
+ "words": "运用逻辑优势,开启业余程序员大门!"
+ },
+ {
+ "avatar": "https://ws3.sinaimg.cn/large/006tNc79ly1fig6fhvtbvj30zk0zkn4f.jpg",
+ "name": "周泠秋",
+ "words": "在人们看来编程是一件很难的事,但是正因为难做起来才有意思啊"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tNc79gy1fio9xha9hjj30hs0hsdgr.jpg",
+ "name": "蔡东言",
+ "words": "一入编程深似海。。。。"
+ },
+ {
+ "avatar": "http://opkslf6o7.bkt.clouddn.com/image/jpg/%E5%BE%AE%E4%BF%A1%E5%A4%B4%E5%83%8F.JPG",
+ "name": "曹振",
+ "words": "利用这次难得的机会系统学习javascript和前端知识,向着全栈的目标前进"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tKfTcgy1fikl7frqgvj30hs0hsglv.jpg",
+ "name": "陈玲敏",
+ "words": "正在学Ruby On Rails。Javascript看着很强大,到哪都能遇到它。接触的时候有种很神奇的感觉。"
+ },
+ {
+ "avatar": "http://img0.imgtn.bdimg.com/it/u=1649639124,2757239308&fm=27&gp=0.jpg",
+ "name": "崔雨薇",
+ "words": "学习有时是甜的,开心到可以飞起来,有时候又很累。但是因为有了一起学习的同伴,相互鼓励,学习变得一直都很甜。希望能把JS学到溜,同时,特别期待老师会教其他的课程,在编程的路上越走越远。"
+ },
+ {
+ "avatar": "",
+ "name": "Elizabeth周丽",
+ "words": "2017年最重要的三件事之一就是学习编程,今年的目标是在年底时候成为高级新手,做出自己的网站。感谢新大开设的JavaScript,帮助我逐步打开编程世界的大门,让我有勇气在老师和同学们的陪伴下进入新的世界~ Hello,world!"
+ },
+ {
+ "words": "学习编程对我来说是进入一个完全崭新的世界,也是一个很大的挑战。\n能够学好编程对我来说不仅意味着掌握了一门新的语言,同时也是我开始学习《刻意练习》这本书之后,利用刻意练习来学习一门新技能的试验场。因此希望自己能获得这个双重成功。",
+ "name": "Explorer1982.",
+ "avatar": "http://pan.baidu.com/s/1eROFrmM"
+ },
+ {
+ "avatar": "https://ws3.sinaimg.cn/large/006tKfTcgy1fia6uqf70zj30l70l7tb7.jpg",
+ "name": "Jay Chen",
+ "words": "希望能够从Javascript入手,从基础掌握前后端的相关编程知识。"
+ },
+ {
+ "avatar": "https://ws3.sinaimg.cn/large/006tKfTcgy1fidwsnx71cj30u81hcq8n.jpg",
+ "name": "Liaoyuemin",
+ "words": "I want to be strong to enjoy an imperfect life "
+ },
+ {
+ "avatar": "http://pic6.58cdn.com.cn/zhuanzh/n_v1bl2lwkpsigsvriy7uftq.jpg",
+ "name": "刘军",
+ "words": "开拓视野,把想法透过编程得以实现,同时也是为跨界做准备"
+ },
+ {
+ "avatar": "https://ws2.sinaimg.cn/large/006tNc79gy1fiekv1tc2wj3069069mx4.jpg",
+ "name": "Risexie",
+ "words": "学习编程是我新生活的开始,是为了更好地和未来的世界相处"
+ },
+ {
+ "avatar": "https://ws3.sinaimg.cn/large/006tNc79ly1fj23gkeumnj30b40b4q4a.jpg",
+ "name": "陈如珊",
+ "words": "认真地玩编程,开心地学Javascript。"
+ },
+ {
+ "avatar": "http://a3.qpic.cn/psb?/V14GyYoI2uOb2N/wtaaC5ASnGKJjaZR78xoTkuJYXK17SEwf5OjVh7GjTk!/b/dD4BAAAAAAAA&ek=1&kp=1&pt=0&bo=kAGQAQAAAAARFyA!&vuin=591351718&tm=1502805600&sce=60-1-1&rf=viewer_4",
+ "name": "孙博",
+ "words": "制作出自己的JS小作品,享受并收获认真思考练习提升的过程"
+ },
+ {
+ "avatar": "http://othyo5zr8.bkt.clouddn.com/17-8-6/7536584.jpg",
+ "name": "王仲斌",
+ "words": "掌握一门技术,可以独立开发小程序,和一些工具,成为一个跨纬度生长的人"
+ },
+ {
+ "avatar": "https://ws2.sinaimg.cn/large/006tKfTcly1fic46qkg8zj30zk0zkwh0.jpg",
+ "name": "郭威",
+ "words": "打磨编程技能,解决自己和他人生活中问题,赚钱"
+ },
+ {
+ "avatar": "https://thumbnail0.baidupcs.com/thumbnail/2ff007c6dbf8d6676ac0523419d77453?fid=1141771415-250528-550510704890453&time=1501902000&rt=sh&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-%2BtK2iy3fz0O6ZFqA0gTdnADhVwI%3D&expires=8h&chkv=0&chkbd=0&chkpc=&dp-logid=5020581978850644106&dp-callid=0&size=c710_u400&quality=100&vuk=-&ft=video",
+ "name": "凌晓",
+ "words": "永远年轻,永远热泪盈眶。喜欢不断学习新知识的感觉,喜欢把学到的知识应用然后固化到骨髓里面的感觉。更何况编程是我们必须掌握的技能之一,所以我来了,而且会学好。还有曾经逼迫上大一的老弟自学编程,导致他产生了严重的挫败感,这次我打算自己先把知识掌握,然后再教他,重新培养他被我和编程打垮的自信。然后,希望能在课程上遇到志同道合的朋友,大家一起跟着高老师学习,相互帮助,共同进步。最后,真心喜欢浸淫在知识学习中的快感。"
+ },
+ {
+ "avatar": "http://b96.photo.store.qq.com/psb?/V132hQNs4gFlJL/DtXK2yG3MGq6Ghknb6CYgVuyrLXmyn8ahmLyXO0m4SI!/b/YWj8OTnxDAAAYj2hQTkqDQAA&bo=ngKqAQAAAAABBBQ!&rf=viewer_4",
+ "name": "郑超",
+ "words": "看看学完之后到底能用它来干点啥好玩的事情"
+ },
+ {
+ "avatar": "http://wx2.sinaimg.cn/square/95a79662ly1fidxfgug9fj20hs0hsta0.jpg",
+ "name": "安建才&刘蕾",
+ "words": "学习编程思维和学习如何运用编程数据解决问题,深夜加餐"
+ },
+ {
+ "avatar": "http://a2.qpic.cn/psb?/V11bQUyC41BSKW/cflhIsZGdGoKWSgWJBwAKBZXqyQWjW2weLdTh6AraeY!/b/dD8BAAAAAAAA&bo=fgKAAgAAAAARB84!&rf=viewer_4",
+ "name": "陈浩",
+ "words": "学习编程目的是想习得另一种看问题的思路"
+ },
+ {
+ "avatar": "http://wx2.sinaimg.cn/square/95a79662ly1fidxfgug9fj20hs0hsta0.jpg",
+ "name": "安建才&刘蕾",
+ "words": "学习编程思维和学习如何运用编程数据解决问题"
+ },
+ {
+ "avatar": "https://ws4.sinaimg.cn/large/006tNc79gy1fickawwmvxj30ou0oudhc.jpg",
+ "name": "吴魁拼",
+ "words": "区块链行业发展如此迅猛,我想进去看看!"
+ },
+ {
+ "avatar": "https://ws4.sinaimg.cn/large/006tNc79ly1ficrwvfngtj30wu0ihq5w.jpg",
+ "name": "尹志宝",
+ "words": "看了文章瞬间路转粉,迟到生来补交作业"
+ },
+ {
+ "avatar": "http://wx1.sinaimg.cn/small/006xcK8hgy1fimmji87nmj30hs0hs74k.jpg",
+ "name": "包国强",
+ "words": "改善当前的现状和不满,让自己有个更好的工作环境和薪资待遇,也可以通过学习编程思想运用到其他的方方面面,让自己的生活多姿多彩"
+ },
+ {
+ "avatar": "http://pan.baidu.com/s/1o8LXp6y",
+ "name": "Chloe",
+ "words": "学习编程让思维越狱"
+ },
+ {
+ "avatar": "https://ws4.sinaimg.cn/large/006tNc79gy1fiiip1u9jwj30hs0hs74e.jpg",
+ "name": "柴高平",
+ "words": "希望这次能够正真学会一门语言"
+ },
+ {
+ "avatar": "http://ww4.sinaimg.cn/large/74f67c55jw1disaov37shj.jpg",
+ "name": "陈德荣",
+ "words": "互联网的兴起,Web的流行,已经快二十年,创造了财富神话,改变了世界。JavaScript在Web的流行中,起来关键作用,为基于浏览器的复杂交互提供了可能。Web还会流行下去,它具有超越系统的普适交互特性,不管在Windows、Mac、Linux,不管是桌面还是移动设备,iOS or Anroid设备,都可以一次编写,到处运行。现在甚至可以在后端运行的node.js。Web、JS的标准也在不断进化。基于Web的应用越来越广泛。相信未来,JavaScript必将创造更多奇迹、越来越流行。学好这门语言是非常有必要的。"
+ },
+ {
+ "avatar": "https://ws2.sinaimg.cn/large/006tKfTcgy1fia3guals9j30e10dtdn3.jpg",
+ "name": "程君",
+ "words": "我想设计出属于自己的产品,成为一名程序员!"
+ },
+ {
+ "avatar": "https://ws3.sinaimg.cn/large/006tKfTcgy1fiqnq8hezhj30pt0pt0w6.jpg",
+ "name": "陈璐璐",
+ "words": "必备技能+1"
+ },
+ {
+ "avatar": "https://ws4.sinaimg.cn/large/006tKfTcgy1fikoe96wyej30hs0hsdga.jpg",
+ "name": "陈燕杏",
+ "words": "认真接触ruby语言是从两个月前开始的,学习全栈营的课程,有收获但是进步缓慢,学到目前的感觉还是不太懂,就连前面一课「提交一个项目」我都倍感吃力,基础不好,学习状态也不佳,我在想我是不是不适合学编程?想在几个月之间从小白入门编程于我难度还是挺大的,但是我会坚持学下去的,因为这是一门被人们认为要学会的技能,我就是想看看习得之后会给我带来多大的变化。"
+ },
+ {
+ "avatar": "https://github.com/Chenzd-homeland/sample_picture/blob/master/picture.jpg?raw=true",
+ "name": "陈自东",
+ "words": "通过学习JavaScript掌握大牛学习编程的方法,为学习别的编程技能打好基础。最终的目标是习得一项硬技能,换份有挑战性,能创造更大价值的工作。"
+ },
+ {
+ "avatar": "https://avatars3.githubusercontent.com/u/31364061?v=4&s=40",
+ "name": "陈子文",
+ "words": "延续儿时的兴趣!小时候爸爸给我买了学习机,有机会接触basic语言,当时没有老师指导,再加上那个学习机是不能存档的,对问题的不能解决之感和耐心的缺乏,无奈的放弃了编程学习.我也是个懒人,喜欢一次创建重复使用的路子,我认为计算机编程就是这样.我认为编程是能锻炼人的思维,帮助人更理性的思考问题,我希望自己学会后把这些方法都给我的儿子."
+ },
+ {
+ "avatar": "http://wx1.sinaimg.cn/mw690/539843d2gy1ficrbw1497j20hs0hsjrv.jpg",
+ "name": "戴军/cloudyview",
+ "words": "大学的时候学过一年的C,那个时候实话说,没好好认真学。工作出来了,从事的工作范围都是跟软件,互联网相关,但是,每次自己总觉得编程这样的事情,交给专业人士就好,我做好我的产品经理/项目经理/业务架构设计这些工作就好。后来自己出来创业,又接触了区块链这些领域,越发觉得完全不懂编程,越来越像文盲——完全看不懂人家在做什么。特别是区块链。我之前的认为,让技术的归程序员,让经济的,人文的,管理的这些归到各自的专业人士那里去吧。但是比特币给我的震撼是,中本聪这个人根本就是用密码学,用程序,用计算机,而且,最可怕的是用这背后的思维方式,在碾压经济学。我是学经济和管理的,这让我相当焦虑。由于区块链的关系,我知道了李笑来老师。后来,又学习了他的《通往财富自由之路》,一边学,一边思考着如何践行,如果让我的焦虑成为我的刚需。而后来,我知道了新生大学,进来就看到JS的课程。没说的,立刻上!我希望学了以后,我能更好的理解中本聪的论文,我能更好的看懂区块链的那些代码。如果可能,我希望自己能为这些做出一些贡献,多少都好。我知道有相当多的区块链项目是采用NODE.JS来写的,有一天,希望自己构思的项目,自己能动手写出来。这是我学习JS的愿望。PS:我在注册的时候,将姓名当成用户名来输入了。我正在跟客服交涉是否能修改这个姓名。目前先用这个cloudyview来做作业。"
+ },
+ {
+ "avatar": "http://a4.qpic.cn/psb?/V10782zs2lPwov/w*Os6Zhbo2hGum4pucwjDAcTuU387FoWmRkZxCH29Xs!/b/dPcAAAAAAAAA&ek=1&kp=1&pt=0&bo=OAQ4BAAAAAARFyA!&vuin=24603898&tm=1502848800&sce=60-2-2&rf=viewer_4",
+ "name": "崔淼",
+ "words": "从事信息化相关工作,但编程却是小白,希望通过新生大学这个平台,学习JavaScript,为自己打开多维成长之路。"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tNc79ly1fih8dej6twj3046046gln.jpg",
+ "name": "邓翔宇",
+ "words": "希望能入门编程,虽然对职业路径还没有规划,但是敲代码是我人生中遇到的最爽的一件事"
+ },
+ {
+ "avatar": "https://avatars0.githubusercontent.com/u/30835292?v=4&u=0828fdc04493f465d3a4ee0957fb8397e9c0d940&s=400",
+ "name": "刁志聪",
+ "words": "我学习JS的心愿是,先将容易上手的JS学透,然后应用在自己的领域里,如果可能,转行编程行业,把自己的想法用编程的方式展现出来,这将会是一件非常有趣的事"
+ },
+ {
+ "avatar": "https://avatars3.githubusercontent.com/u/7390760?v=4&s=400",
+ "name": "dongge",
+ "words": "JS是升职加薪的利器"
+ },
+ {
+ "avatar": "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgeticon?seq=659548762&username=@e7175d308edc5250999bdf0f6cc5ed3c&skey=@crypt_3e5c8b8b_404775965a35ed981c3bb72a9addcb03&type=big",
+ "name": "donglili",
+ "words": "在这个需要学习学习再学习的时代,有幸遇到了js,又恰好这个课程超便宜,为什么不学一下呢?走过路过不要错过。进来发现这个课程真是超值了,有老师和助教全天候服务。超赞!"
+ },
+ {
+ "avatar": "https://qlogo1.store.qq.com/qzone/50004612/50004612/100?1445774486",
+ "name": "段颖志",
+ "words": "已知比较关注编程,前两年自学过python,但由于各种变故没有持续下去。这次加入新大报了JS和python两门语言,希望通过这两门语言踏进编程的世界。学习编程的目的一是想理解编程的逻辑性,运用到生活中,二是想用编程做点什么事情,至于做什么还真不知道,学起来再看。"
+ },
+ {
+ "avatar": "http://a3.qpic.cn/psb?/V13RQJID39Shhk/d7.HmUGVCLCaS9.8wEeavMT8CsnCBhnasvTaha10u.U!/b/dG0BAAAAAAAA&bo=gAKAAgAAAAARBzA!&rf=viewer_4",
+ "name": "杜红霞",
+ "words": "我要学会编程,更好的生活和工作"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/ad915470gy1fid3b2869rj20qo0zkdmw.jpg",
+ "name": "方庆扬",
+ "words": "一想到以后可以在电脑上做出自己的东西,就很兴奋"
+ },
+ {
+ "avatar": "https://ws2.sinaimg.cn/large/006tNc79ly1ficho8d5amj30hs0hsdg6.jpg",
+ "name": "范青",
+ "words": "我在大学时学的应用电子专业,课程中偏爱数据结构、C语言,学得乐此不疲,成绩明显好于其他课程。工作后,工作内容与编程无关,记得刚开始还想学下当时的ASP开发,曾经抱书在公司翻看,很遗憾当时未建立起元认知能力、做自己最重要的事以及默默学起来等等概念,受周围环境影响较大,没多久就放下了。那段时间前后还买过《Java Programming Language》、《Java编程思想》,其实并没有学习,这几天重学编程,这两本书又找了出来,不知旧版本的价值是否已打折扣,这个待我慢慢体会。工作一段时间后,曾经业余时间基于已有平台制作过几个网站,并未深入编程语言,后来也仅是维护还既有的老用户,未再发展新客户,因为我未投入更多精力,老客户也所剩无几。又过了不少时间,自从小程序概念的出现起,看到过笑来老师鼓励大家学习,觉得应该是挺有趣,去图书馆借了本《编写可维护的javascript》,那时或因工作、生活的忙碌,或因并没有很明确的学习任务,自学并没有真正开始,直到现在,报名了新生大学的课程。这本已续借多次的书终于可以开始仔细阅读。目前我对javascript所能做的事还不太了解,只知道也许掌握了就可以做小程序了。希望能做出自己感兴趣、实用的小程序,还想象着也许可以尝试给我那所剩无几的网站客户做出小程序,如果他们中意,准备免费赠送老客户。P.S.很高兴能通过新大的课程进入了github平台,打开了一片新的视野。全英文的界面对于基本不用英语的人有相当的冲击力、也是一种激发,希望自己能多多练习,以后更多的用英语表达。"
+ },
+ {
+ "avatar": "https://ws2.sinaimg.cn/large/006tNc79gy1fi827p2y74j30go0go76d.jpg",
+ "name": "费玺光",
+ "words": "我可能还不太了解 JavaScript ,招聘的时候都是HTML/CSS/JavaScript,就想让我的前端开发水平更上一层,或者能领悟到更深的意义吧!"
+ },
+ {
+ "avatar": "https://ww3.sinaimg.cn/large/006tNc79ly1ficgraqd81j30jz0jzgqc.jpg",
+ "name": "冯凯",
+ "words": "I am on my way!"
+ },
+ {
+ "avatar": "http://oucyv4vzu.bkt.clouddn.com/tian.jpg",
+ "name": "geyee",
+ "words": "学习 JavaScript 的心愿:1.磨砺编程思维,践行编程习惯,能创建一些拿得出手的应用;2.让自己过得说的过去,信心与勇气;3.类 MOOC 学习环境下与他人更好的交流。"
+ },
+ {
+ "avatar": "http://wx2.sinaimg.cn/mw690/006yZIPkgy1fic9zmazatj30hs0hs0tq.jpg",
+ "name": "郭俏君",
+ "words": "想学习Javascript是机缘巧合的事,我一直想要学习编程,但没有什么目标语言,自学深感乏力,一般的编程课程又价格高昂,负担不起。看到新大开了编程课程,相信质量不错,价格又合理,特别是Javascript性价比超高,而且听说Javascript既能做前端,又能做后端,很全能的样子(虽然并不知道前端和后端是什么),最近又有时间就报了。报了之后,发现老师认真负责又幽默风趣,更加期待上课了(我绝对不是在拍马屁),希望学完后能正式脱离小白的身份。"
+ },
+ {
+ "avatar": "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgeticon?seq=1542306414&username=@27c8d42815d1807ccf3b7f9a827936a95cb05cf27362d9457f0f0d70eb6ec7ae&skey=@crypt_70df2d69_2b86dfdbb5a9008f98d1ac9c3d7f61ea&type=big",
+ "name": "韩猛",
+ "words": "在我心中“编程”一直都是很神圣的技能,也特别向往,希望有一天,自己也可以通过学习成为掌握这项技术的牛人。现在的职业发展受限希望学会一项新技能,开启一段新的职业生涯。让自己更有价值。将来能用JavaScript创造出自己的小程。认识更多的编程牛人,与牛人为伍。"
+ },
+ {
+ "avatar": "https://ws3.sinaimg.cn/large/006tNc79gy1fiej3i999vj30hs0hsaau.jpg",
+ "name": "韩巍",
+ "words": "成为技术大牛"
+ },
+ {
+ "avatar": "http://wx1.sinaimg.cn/mw690/9f4e25a9ly1filvlfthavj20be0bfdgp.jpg",
+ "name": "郝户",
+ "words": "Make America Great Again!"
+ },
+ {
+ "avatar": "https://visualhunt.com/photo/200318/",
+ "name": "郝凯歌",
+ "words": "技术是有价值的,未来更为凸显,现在才刚刚开始"
+ },
+ {
+ "avatar": "https://ws4.sinaimg.cn/large/006tNc79ly1fi8psvoa5gj305k05kt8z.jpg",
+ "name": "何伟",
+ "words": "前端在网站开发中所占的比重越来越大,Node.js也开始在后端领域崭露头角,因而与两者息息相关的JavaScript也变得越来越重要。学习编程语言不只是为了多掌握一门技能,它更是我们用全新的视角认识世界的一种方式。除此之外,学习编程技能还能够让我们抓住可能到来的机会,在未来的竞争中增加自己的竞争力的维度。就我自己而言,本来就是从事这个职业的,而且很喜欢这项工作,接着新生大学开通JavaScript课程的机会,继续深造,让自己的技能更上一层楼,何乐而不为?顺便在这里再推广一下自己在Github上的帐号:https://github.com/Dream4ever。"
+ },
+ {
+ "avatar": "https://github.com/albertschr/albertschr.github.com/blob/master/dogemoney.jpeg",
+ "name": "hitchhacker",
+ "words": "搞定JS."
+ },
+ {
+ "avatar": "https://o3b126ie1.qnssl.com/avatar/cbdb8537-f7a4-4273-b0e3-76ab95d03e66",
+ "name": "黄家树",
+ "words": "JavaScipt is a widely used language in the world. There is a greate need in the worktime, so I want to learn it."
+ },
+ {
+ "avatar": "https://ws2.sinaimg.cn/large/006tNc79gy1fifzn6nfwkj30hs0h8gmc.jpg",
+ "name": "黄晓晖",
+ "words": "学习javascript纯属偶然,我本来是新生大学的会员,改版后看到这个课程,既然可以从零基础学习,就尝试着接触一下编程的世界,就让我从javascript开始吧"
+ },
+ {
+ "avatar": "http://ou5vdfvru.bkt.clouddn.com/photo.jpg",
+ "name": "黄永飞",
+ "words": "你学习JavaScript的心愿,学会玩小程序"
+ },
+ {
+ "avatar": "https://ws4.sinaimg.cn/large/006tNc79gy1fim22xnv1oj30r80ra499.jpg",
+ "name": "黄志华",
+ "words": "太有趣了!我开始被这种多人协同的事情所着迷,我在设想为什么老师要我们提供头像,我想有一天老师会利用这些头像组成一个类似照片墙的东西?每个人还会自动浮现这句话!"
+ },
+ {
+ "avatar": "https://ws2.sinaimg.cn/large/006tKfTcgy1fii70fhp5jj30hs0hsaat.jpg",
+ "name": "胡传亮",
+ "words": "能够用JS改变生活状态,提升生活品质,在网络世界中起到些作用"
+ },
+ {
+ "avatar": "http://i1.bvimg.com/1949/cb3d28ecfd7f92b3t.jpg",
+ "name": "���쵤",
+ "words": "�����˽�ǰ�ˡ������Լ��������ص�֪ʶ�����Զ�������˼ά��"
+ },
+ {
+ "avatar": "https://ws3.sinaimg.cn/large/006tKfTcgy1fif52cwlloj30jz0k0dgj.jpg",
+ "name": "胡宜",
+ "words": "敲指令就能驱动电脑工作,这样很酷,我也想成为这样酷的人"
+ },
+ {
+ "avatar": "http://wx2.sinaimg.cn/mw690/005Egs8bgy1figzupy12yj30hs0hsaa8.jpg",
+ "name": "胡永",
+ "words": "学好js进入编程世界,了解区块链,为将来转行做准备"
+ },
+ {
+ "avatar": "https://lh3.googleusercontent.com/-aDYCfKxW2rw/V2igWiKBq0I/AAAAAAAAD7Q/Urqh9kcetOwMvyE1RdN7ovXzVXpg6W0vwCEwYBhgL/w140-h140-p/16084879805343795.jpg",
+ "name": "ianyang",
+ "words": "获得基本代码能力,便于鉴别开源项目真伪与品质"
+ },
+ {
+ "avatar": "https://ww3.sinaimg.cn/large/006tNc79ly1fibin27q4aj30hs0hs0tl.jpg",
+ "name": "江蓉",
+ "words": "虽然参加了全栈营的学习,但是javascript还是一点不懂,希望能够入门,谢谢老师!"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tKfTcly1fia8o6wzshj30hs0hr0up.jpg",
+ "name": "靳超",
+ "words": "你学习JavaScript的心愿:对我而言,程序并非一种语言,而是实现自由的工具。我想用想象力把工具带到更远的地方,而现在,从创建一个站点做起!"
+ },
+ {
+ "avatar": "http://image.jiantuku.com/17-8-9/54286073.jpg?attname=file_1502268260429_5d12.jpg&e=1502269210&token=el7kgPgYzpJoB23jrChWJ2gV3HpRl0VCzFn8rKKv:iDsZGCt1aRzOZmugi4kcIY4-EJo=",
+ "name": "郎建军",
+ "words": "This is the second time I learn Java Script. Last year I learned some all by myself. Then before mastering it, I gave up. One of the reason is that my working laptop was stolen and that made me mad and sad. This time I will try to catch up, master it and have some products."
+ },
+ {
+ "avatar": "https://i.loli.net/2017/08/17/5995a306c8ad6.jpg",
+ "name": "雷震",
+ "words": "好好学,管它有没有用,说不定以后就是工程师呢?"
+ },
+ {
+ "avatar": "http://b166.photo.store.qq.com/psb?/V11W2Ieo3T6gbv/xVmzvkTshEQqPQBZ6U83UDKhbdzR3.uHinYIHNUhPfg!/b/dKYAAAAAAAAA&bo=OAQ4BNAL0AsFCSo!&rf=viewer_4",
+ "name": "梁会锋",
+ "words": "感觉现在是一个全民学编程的时代,不想被时代抛弃。再一个就是便宜,哈哈"
+ },
+ {
+ "avatar": "https://ws3.sinaimg.cn/large/006tKfTcgy1filyapuztaj30hs0hsq3o.jpg",
+ "name": "梁信众",
+ "words": "希望通过学习编程思维,帮助总结出自己的生活原则,从而解决生活中的实际问题。也许这个想法在别人看来难以理解,但是在你做成任何事情之前,都需要有一个愿景或构想,有了此蓝图,才会有实现的可能性。"
+ },
+ {
+ "avatar": "https://ws4.sinaimg.cn/large/006tNc79gy1fieezsimgnj30lk0lk7wh.jpg",
+ "name": "lichen",
+ "words": "正在学习ruby on rails ,想通过学习JS来完善对编程的认知边界,同时补充一些知识技能。"
+ },
+ {
+ "avatar": "https://ws4.sinaimg.cn/large/006tNc79gy1fiqf2ameatj30hs0hsgmh.jpg",
+ "name": "lily(许丽)",
+ "words": "还有不到一个月的时间,我想在小宝贝出生之前来一次自我挑战,学编程是我曾经仅仅停留在脑海里,但从不敢真正想象的一件事儿,高阳老师的这个课让我想要通过学js,试图来一次别样的新生!感谢高阳老师,感谢同学们的帮助!今天高阳老师给我的远程协助,我突然想象,也许我通往这个世界之门将真正打开,我想我会爱上js~"
+ },
+ {
+ "avatar": "https://ws4.sinaimg.cn/large/006tKfTcgy1fidvof293rj309s0800uq.jpg",
+ "name": "李明星",
+ "words": "正在紧跟着老师的脚步领略编程语言JavaScript的魅力,希望这次的学习之旅能帮助我打开编程的暗门"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tKfTcgy1fijm1e02f7j30zk0zctad.jpg",
+ "name": "林德光",
+ "words": "以编程为生"
+ },
+ {
+ "avatar": "http://a3.qpic.cn/psb?/V13uYcBA2Bs7DK/29OCNJhoKlbukD0H.BS9cbtDBgINJQAO1B4GT44Ln5Q!/b/dD0BAAAAAAAA&bo=gAKAAoACgAIRCT4!&rf=viewer_4",
+ "name": "林细瑶",
+ "words": "打了一百遍退堂鼓,最后还是颤颤巍巍报了这门编程课——万一学会了呢!前天光下载git就费了好大劲,课前作业更是看不懂,硬着头皮去上第一节课,竟然完全听懂了!对,感觉真的是全懂了!但是,但是,好像作业还是不会做啊......今天又断断续续折腾了很久,终于来到这里。等会我敲下一步会报错吗?坑们,我又来了!"
+ },
+ {
+ "avatar": "http://osv97pbuy.bkt.clouddn.com/avatar_wechat.JPG",
+ "name": "李朋",
+ "words": "用JavaScript搞项目"
+ },
+ {
+ "avatar": "https://ws4.sinaimg.cn/large/006tKfTcly1fiduvhawdwj30iy0iygm9.jpg",
+ "name": "李涛",
+ "words": "对编程领域很好奇,而且感兴趣。希望真正会用git工具,使用GitHub创建个人主页,编辑文档。这几天下来,我始终处于对这些新概念的懵懂状态,一遍遍地从最初的预习作业开始重新操作,一步步地按照老师的文档描述去练习,不断加深理解。"
+ },
+ {
+ "avatar": "https://github.com/liujin1991/javascript/blob/master/wx.jpg",
+ "name": "刘锦",
+ "words": "抱歉,老师,我来晚了。中间好多节课都没听,这几天抓紧时间学习!"
+ },
+ {
+ "avatar": "https://wx4.sinaimg.cn/thumb300/7b535f23gy1fi9s6a7fixj20hs0hsaa9.jpg",
+ "name": "刘军",
+ "words": "我想试试从0开始能不能学好一项技能。"
+ },
+ {
+ "avatar": "http://pan.baidu.com/s/1mi5L9Rq",
+ "name": "刘丽媛",
+ "words": "没什么事,是睡一觉和喝一罐可乐解决不了的。所以,一般遇到问题我们都说不要轻易放弃,可有些事确实会损耗你的认知。这样你就不如去睡一觉,醒来后再去做,避免认知胶着的发生,反而会有好的结果。"
+ },
+ {
+ "avatar": "https://thumbnail0.baidupcs.com/thumbnail/6a64fde3ca59e4660be37f8d59adc28b?fid=2063916389-250528-1045738355729916&time=1504530000&rt=sh&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-uPJUshlmHxvd6yWLQ5V2uBzAAD4%3D&expires=8h&chkv=0&chkbd=0&chkpc=&dp-logid=5726183852813185133&dp-callid=0&size=c710_u400&quality=100&vuk=-&ft=video",
+ "name": "柳青",
+ "words": "学习编程思维,开发一款微信小程序"
+ },
+ {
+ "avatar": "http://ww1.sinaimg.cn/large/006axpoxly1fibksijahbj33402c0hdu.jpg",
+ "name": "刘儒勇",
+ "words": "会有javaScript做项目"
+ },
+ {
+ "avatar": "https://ws2.sinaimg.cn/large/006tKfTcly1fiig7mmw14j30hs0hsjua.jpg",
+ "name": "刘胜思",
+ "words": "从JavaScript开始,一步步构建起自己的编程技能树,这是我的7年目标之一!"
+ },
+ {
+ "avatar": "https://ws4.sinaimg.cn/large/006tNc79ly1fibk20u4ynj30ru0ronlf.jpg",
+ "name": "刘胜新",
+ "words": "学习本身就是有趣的事情、不为别的、只想做些有趣的事情"
+ },
+ {
+ "avatar": "http://a3.qpic.cn/psb?/ebfa945e-6b53-48b4-b671-f3abe4715eee/SOtY*57lbcOrPu08atEJbRU612e8Q6XGBG5QPir8cNk!/b/dG0BAAAAAAAA&bo=gAKAAgAAAAARBzA!&rf=viewer_4",
+ "name": "刘小昊",
+ "words": "想知道程序员的世界是怎样的,对此我非常好奇。"
+ },
+ {
+ "avatar": "https://qlogo1.store.qq.com/qzone/7249864/7249864/100?1461031672",
+ "name": "刘永军",
+ "words": "践行终身学习,结合公司需求,学以致用。"
+ },
+ {
+ "avatar": "https://pan.baidu.com/s/1boV6rHt",
+ "name": "刘争春",
+ "words": "被徐老师的超低价给吸引进来了,本来学的是python数据科学,哈哈哈!!!"
+ },
+ {
+ "avatar": "http://up.qqjia.com/z/13/tu14994_2.jpg",
+ "name": "李想(Ideal)",
+ "words": "通过学会一门编程语言,努力掌握计算机式的思维模型"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tNc79gy1fic8mdlpftj30sc0scgno.jpg",
+ "name": "李小欣",
+ "words": "继续在编程的奇妙世界里探索"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tKfTcly1fj23busdqjj30940b4teb.jpg",
+ "name": "李永静",
+ "words": "说实话这样的学习机会很少,大家平时工作都很忙,最大的感慨就是时间不够用的,老师能这样尽心尽力的教我们,群里有这么多热心的同学,我没有理由不好好学"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tKfTcgy1fi8vbcwpx0j30no0no0v5.jpg",
+ "name": "Rachel",
+ "words": "我想做一个小程序解决工作中重复的工作/我想参与未来的世界。"
+ },
+ {
+ "avatar": "https://avatars0.githubusercontent.com/u/384727?v=4&s=460",
+ "name": "蓉儿",
+ "words": "成为屌屌的全栈设计师"
+ },
+ {
+ "avatar": "https://ws3.sinaimg.cn/large/006tKfTcgy1fiihu6re29j30hs0hs3zk.jpg",
+ "name": "罗睿君",
+ "words": "学习编程思维"
+ },
+ {
+ "avatar": "http://www.spzwl.com/img/1111.jpg",
+ "name": "macheng",
+ "words": "成长是永远的刚需!"
+ },
+ {
+ "avatar": "http://pan.baidu.com/s/1boUksaV",
+ "name": "MaggieWong王颖",
+ "words": "希望能开发一个微信小程序记录外用内服药使用情况"
+ },
+ {
+ "avatar": "http://pan.baidu.com/s/1i5DtEct",
+ "name": "Marshalcy",
+ "words": "完成个人站,做出自己想要的效果。"
+ },
+ {
+ "avatar": "https://raw.githubusercontent.com/wiki/mdqsky/words-from-the-heart/xdjs-portrait.jpg",
+ "name": "闵东泉",
+ "words": "学习编程,获得新生!"
+ },
+ {
+ "avatar": "http://pan.baidu.com/s/1cpStK6",
+ "name": "欧阳春",
+ "words": "学习编程思维,现在才交作业,才搞懂"
+ },
+ {
+ "avatar": "http://pan.baidu.com/s/1eSlF58e",
+ "name": "潘琦",
+ "words": "学无止境,技多不压身,学到更要做到,享受琦妙之旅"
+ },
+ {
+ "avatar": "https://avatars0.githubusercontent.com/u/2305999?v=4&u=78e4d2861d39cfa64ef316a16ad0dfcacf486abd&s=400",
+ "name": "潘勇",
+ "words": "想建个个人网站。想玩公众号和小程序。想Get个高级、好玩、又可赚钱的技能:编程!"
+ },
+ {
+ "avatar": "http://oon3erbcp.bkt.clouddn.com/avata%28qiujingyu%29.png",
+ "name": "丘竟钰(一休)",
+ "words": "能让自己建立的网站更加生动活泼"
+ },
+ {
+ "avatar": "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgeticon?seq=656839578&username=@c44a7655c2d20258da570c60e428efe3&skey=@crypt_94c460b8_9409eab225957dfccb93d4736572eab0",
+ "name": "邵振",
+ "words": "培训学习的良好习惯,提升个人竞争力,提高自身的生活品质。"
+ },
+ {
+ "avatar": "https://github.com/zjutszl/my_post_images/blob/master/26155027.jpg?raw=true",
+ "name": "沈志立",
+ "words": "刚刚加入新大这个大家庭,久违了。老早就想学一门计算机语言了,但总是从入门到放弃:),希望这次能快速入门,正式进入程序员的世界~"
+ },
+ {
+ "avatar": "https://ws4.sinaimg.cn/large/006tKfTcgy1fidstmvzb0j30cs0csq3r.jpg",
+ "name": "祁曚",
+ "words": "学习javaScript,在网页前端使用,微信小程序的开发。学习新的技能"
+ },
+ {
+ "avatar": "http://ww3.sinaimg.cn/large/006tKfTcgy1fiutn4rxwhj30hs0hsq2z.jpg",
+ "name": "孙艳",
+ "words": "看不懂代码的UI不是好产品,哈哈"
+ },
+ {
+ "avatar": "https://github.com/Supersunlady/sample-picture/blob/master/weixin%20picture.jpg?raw=true",
+ "name": "孙艳红",
+ "words": "我是在看到笑来老师那句‘只要你文字能力好,就能学编程’之后挑起的好奇心,去年就想报Xdite编程课,但一直以为得先换一台高配置的苹果电脑,就作罢。这一切,我想可能也都是借口,比如这次的编程课我听了四节,不仅听得云里雾里,连Github网站注册和GIT都没安装。还好找到了战友,在队长的督促和陪伴下,昨晚装好GIT,今天注册好Github,现在开始写作业。这次得到素不相识的战友热情的帮助,很暖心,我希望自己能从一位小白变成以后也可以帮助别人的高手。"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tNc79ly1fiia00ci7sj30j60j7wf0.jpg",
+ "name": "suzichao",
+ "words": "路漫漫其修远兮,吾将上下而求索"
+ },
+ {
+ "avatar": "https://ws4.sinaimg.cn/large/006tKfTcgy1fichri1aobj30hs0bumxh.jpg",
+ "name": "唐剑锋",
+ "words": "学习了全栈营后,觉得还要提高,所以来学,希望能学到东西"
+ },
+ {
+ "avatar": "https://avatars1.githubusercontent.com/u/16713557?v=4&u=166356ef5dd53744cb3bd878a2a682268d5ad551&s=400",
+ "name": "汤宣洋",
+ "words": "学习JavaScript的心愿,希望成为一名能撸得了代码的产品经理O(∩_∩)O哈哈~"
+ },
+ {
+ "avatar": "http://pan.baidu.com/s/1jH4ojxO",
+ "name": "唐文东",
+ "words": "能对网页有更深入的了解;能做出一个爬虫软件,把每天翻网页找信息的工作交给电脑;最终能进入一个全新的世界开阔眼界"
+ },
+ {
+ "avatar": "https://avatars0.githubusercontent.com/u/25058977?v=4&s=400",
+ "name": "taobao",
+ "words": "如何从学过到精通"
+ },
+ {
+ "avatar": "https://avatars0.githubusercontent.com/u/22571496?v=4&u=4c4771e3dd0713292f18ec5f3283a6b2891fc504&s=400",
+ "name": "陶振伟",
+ "words": "学习js,让人生更多彩。"
+ },
+ {
+ "avatar": "你头像的链接地址",
+ "name": "你的名字",
+ "words": "你学习JavaScript的心愿"
+ },
+ {
+ "avatar": "http://photo.weibo.com/5054269711/photos/detail/photo_id/4122238134662918/album_id/3683440326228894#4122238134662918",
+ "name": "田智羽",
+ "words": "放下对编程的恐惧,进入这个新世界,让自己更有价值一点,这个世界更好一点"
+ },
+ {
+ "avatar": "https://user.qzone.qq.com/349004643/photo/59ae03c6-5475-4796-8f1b-f5749f74ea98/batchid/1502109563746000",
+ "name": "涂益浪_tuyilang",
+ "words": "学习javascript将是一件既有趣又有用的事情,顺便看看xdite老师的元学习方法是否在编程这件事上奏效,哈哈!"
+ },
+ {
+ "avatar": "http://ou7elf9tx.bkt.clouddn.com/blog/170805/lm1mcDh715.png?imageslim",
+ "name": "王长庆(Frank)",
+ "words": "Firstly, it is because XinShengDaXue put up this lesson, and I am a student who saw it. XinDa is a fantastic place and I love it, although I haven't known a lot about this lesson, but I believe I can learn much from it. Secondly, I have heard a lot about programming. This is a world made of CODE, so programmer can make many things by programming. I want to be a programmer, or be a man knowing something about programming at least. I think if my dream comes ture, my life will have more fun and more possibility. In one word, programming is a kind of magic in my eyes, JAVAscript is a chance for my to get this magic."
+ },
+ {
+ "avatar": "http://a1.qpic.cn/psb?/V122ytfQ2Wo0yN/kaa1B6eo0X*80AhXR1sXk3yzd4HQSpy8Or2XjJ2Nc10!/b/dD4BAAAAAAAA&bo=oAU4BAAUAA8RALU!&rf=viewer_4&t=5",
+ "name": "王凡豪",
+ "words": "我听说编程加音乐等于自由"
+ },
+ {
+ "avatar": "http://b131.photo.store.qq.com/psb?/V10MQthU4Wxqzy/QQOB.XuWvwI7ouyZAaVtDVt3T8.iR*FguIh*nLF2pAA!/b/dBseG06zAwAA&bo=ngL2AQAAAAABB0s!&rf=viewer_4",
+ "name": "王美玲",
+ "words": "我想学好这门课,这是我第一次正儿八经地上编程课;很幸运能遇到徐老师。"
+ },
+ {
+ "avatar": "http://b131.photo.store.qq.com/psb?/V10MQthU4Wxqzy/QQOB.XuWvwI7ouyZAaVtDVt3T8.iR*FguIh*nLF2pAA!/b/dBseG06zAwAA&bo=ngL2AQAAAAABB0s!&rf=viewer_4",
+ "name": "王美玲",
+ "words": "这是我的第一门编程"
+ },
+ {
+ "avatar": "https://thumbnail0.baidupcs.com/thumbnail/e198cb436ac867f5d7a3987b259154c3?fid=1263497160-250528-104582875615306&time=1504450800&rt=sh&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-SsJRsyAERIK1YHNRUAufKGDSFt0%3D&expires=8h&chkv=0&chkbd=0&chkpc=&dp-logid=5705134557209556634&dp-callid=0&size=c710_u400&quality=100&vuk=-&ft=video",
+ "name": "王沙沙",
+ "words": "你学习JavaScript的心愿:这次报js课,是因为公司之后会开发服务号和小程序,虽然我觉得自己短时间学了也不能独立做事,但或许以后可以帮忙。自己对编程有兴趣,以后有可能在工作中用到,公司是创业公司,希望自己能在不同维度找到能认领的工作;编程也是一个肯定要会的技能、工具,一个肯定要踏进的世界,实用又有趣,所以要学。我还希望学会之后能带着好友还有姨妈舅舅家其他小朋友们(想太远了哈哈)。为什么想学编程?又酷又可爱啊!!!在我心里,会用代码就是又酷又可爱又厉害的!(写这个主题的时候一开心又写了不少跟编程相关的其他的事,怕自己太啰嗦、纯自high,就不在这里放了,稍后放到自己公号里。)"
+ },
+ {
+ "avatar": "http://a2.qpic.cn/psb?/V13xDUYI0lw68j/PWRY82rfXz6V.fDKzLKPMLwPIGGHjsVGnu5OdrYjcFU!/b/dD8BAAAAAAAA&bo=ZwFnAQAAAAARADc!&rf=viewer_4&t=5",
+ "name": "王宣鼎",
+ "words": "这个人很懒,什么都没有留下。"
+ },
+ {
+ "avatar": "http://opkslf6o7.bkt.clouddn.com/image/jpg/%E5%BE%AE%E4%BF%A1%E5%A4%B4%E5%83%8F.JPG",
+ "name": "王一虎",
+ "words": "利用这次难得的机会系统学习javascript和前端知识,向着全栈的目标前进,感谢李朋、云飞和徐老师,今天开学第一天,迈开第一步,与孩子一起成长。"
+ },
+ {
+ "avatar": "https://ws2.sinaimg.cn/large/006tKfTcgy1fi86weipyzj31kw23v1ky.jpg",
+ "name": "王煜亮",
+ "words": "我想成为让世界变的更美好的人,想通过编程提高自己证明自己,可以认识更多朋友,赚更多钱"
+ },
+ {
+ "avatar": "http://r.photo.store.qq.com/psb?/V13hqj0m2qC5lF/lardD2PAalGPWSVgKLOS*2M.Yje7*wUAr1KmS6w9Tio!/r/dD0BAAAAAAAA",
+ "name": "王云飞",
+ "words": "相信自己,超越自己"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tNc79gy1fih299nuumj3064064q3c.jpg",
+ "name": "王智超",
+ "words": "希望能通过javascript,走入程序员的世界,从事让自己兴奋的工作"
+ },
+ {
+ "avatar": "https://avatars0.githubusercontent.com/u/24565307?v=4&s=460",
+ "name": "wayneWong 王炜",
+ "words": "之前学过一点 html和css, 还比较好理解,但是JS 就更偏向于 编程和代码了,所以想和名师系统的学一下"
+ },
+ {
+ "avatar": "http://upload-images.jianshu.io/upload_images/6581981-58c3a896aeabbb62.jpg",
+ "name": "陈为林",
+ "words": "跟着高阳老师学JS,好好学习,天天向上."
+ },
+ {
+ "avatar": "http://a1.qpic.cn/psb?/746f526d-5a85-440c-bd36-f4e5e4285e00/rftDdSBZXQwo2Tghi6DW18vkaZ.8EvrOzJKa*ZWn1cM!/b/dD4BAAAAAAAA&bo=kQKQApECkAIRADc!&rf=viewer_4",
+ "name": "温刘欣",
+ "words": "希望有拿得出手的技能,毕业后能到互联网公司工作。"
+ },
+ {
+ "avatar": "https://avatars1.githubusercontent.com/u/29993284?v=4&u=d5728c1c5fab19cbb0d0aa6c7f80cac6ced02cae&s=400",
+ "name": "温云新",
+ "words": "学习前端必修课,开发微信小程序"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tNc79gy1fjazppi0ssj30hs0hsdg5.jpg",
+ "name": "吴迪",
+ "words": "掌握编程技能,开发自己的应用。"
+ },
+ {
+ "avatar": "http://wx3.sinaimg.cn/large/68487189ly1fiel3jeyogj20hs0hsaa5.jpg",
+ "name": "吴高星",
+ "words": "Big JavaScript Small Life"
+ },
+ {
+ "avatar": "http://photo.weibo.com/1715758172/photos/detail/photo_id/4137694631471858/album_id/3440940430341158",
+ "name": "wuguohua",
+ "words": "学习编程是为了理解这个世界的底层代码,未来已来,未来不远。"
+ },
+ {
+ "avatar": "http://a2.qpic.cn/psb?/V11gEvOt4cCVez/6ge1tCxikCCzfOs7i9yjnmJjOPXGanLoRKRQyRl4bXs!/b/dIUBAAAAAAAA&ek=1&kp=1&pt=0&bo=gAKAAoACgAIRADc!&tm=1504231200&sce=0-12-12&rf=viewer_311",
+ "name": "夏能啟",
+ "words": "我想踏入编程大门,未来将会是万物互联的时代,掌握编程这门技术会是刚需,现状MR混合现实技术已经悄悄来临了,我想运用MR技术来解决社会上制造业的问题,首先我要学习编程来运用编程结合MR技术来解决制造业的问题,以上我暂时总结了这几点,希望和同学们一起进步,加油"
+ },
+ {
+ "avatar": "http://tva1.sinaimg.cn/crop.0.0.540.540.180/716bda7bjw8ei4se9cxfnj20f00f074i.jpg",
+ "name": "晓静",
+ "words": "成为神"
+ },
+ {
+ "avatar": "http://oqym24k6p.bkt.clouddn.com/xiaoyi/2017-08-11-IMG_5308.JPG",
+ "name": "小一",
+ "words": "不会编程的人终将被淘汰"
+ },
+ {
+ "avatar": "http://t3.qpic.cn/mblogpic/4627a939e664f144bb58/460",
+ "name": "谢玉辉",
+ "words": "我学习JavaScript纯属兴趣爱好,真要谈心愿的话,我最的心愿是成为时代的精英"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tKfTcgy1fi7s7vo8y0j30hs0hsaay.jpg",
+ "name": "徐高阳",
+ "words": "我想带领大家感受编程语言JavaScript的魅力,与同学们一起成长我感到非常的荣幸"
+ },
+ {
+ "avatar": "http://a3.qpic.cn/psb?/V10O9c6i3HeJsg/aQbyx7d0GV16sSzxKreB.pJXZsSWASh0p6UY0PUJT*E!/b/dCPS2FikLwAA&bo=VQOAAgAAAAAFB*A!&rf=viewer_4",
+ "name": "徐良海",
+ "words": "JAVA有一定基础,以前没用过GIT做版本管理,这个还不错,省得搭建SVN。。。。"
+ },
+ {
+ "avatar": "https://ws3.sinaimg.cn/large/006tNc79gy1fixa6njatgj30e80fn14g.jpg",
+ "name": "徐敏",
+ "words": "怀着好奇心报了JS课程,希望拓展自己的思维方式,继续跨界学习不同领域的知识。"
+ },
+ {
+ "avatar": "http://okr0iw9h2.bkt.clouddn.com/2017-08-08-yammy%20.png",
+ "name": "yammy",
+ "words": "JavaScript is a must in front-end, I'm using it for my projects now.And, I'd like to make it useful for me both in front-end and back-end. Wow, pretty cool."
+ },
+ {
+ "avatar": "http://a2.qpic.cn/psb?/V143oJCd4RvPsQ/Q*tFPW34KCpPIzfe4HooGNcHQKtwH.e60vJwNQqUfVg!/b/dB4BAAAAAAAA&bo=fgKAAn4CgAIRADc!&rf=viewer_4&t=5",
+ "name": "杨春光",
+ "words": "希望通过掌握编程技巧,设置财报参数,筛选上市公司股票,这样就不用自己挨个分析了!"
+ },
+ {
+ "avatar": "https://ws4.sinaimg.cn/large/006tNc79gy1fj4ibtff3tj30dt0dstjd.jpg",
+ "name": "李清凤",
+ "words": "我想与大家一起感受编程语言JavaScript的魅力,与同学们一起成长我感到非常的荣幸"
+ },
+ {
+ "avatar": "http://wx3.sinaimg.cn/mw1024/61cb7abdgy1fi85e6hp1tj20gx0gxgor.jpg",
+ "name": "Terry Yang",
+ "words": "学习新的技能,开启新的生活体验,走向下一个7年"
+ },
+ {
+ "avatar": "http://otnjt3h06.bkt.clouddn.com/image/%E5%BE%AE%E4%BF%A1%E5%A4%B4%E5%83%8F.jpg",
+ "name": "杨学武",
+ "words": "从开始学习编程到使用 ASP.NET 编写第一个管理系统网站,前后用时一年多,在这个过程中,一路磕磕绊绊,总是在为了新的界面、更友好的交互方式、更方便用户使用而发现跟多的东西,Bootstrap,JavaScript,jQuery......网站也从开始翻着一本《ASP.NET从入门到精通》找例子,在博客园找控件的用法,到现在会写一点简单的 JavaScript 语句响应用户操作,利用 Bootstrap 对网站进行布局。这次之所以要学习 JavaScript 课程,有两个目的。 一是想通过和老师一起学习,能够更好的运用 JavaScript,并且我也是因为在课程目录里看到老师会讲 jQuery ,觉得必须要上这个课。二是想和大家在一起学习,听老师讲课,能听到不一样的声音,吸收不一样的想法,学到更多编程思维方面的知识。"
+ },
+ {
+ "avatar": "https://images-na.ssl-images-amazon.com/images/M/MV5BMjA3ODA0MDI4OF5BMl5BanBnXkFtZTgwMjEyNzI3MDE@._V1_UY317_CR131,0,214,317_AL_.jpg",
+ "name": "杨业鹏",
+ "words": "感觉是被忽悠上了编程这条贼船,然后就停不下来了。目前还是处在糊里糊涂,跌跌撞撞的状态。加油吧,继续努力,总有一天你会感受到编程世界的无限魅力"
+ },
+ {
+ "avatar": "http://oug6btu3p.bkt.clouddn.com/%E5%A4%B4%E5%83%8F.jpg",
+ "name": "严情木",
+ "words": "Now, I’m in the JavaScript learning program, and start to use Gitbub. It’s very interesting. Can you feel my smile mouth?😀"
+ },
+ {
+ "avatar": "https://avatars1.githubusercontent.com/u/20189536?v=4&s=460",
+ "name": "李一淼",
+ "words": "想完完整整的学习一种编程语言;之前都半途而废了让我很懊恼;之前学过html等,对Java很感兴趣;同时我们公司的网站我也负责更新,觉得这个会对我有用处。最核心的就是想完整的学下来,即使他的意义对我的职业来说并没有看得到的连续性。"
+ },
+ {
+ "avatar": "https://o3b126ie1.qnssl.com/avatar/40663b07-cb8b-4ba0-90b9-bb30543289e1",
+ "name": "尹旭",
+ "words": "学习JavaScript,希望能在自己的工作中应用,提高效率,并尝试在业余时间利用编程技能为他人提供价值,获取额外收入"
+ },
+ {
+ "avatar": "http://a1.qpic.cn/psb?/62469739/FiPwDeU4ZhcyW0emCXEW1CUFrpDT5OGSDih8eEsYCOM!/b/dOcAAAAAAAAA&bo=gAKAAgAAAAABACc!&rf=viewer_4",
+ "name": "尤石磊",
+ "words": "一直对编程很感兴趣,这次新大提供的平台很不错,希望自己能够掌握点编程知识,对生活有所帮助。"
+ },
+ {
+ "avatar": "https://ss3.baidu.com/7LsWdDW5_xN3otqbppnN2DJv/pass/;q=90;g=0/sign=cb4604c004f41bd5961fe0fd61e1e6f6/8d5494eef01f3a299bad36259325bc315d607cf0.jpg",
+ "name": "乐瑞琪",
+ "words": "换一种角度,更好的认识这个世界!"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tKfTcgy1fij20nn60tj303b038jrm.jpg",
+ "name": "余剑科",
+ "words": "希望能学会编程,实现心中好玩的idea!!"
+ },
+ {
+ "avatar": "https://ws4.sinaimg.cn/large/006tKfTcgy1fj6r141ekij30b40b40v2.jpg",
+ "name": "zengjinlin",
+ "words": "学习编程思维,做出炫酷的网站,转行做软件工程师!"
+ },
+ {
+ "avatar": "https://ws3.sinaimg.cn/large/006tNc79gy1fi86vb5velj316022onpd.jpg",
+ "name": "张瑞瑞",
+ "words": "js用途很广,忍不住来学一下^_^"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tKfTcgy1fidqzwf3gyj30hs0hsaal.jpg",
+ "name": "张高阳",
+ "words": "改了好几遍,目前我已经不想多说什么了"
+ },
+ {
+ "avatar": "https://ws2.sinaimg.cn/large/006tNc79gy1fi8o1ri2hcj30hs0hsmy8.jpg",
+ "name": "张丽娜",
+ "words": "成为一名真正可以翱翔在编程世界的帅气程序媛"
+ },
+ {
+ "avatar": "https://ws2.sinaimg.cn/large/006tNc79ly1fien1cn3clj30bf0bfgll.jpg",
+ "name": "张倩",
+ "words": "习得新技能,培养自己的耐性。"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tKfTcgy1fie0w5fpl2j3075075mxg.jpg",
+ "name": "张雪冬",
+ "words": "我想知道极客世界的玩法,为人生增加更多可能性。"
+ },
+ {
+ "avatar": "https://ws3.sinaimg.cn/large/006tKfTcgy1fidqzbxnllj30fi0fiq4t.jpg",
+ "name": "zhaochunyi",
+ "words": "踏实上课,做作业,跟上步伐"
+ },
+ {
+ "avatar": "https://thumbnail0.baidupcs.com/thumbnail/52fb2c693131ce2841fc2bbbc0de538a?fid=1783299430-250528-187806972639896&time=1501862400&rt=sh&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-CKsa5G9nmK686CFhBAcdJHnvY%2Fw%3D&expires=8h&chkv=0&chkbd=0&chkpc=&dp-logid=5009830728287247056&dp-callid=0&size=c710_u400&quality=100&vuk=-&ft=video",
+ "name": "赵凯莉",
+ "words": "希望我能从中发现很多好玩有趣的事情!"
+ },
+ {
+ "avatar": "https://ws3.sinaimg.cn/large/006tKfTcly1fj7xh5emo8j30f10he48j.jpg",
+ "name": "赵睿",
+ "words": "争取用更少的代码,实现更多的事💪"
+ },
+ {
+ "avatar": "http://h.hiphotos.baidu.com/image/pic/item/71cf3bc79f3df8dc46979b75c711728b461028af.jpg",
+ "name": "赵晓昕",
+ "words": "补作业中,看了笑来老师的《人人都是工程师》感觉学习编程好像也没有很难,遇到任务,不断拆分,一步一步跟着走就能入门。以前学过VB,VF,都是皮毛。这次想认真学习一下。还有就是,会编程可以减少很多重复的工作,可以变得更牛,编程的世界有很多牛人和很多牛的做事方法做事思维,也可以提高自己。一个人对着电脑,按照老师的提示一步步前进,遇到困难的时候想想这么多同学已经做过了。他们能做到,我相信自己也可以,就这样一步一步走来。做了很多以前没有做过的事情,黑暗里走了这么久,解决了这么多困难,感觉以后再遇到什么没有解决的事情,也没什么好怕的了。感谢老师,带着我们一路前行"
+ },
+ {
+ "avatar": "https://sh-btfs-v2-yun-ftn.weiyun.com/ftn_handler/91ba18097625786d6930168e2ab53b09e144e2dbe4615d06ca5951997105a2a2e37a4d1d0624af9e3fd5f3e0e895862d2b55476d9cc6b4543f28bda1532e4cbf/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20170809192415.jpg",
+ "name": "赵一楠",
+ "words": "我希望学习JavaScript能帮我在北京找到一份月收入2万的工作"
+ },
+ {
+ "avatar": "http://opqyer7zj.bkt.clouddn.com/17-8-7/84970174.jpg",
+ "name": "郑承演",
+ "words": "多掌握一种实现数据可视化的方式;数据分析进阶"
+ },
+ {
+ "avatar": "https://thumbnail0.baidupcs.com/thumbnail/f8a43306dbdf7c8269d5edbd1c6e4922?fid=796796274-250528-84981343015016&time=1502715600&rt=sh&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-8XDhP2nMXn3yATa4orxXkSaEZB0%3D&expires=8h&chkv=0&chkbd=0&chkpc=&dp-logid=5239161895737332579&dp-callid=0&size=c710_u400&quality=100&vuk=-&ft=video",
+ "name": "周弘",
+ "words": "通过学习js,打开编程世界的大门,从而进入另一个世界,以期获得不一样的生活体验"
+ },
+ {
+ "avatar": "https://quanzhan-production.s3.amazonaws.com/uploads/user/image/662/thumb_WechatIMG4.jpeg",
+ "name": "周启洲",
+ "words": "学过php ruby js 由于太单调没有下功夫,希望完成本课程有所进步"
+ },
+ {
+ "avatar": "https://ws2.sinaimg.cn/large/006tKfTcgy1fii8sbeyjxj30hm0hmwf7.jpg",
+ "name": "周文明",
+ "words": "学会编程,用编程改变生活!"
+ },
+ {
+ "avatar": "http://wx4.sinaimg.cn/mw690/005tMBEFgy1fi8ts0awxnj30hs0hs3z9.jpg",
+ "name": "周子琦",
+ "words": "在校学生,编程小白。希望能学到一项新技能,学会用新的方式表达自己的创意。请老师和同学们多多指教。"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tKfTcgy1fi8vbcwpx0j30no0no0v5.jpg",
+ "name": "Rachel",
+ "words": "我想做一个小程序解决工作中重复的工作/我想参与未来的世界。"
+ },
+ {
+ "avatar": "https://ws1.sinaimg.cn/large/006tNc79gy1fidieqkz6hj30hs0hsq4m.jpg",
+ "name": "朱宁宁",
+ "words": "希望自己和孩子都不被现实世界限制,走向自由"
+ },
+ {
+ "avatar": "http://chuantu.biz/t5/164/1502191686x2890149518.jpg",
+ "name": "Eugene",
+ "words": "相信未来不懂编程就像以前的文盲,想活在未来。"
+ },
+ {
+ "avatar": "https://avatars0.githubusercontent.com/u/24871891?v=4&u=b493442c8b1f23e860c99323eb39bd9569c8979f&s=400",
+ "name": "邹海南",
+ "words": "自己对编程很感兴趣,觉得它能够让生活、学习更高效,也可以帮自己更好地理解这个信息世界!课程结束后,要建立自己的网站并维护好。也希望能在这里结识更多学习道路上的朋友,共同前进!!"
+ }
+]
\ No newline at end of file
diff --git a/public/lesson7/main.js b/public/lesson7/main.js
new file mode 100644
index 0000000..97ee8df
--- /dev/null
+++ b/public/lesson7/main.js
@@ -0,0 +1,21 @@
+(function () {
+
+ 'use strict';
+
+ var result = '';
+
+ $.ajax({
+ url: "https://raw.githubusercontent.com/Dream4ever/JavaScript/master/public/lesson7/content.json",
+ success: function (data, status) {
+
+ result = JSON.parse(data);
+
+ var vm = new Vue({
+ el: '#app',
+ data: {
+ words: result
+ }
+ });
+ }
+ });
+})();
\ No newline at end of file
diff --git a/public/lesson7/process.js b/public/lesson7/process.js
new file mode 100644
index 0000000..26e10d4
--- /dev/null
+++ b/public/lesson7/process.js
@@ -0,0 +1,80 @@
+// use strict 的合理用法
+// https://stackoverflow.com/a/4462560/2667665
+(function () {
+ 'use strict';
+
+ /* 可以引入 simple-git 这个库
+ 每次输出心里话之前,先自动更新一下,保证内容是最新的 */
+
+ var fs = require('fs'),
+ path = require('path'),
+ jsonfile = require('jsonfile');
+
+ var repoPath = path.join(__dirname, '../../../words'),
+ contentPath = path.join(__dirname, 'content.json'),
+ errorPath = path.join(__dirname, 'error.json');
+
+ var jsonFiles = [],
+ errorFiles = [],
+ fileContent = [];
+
+ // https://stackoverflow.com/a/4482701/2667665
+ if (!fs.existsSync(repoPath)) {
+
+ console.log('心里话项目的路径不正确,请检查路径');
+ return -1;
+
+ }
+
+ var files = fs.readdir(repoPath, function (err, files) {
+
+ if (err) {
+ console.log('读取文件夹失败,请检查原因');
+ return -1;
+ }
+
+ // jshint: i is already defined
+ // when defined in both for loops
+ // https://stackoverflow.com/questions/19412727/
+ var i;
+
+ for (i = files.length - 1; i >= 0; i--) {
+
+ var fullPath = path.join(repoPath, files[i]);
+
+ if (fs.statSync(fullPath).isDirectory()) {
+
+ files.splice(i, 1);
+
+ } else if (!files[i].endsWith('.json') &&
+ fs.statSync(fullPath).isFile()) {
+
+ files.splice(i, 1);
+ } else {
+
+ // 提前就把文件的路径拼接好
+ files[i] = fullPath;
+ }
+ }
+
+ jsonFiles = files;
+
+ for (i = 0; i < jsonFiles.length; i++) {
+
+ try {
+
+ // 如果用异步读取,读取失败的文件名无法传入回调函数
+ var content = jsonfile.readFileSync(jsonFiles[i]);
+
+ fileContent.push(content);
+
+ } catch (ex) {
+
+ errorFiles.push(path.basename(jsonFiles[i]));
+ }
+ }
+
+ jsonfile.writeFileSync(contentPath, fileContent);
+ jsonfile.writeFileSync(errorPath, errorFiles);
+ });
+})();
\ No newline at end of file
diff --git a/public/lesson7/style.css b/public/lesson7/style.css
new file mode 100644
index 0000000..0fad01d
--- /dev/null
+++ b/public/lesson7/style.css
@@ -0,0 +1,54 @@
+.bs-docs-header {
+ background-color: #6f5499;
+
+ padding-top: 60px;
+ padding-bottom: 60px;
+ font-size: 24px;
+ text-align: left;
+
+ color: #cdbfe3;
+}
+
+.bs-docs-header h1 {
+ font-size: 60px;
+ line-height: 1;
+ color: #fff;
+}
+
+body > .container {
+ margin-top: 60px;
+ width: 96%;
+}
+
+.left, .right {
+ margin-bottom: 40px;
+}
+
+.img-wrapper {
+ max-height: 100%;
+ padding: 0;
+ border: 1px solid #bbb;
+ box-sizing: border-box;
+}
+
+.avatar {
+ width: 100%;
+ height: 100%;
+ box-shadow: #aaa 2px 2px 2px;
+ float: none;
+}
+
+h3 {
+ /* https://stackoverflow.com/a/39417644/2667665 */
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: inline-block;
+ max-width: 100%;
+
+ margin-top: 0;
+}
+
+.left p, .left h3 {
+ text-align: right;
+}
\ No newline at end of file
diff --git a/public/style.css b/public/style.css
deleted file mode 100644
index d7bbf17..0000000
--- a/public/style.css
+++ /dev/null
@@ -1,13 +0,0 @@
-.main-header {
- padding-top: 60px;
- padding-bottom: 60px;
- margin-bottom: 30px;
- font-size: 24px;
- text-align: left;
- background-color: #6f5499;
-}
-
-.main-header h1 {
- margin-top: 0;
- color: #fff;
-}
\ No newline at end of file
diff --git a/topics/closure-scope-chain.md b/topics/closure-scope-chain.md
new file mode 100644
index 0000000..1be7dd7
--- /dev/null
+++ b/topics/closure-scope-chain.md
@@ -0,0 +1,159 @@
+# [翻译] 实例剖析 JavaScript 闭包及作用域链
+
+原文链接:[Explaining JavaScript Closure & Scope Chain with Examples](https://community.risingstack.com/explaining-javascript-closure-scope-chain-examples/)
+
+---
+
+JavaScript 这门语言中的 **继承** 和 **作用域** 与大多数编程语言都不一样,只有对这些概念有了清晰的理解,在写代码的时候才能充分利用它们的特性,同时避开那些 **坑**。
+
+该系列文章的第一篇解释了[《JavaScript 原型链和继承》](https://community.risingstack.com/javascript-prototype-chain-inheritance/)。
+
+## 前言
+
+在开发 JavaScript 程序的时候,有一类 bug 总是与不恰当地使用闭包(closure)有关(主要是在写异步代码的时候)。虽然可以换别的方式写代码来避开这些坑,但是弄清楚了 **闭包** 和 **作用域链** 这两个“坑”,我们便能扬其长避其短,充分发挥其特性。
+
+## 匿名函数与状态
+
+问题的根源,在于函数的 **状态**。在 JavaScript 中,这个状态叫做函数的作用域(scope)。在创建函数时(TODO: 这个创建指的是定义,还是调用?)会顺带声明函数体内的所有局部变量,作用域中所保存的,就是所有这些局部变量的 **引用**。对于命名函数(非匿名函数)来说,定义函数的代码不管是在文件中的什么位置,都会由于声明提前/作用域提升(hoisting),导致它在代码顶部就有作用域了(TODO: 顶部,是指最外层代码,还是代码物理位置的顶部?)。匿名函数则不同,作用域只存在于函数定义所在的地方(TODO: 再往后就没有了?用完就销毁?闭包除外?)。
+
+## JavaScript 闭包实例
+
+闭包:捕捉一个对象,将其与原本的作用域分离开来,在捕捉这个对象的函数中永远可以访问这个对象,这种行为,就叫闭包(TODO: 比如使局部变量脱离原本的作用域,在全局或者其它地方始终可用?)。
+
+下面的代码就演示了在不希望使用闭包的时候,却意外触发了闭包特性的情况。
+
+```javascript
+var helloStr = 'world';
+
+var sayHello = function(name) {
+ return function() {
+ console.log('Hello ' + name + '!');
+ }
+};
+
+var sayGreeting = sayHello(helloStr);
+
+helloStr = 'Bob';
+sayGreeting(); // => Hello world!
+```
+
+上面这段代码,本意是想用函数引用字符串 `helloStr`。但是!这个函数实际上将它首次执行时,`helloStr` 的 **值** 永远地保存在函数里了。
+
+我们再来看看这个异步版本的计数器。
+
+```javascript
+for (var i = 0; i < 4; i++) {
+ setTimeout(function() {
+ console.log(i);
+ }, 1000);
+}
+```
+
+是不是以为会依次输出 1 到 3?啊哈。
+
+```javascript
+4
+4
+4
+4
+```
+
+怎么样?惊不惊喜?意不意外?在这段代码里,我们本来是想利用闭包的特性,在每次循环执行完的 1 秒钟之后,输出当前的 `i` 的值。但是!实际上,在四次循环执行完的 1 秒钟之后,代码引用的是 `i` 当前的值:4。要理解函数什么时候会永远地保存一个变量的值,我们就要先了解一下作用域。
+
+## 什么是作用域?
+
+如果把 JavaScript 中的每个函数都看成是一部状态机的话,作用域就是其 **状态**。(状态机的相关知识,可查看阮一峰的 [《JavaScript与有限状态》](http://www.ruanyifeng.com/blog/2013/09/finite-state_machine_for_javascript.html) 这篇文章,可以有一个基础的了解。)不管 JavaScript 程序的指针走到什么地方,都会有一个作用域。如果指针在函数内,则这个作用域就是该函数的作用域。如果没有作用域,其实就是位于全局作用域中。可以把作用域看作具有下面这种结构的对象:
+
+```javascript
+{
+ _scope,
+ variables
+}
+```
+
+`_scope` 变量指向的作用域就是程序的指针所在的位置:创建函数的时候,指向的就是函数的作用域;如果指向的是全局作用域,这个变量的值就是 `null`。这样一来(TODO: 怎么就创建作用域链了?说来就来?),就会创建一个作用域链(scope chain)。`variables` 则是对所有函数实参及函数内声明的局部变量的映射:一旦这些映射中的某个变量变化了,它在 `variables` 这个映射里的入口(entry)也会对应变化。
+
+## 闭包和作用域是怎么走到一起的?
+
+使用变量的时候,程序会遍历整个作用域链,直到找到这个变量的入口为止。(TODO: 对于全局变量,程序直接在全局对象中查找,函数内的变量呢?通过闭包?)
+
+重新声明(按下面的代码来看,就是赋值)一个变量,或者将其作为参数传给函数(从下面的代码来看,并不是简单地作为参数传递给函数),都会将其从原本在作用域链中的位置抽离出来。
+
+```javascript
+var str1 = 'hello';
+// 重新声明变量 => 重新声明的是 str1?
+var str2 = str1;
+str1 = 'goodbye';
+// 重新声明变量,会将其与原本的引用隔离开来
+console.log('str2: ' + str2); // => str2: hello
+console.log('str1: ' + str1); // => str1: goodbye
+```
+
+```javascript
+var str1 = 'hello';
+var printVar = function(v) {
+ return function() {
+ console.log(v);
+ }
+};
+// 将变量作为函数参数传入函数中
+var printHello = printVar(str1);
+str1 = 'goodbye';
+// 作为参数传入函数的变量,会将其传入函数时的值保存在函数的作用域中
+printHello(); // => hello
+```
+
+在文中的第一个示例代码段里,由于字符串作为参数被传入了函数,并继续存在于函数的作用域中,因此其原本的值被保留下来了。即使之后在函数外部又更改了该字符串的值,但是在这个函数里依然保存的是该字符串之前的值。
+
+对于第一个示例代码段,当程序执行到最后:指针位于 `console.log()` 语句的时候,作用域链是下面这样的。
+
+- scope(return 语句中的函数的作用域?)
+- scope.scope(sayGreeting 函数的作用域?)
+ - name: 'world'
+- scope.scope.scope(全局对象)
+ - sayHello: 函数
+ - helloStr: 'Bob'
+ - sayGreeting: 函数
+
+对于异步版本计数器的示例代码,在程序执行 1 秒钟之后,指针位于 `console.log()` 语句的时候,每次执行循环时的作用域链是下面这样的。
+
+- scope(setTimeout 中的匿名函数的作用域?)
+- scope.scope(全局对象)
+ i: 4
+
+如果想要把这个异步版本的计数器,写成能够输出我们期望的值的版本,就可以像下面这样写,获取每次循环时 `i` 的值,而不是它的最终值。
+
+```javascript
+var logI = function (i) {
+ return function () {
+ console.log(i);
+ };
+};
+
+for (var i = 0; i < 4; i++) {
+ setTimeout(logI(i), 1000);
+}
+```
+
+虽然代码看起来和前面的差不多,但是在这段代码里,`logI` 中的 `i` 的值在 `return` 语句中的匿名函数的作用域之外是无法存取的。这是 JavaScript 中设置私有变量的一种方法。
+
+## 进阶:立即调用函数表达式(Immediately Invoked Functional Expression)
+
+立即调用函数表达式(IIFE):在 JavaScript 中,将变量和方法声明在作用域内,可以将它们变成私有的(private)。jQuery 这样的库就是如此构建的。将 `window` 对象作为参数传入 IIFE 中,就可以将 IIFE 里的部分内容导出至全局命名空间中。
+
+```javascript
+(function(global) {
+ var privateVariable = 'No one can ever see me or change me outside of this scope';
+ var publicVariable = 'No one can change me, but some can see me';
+
+ global.getPublicVariable = function() {
+ return publicVariable;
+ };
+})(window);
+```
+
+这样一来,`window` 对象就有 `getPublicVariable` 这个方法了。
+
+---
+
+好吧,翻译完了这篇文章,对于闭包和作用域链还是没弄清楚……得再看看别的文章……
diff --git a/topics/git.md b/topics/git.md
deleted file mode 100644
index 5bfa7d2..0000000
--- a/topics/git.md
+++ /dev/null
@@ -1,189 +0,0 @@
-# Git常用操作笔记
-
-## 为什么要先add再commit呢?
-
-徐老师周五中午加餐,给大家讲解git基本操作的涵义。借着这个机会,我也来说一下我对git add、git commit的理解吧。
-
-### git add
-
-这个命令存在的意义,是让我可以只提交(commit)一部分文件。为什么会有这样的需求?
-
-举个例子,我想写个网站,那么一般都是一次写一个小功能,写完了再写下一个小功能。
-
-假如我今天时间有限,但是客户又想看我完成了哪些工作。
-
-注册功能我写完了,是文件a.js;登录功能还没写完,是文件b.js。
-
-那么我用git add a.js,将这个文件加入暂存区。
-
-然后执行git commit -m "XXX",将这个文件提交至本地仓库。
-
-再用git push origin master,将修改推送至服务器。
-
-这样,客户就能够在网上看到我今天完成的注册功能了。
-
-参考资料:
-
-- [Git: add vs push vs commit](https://stackoverflow.com/questions/6143285/git-add-vs-push-vs-commit/)
-- [When should I use git add?](https://stackoverflow.com/questions/3673537/when-should-i-use-git-add/)
-
-### git commit
-
-git的一大功能,就是可以将文件退回到某次commit之前的版本,也就是笑来老师说的时光机。
-
-这个功能要怎么用呢?我们继续用上面的例子。
-
-假设在编写注册功能的时候,我commit了两次:第一次只完成了基础的注册功能,第二次增加了对用户密码强度的检验。
-
-但是在我的客户试用注册功能的时候,发现检验密码强度的功能有问题,需要暂时取消密码强度的检验,这个时候应该怎么做呢?
-
-我就可以用git reset或者git revert命令,来撤销最近一次的commit,并执行git push。这样,网站就只有基础的注册功能,没有密码强度检验功能了。
-
-参考资料:
-
-- [How to undo the last commits in Git?](https://stackoverflow.com/questions/927358/how-to-undo-the-last-commits-in-git/)
-- [Undoing Changes](https://www.atlassian.com/git/tutorials/undoing-changes/)
-
-## 和老师的仓库保持同步
-
-因为自己和老师的仓库都是一直在更新,所以每次提交前,需要先将自己的仓库(包括远程和本地)同步为老师仓库的最新状态,然后再提交自己的更改。
-
-首先,添加徐老师的仓库,并命名为upstream,方便以后再次调用。
-
-```bash
-git remote add upstream https://github.com/xugy0926/getting-started-with-javascript.git
-```
-
-然后将老师的仓库中的内容下载至本地。注意,下载至本地的内容,和自己的仓库是互不干扰的。
-
-```bash
-git fetch upstream master
-```
-
-这时,徐老师仓库的最新内容已经下载至本地了。
-
-我们先不急着合并进来,先看看自己的仓库和老师的仓库有哪些不同。
-
-```bash
-git diff upstream/master
-```
-
-下图是执行后的结果。
-
-
-
-注意,执行`git diff`后,终端会进入vim环境,注意看图中最后一行行首的冒号。按一下`q`键,退出vim环境即可。
-
-对比完徐老师和自己仓库的不同之后,就要把这些内容(upstream/master,代表upstream这个源的master分支)合并到自己的仓库中了。
-
-```bash
-git merge upstream/master
-```
-
-然后就可以提交自己的更改,或者进行其它操作了。
-
-## 善用分支功能
-
-### 新建功能分支,各自完成不同的需求
-
-因为自己一边要做笔记,一边还想向徐老师的项目上提PR。由于笔记还没写完,但是笔记已经有过多次commits了,所以在提PR的时候,不想把自己的笔记提交上去。
-
-虽然可以通过git revert或者git reset来撤销commit,但是自己还想保持commit历史的完整性。
-
-这个时候,就可以从徐老师的仓库上新建一个分支work用来提交PR,默认的分支master则用来做笔记,两边互不干扰,又能同时完成两项任务。
-
-首先,将老师的仓库的最新版拉到本地(添加upstream源的操作请查看上一小节的内容,此处不再重复)。
-
-```bash
-git fetch upstream master
-```
-
-用拉到本地的仓库新建一个隶属于自己仓库的分支work。
-
-```bash
-git checkout -b work upstream/master
-```
-
-将91d4fce这次commit(修改老师文章中文字错误和格式的操作)放入新增的work分支中。
-
-```bash
-git cherry-pick 91d4fce
-```
-
-将本地分支work推送至服务器上,并指定origin为默认主机。完成之后,在网页端提交自己的PR即可。
-
-```bash
-git push -u origin work
-```
-
-等到暂时没有PR需要提交了,并且自己的作业也写完的时候,就可以将先将work分支与徐老师最新的代码同步,然后再将work分支同步到master分支上就行了。
-
-参考资料:
-
-- [How to “pull request” a specific commit](https://stackoverflow.com/questions/34027850/how-to-pull-request-a-specific-commit/)
-- [How to synchronize two branches in the same Git repository?](https://stackoverflow.com/questions/4010962/how-to-synchronize-two-branches-in-the-same-git-repository/)
-- [Git远程操作详解](http://www.ruanyifeng.com/blog/2014/06/git_remote.html)
-
-### 同步某分支至本地
-
-因为上面新建的work分支只在办公室的台式机上有,家里的笔记本上并没有这个分支。为了在家里也能够继续学习,就需要把这个分支同步到家里的电脑上。
-
-最开始是用关键字`git clone branch`来查找方法的,试了一下之后发现这个关键字搜到的解决方法,只是把远程分支的文件下载到本机,本机并没有之前所建立的work分支,所以需要更换搜索关键字。
-
-想到可以用`git pull`将代码更新至本地,尝试了一下,发现本地并没有将work分支同步下来。
-
-于是又用`how to pull new branch from remote`作为关键字来Google,参照着这篇教程[Syncing](https://www.atlassian.com/git/tutorials/syncing)操作,终于成功了。
-
-先是将work分支拉至家里的笔记本上,这时候work还没有合并至本机的仓库中。这样可以避免操作错误,影响本机的仓库。
-
-```bash
-git fetch origin work
-```
-
-接着再将work分支合并至本机的仓库之中。
-
-```bash
-git merge origin/work
-```
-
-最后再切换一下分支,就可以在家里的笔记本上继续快乐地学习了~
-
-```bash
-git checkout work
-```
-
-参考资料:
-
-- [How to clone a single branch in git?](https://stackoverflow.com/questions/1778088/how-to-clone-a-single-branch-in-git)
-- [Syncing](https://www.atlassian.com/git/tutorials/syncing)
-
-### 删除无用分支
-
-有时候,只是想新建一个分支,测试一下某个功能。测试完成之后,这个分支就用不到了,那就需要把这个分支删掉。
-
-在Google中用关键字`git remove branch`搜一下,看到StackOverflow上就有一篇文章,很完整地列出了删除分支的方法:[How do I delete a Git branch both locally and remotely?](https://stackoverflow.com/questions/2003505/how-do-i-delete-a-git-branch-both-locally-and-remotely/)。
-
-#### 同时删除本地和远程分支
-
-`git push -d`命令用于删除远程分支,`git branch -d`命令则用于删除本地分支。
-
-```bash
-git push -d origin test
-git branch -d test
-```
-
-#### 强制删除本地分支
-
-有时候会提示本地分支无法删除,如果确定要执行删除操作的话,那我们就来个强制执行。
-
-注意这里的`-D`是大写,编程输入代码时,大小写一定要看仔细。
-
-```bash
-git branch -D work
-```
-
-参考资料:
-
-- [How do I delete a Git branch both locally and remotely?](https://stackoverflow.com/questions/2003505/how-do-i-delete-a-git-branch-both-locally-and-remotely/)
-
-### 重命名分支
diff --git a/topics/js-definitive-guide.md b/topics/js-definitive-guide.md
new file mode 100644
index 0000000..aeb5969
--- /dev/null
+++ b/topics/js-definitive-guide.md
@@ -0,0 +1,1240 @@
+# 《JavaScript 权威指南》学习笔记
+
+```text
+是否需要重新调整为 JS 文件?各章、节、小节依次是嵌套的对象,输入章、节、小节名称,即输出该小节关键知识点。
+Lexical.Charset.CaseSensitive // 输出关键知识点
+```
+
+---
+
+# 词法结构
+
+## 字符集
+
+### 区分大小写
+
+```js
+var a = 0;
+var A = 1;
+```
+
+### Unicode 转义序列
+
+```js
+"café" === "caf\u00e9" // => true: \u00e9 的含义见下面“字符串”一节中的“字符集和内码”这一小节
+```
+
+### 标准化
+
+```js
+"caf\u00e9".normalize() // => "café": 返回标准化的 Unicode 字符串
+```
+
+## 注释
+
+```js
+// 单行注释
+/* 注释段 */ // 另一个注释段
+
+/*
+* 多行注释
+*/
+```
+
+## 直接量
+
+```js
+12 // 数字
+1.2 // 小数
+"hello js" // 字符串
+'hi' // 也是字符串
+true // 布尔值
+/javascript/gi // 正则表达式直接量
+null // 空
+[1, 2, 3] // 数组
+a = { x: 1, y: 2 }; // 对象
+```
+
+## 标识符和保留字
+
+```js
+// 下面的都是合法的标识符
+i
+my_variable_name
+v8
+_dummy
+$str
+sí
+π
+```
+
+```js
+// 以下是各类保留字
+break
+null
+/* 未来版本的 ES 中会用到 */
+const
+super
+/* 在严格模式下是保留字 */
+let
+yield
+arguments
+eval
+/* Java 的关键字 */
+abstract
+private
+/* 全局变量和函数 */
+Infinity
+eval
+```
+
+## 可选的分号
+
+```js
+var a
+a
+=
+3
+console.log(a)
+/* JavaScript 会识别为:var a; a = 3; console.log(a); */
+```
+
+# 类型、值和变量
+
+对象本质上就是属性名(key)和属性值(value)之间的映射表。
+
+```javascript
+// 普通对象
+Person: {
+ "name": "Henry",
+ "age": 28
+}
+
+// 数组对象
+num = [1, 1, 2, 3, 5, 7];
+
+// 函数对象
+function add(a, b) {
+ return a + b;
+}
+```
+
+JavaScript 语言的核心部分还定义了三种常用的类。
+
+```javascript
+// 日期类
+var date = new Date();
+
+// 正则类
+var pattern = /s$/;
+
+// 错误类
+var err = new Error();
+```
+
+JavaScript 是面向对象语言。
+
+```js
+sort(a); // 结构化编程语言,只能这样对数组排序
+a.sort(); // 面向对象语言,调用数组的方法即可
+```
+
+下面是可以拥有方法的数据类型。
+
+```javascript
+// 对象类型
+Person.talk()
+
+// 数字类型
+(1.23e+20).toFixed(2)
+
+// 字符串类型
+'123-234-345'.split('-')
+
+// 布尔类型
+true.toString()
+```
+
+## 数字
+
+### 整型直接量
+
+```javascript
+0
+0xff // 十六进制 <-> 255(十进制)
+0377 // 八进制 <-> 255(十进制) 在ES6的严格模式下是禁止的
+```
+
+### 浮点型直接量
+
+```javascript
+3.14
+.12
+6.07e23
+1.2E-15
+```
+
+### 算术运算
+
+```javascript
+// Math 对象的函数和常量
+Math.pow(2, 53)
+Math.PI
+Math.random()
+```
+
+加餐:四则运算和比较。参考链接:
+
+- [【科普向】JavaScript的四则符和比较符](https://zhuanlan.zhihu.com/p/19735745)
+
+上溢和下溢:
+
+```javascript
+// Infinity 和 NaN: 运算出现特殊值的情况
+
+// Infinity
+1 / 0
+Number.MAX_VALUE + 1E300
+
+// -Infinity
+-1 / 0
+-1 / Number.MIN_VALUE
+
+// NaN
+0 / 0
+
+// +/-0
+Number.MIN_VALUE / 2 // => 0
+-Number.MIN_VALUE / 2 // => -0
+1 / Infinity // => 0
+-1 / Infinity // => -0
+```
+
+### 二进制浮点数和四舍五入错误
+
+```javascript
+(.3 - .2) !== (.2 - .1) // => true: 因为 JS 中的浮点数只是对应实数的近似表示
+```
+
+**解决方法**:对于精度要求高的场合,可用大整数进行运算,记得保证最终值的小数点位数不要错就可以。
+
+加餐:特殊值的判断。
+
+```javascript
+NaN != NaN // => true: 只能通过该等式或 isNaN() 函数判断是否为 NaN
+isFinite(x) // 只有在参数为 NaN、Infinity 或 -Infinity 时才为 false
+1 / 0 !== 1 / -0 // 只有在这个时候,0 和 -0 才不相等
+```
+
+### 日期和时间
+
+```javascript
+var then = new Date(2011, 0, 1, 17, 10, 30);
+var now = new Date();
+var elapsed = now - then; // 单位为毫秒
+now.getFullYear() // => 2017
+// 为什么月份从 0 开始,而天数从 1 开始?按欧美的星期记法,每周也是从 0,即周日开始?
+// https://stackoverflow.com/a/15799570/2667665
+now.getMonth() // => 8: 从 0 开始的月份,而不是从 1
+now.getDate() // => 19: 从 1 开始的天数
+now.getDay() // => 2: 周一至周六分别为 1~6,周日为 0
+```
+
+## 文本
+
+### 字符集和内码
+
+> 不影响基本使用,暂时不用深究这一部分。
+
+JavaScript 采用 UTF-16 编码的 Unicode 字符集,每个字符均用无符号的 16 位值表示。
+因为有很多符号要表示,所以 Unicode 是分区定义的,每个区也称为一个平面(plane),可存放 65536(2^16)个字符。
+最前面的 65536 个字符位称为基本平面(BMP),它的码点范围为:`0 ~ 2^16 - 1`,对应的 16 进制就是 `U+0000 ~ U+FFFF`。所有最常见的字符都在这个平面,这也是 Unicode 最先定义和公布的一个平面。
+剩下的字符都放在辅助平面(SMP),码点范围从 `U+010000` 开始。
+
+```javascript
+U+0000 // => null: 0000 为码点(code point),也是该字符的编号
+U+597D // => '好'
+```
+
+参考资料:[Unicode与JavaScript详解](http://www.ruanyifeng.com/blog/2014/12/unicode.html)
+
+**注意**:JavaScript 中并没有表示单个字符的“字符型”,只有字符串这一种类型。
+
+### 字符串直接量
+
+```javascript
+"" // => 空字符串: 包含 0 个字符
+'test'
+"3.14"
+'name="myForm"' // 由单引号定界的字符串,里面可以包含双引号,但不能再包含单引号了,否则将以内部出现的第一个单引号作为字符串的结束位置
+"It\"s my life" // 由单引号/双引号定界的字符串,如果内部必须包含相同的引号,则内部包含的引号左侧一定要加上转义字符 \
+"This string\n has two lines" // 字符串内可以包含换行符 \n
+```
+
+```javascript
+// 在 ES5 中,下面几行字符串实际输出时只有一行,行末加反斜线是为了标记下一行还是该字符串的内容,并不是换行,\n 才是换行
+"one\
+long\
+line"
+```
+
+### 转义字符
+
+反斜线(\)符号后面加一个字符,该字符就不再表示它们的字面含义了。所有的转义字符及其含义如下表所示。
+
+| 转义字符 | 含义 |
+| - | - |
+| `\o` | NULL字符(\u0000) |
+| `\b` | 退格符(\u0008) |
+| `\t` | 水平制表符(\u0009) |
+| `\n` | 换行符(\u000A) |
+| `\v` | 垂直制表符(\u000B) |
+| `\f` | 换页符(\u000C) |
+| `\r` | 回车符(\u000D) |
+| `\"` | 双引号(\u0022) |
+| `\'` | 撇号或单引号(\u0027) |
+| `\\` | 反斜线(\u005C) |
+| `\xXX` | 由两位十六进制数 XX 指定的 Latin-1 字符 |
+| `\xXXXX` | 由四位十六进制数 XXXX 指定的 Unicode 字符 |
+
+**注意**:只要反斜线(\)出现在上表中字符之外的地方,则都忽略该反斜线,比如 `\#` 和 `#` 相同。
+
+### 字符串的使用
+
+```javascript
+msg = 'Hello' + ', ' + 'world' // 字符串直接量的拼接
+greeting = msg + ' ' + name // 字符串直接量和变量的拼接
+s.length // 字符串的长度
+var s = 'hello, world' // 定义字符串
+s.charAt(0) // => 'h': 第一个字符
+s.charAt(s.length - 1) // => 'd': 最后一个字符
+s.substring(1,4) // => 'ell': 游标在 1~3 之间的字符,即第 2~4 个字符
+s.slice(-3) // => 'rld': 最后 3 个字符
+s.indexOf('l') // => 2: 字符 l 第一次出现时的游标
+s.indexOf('l', 3) // => 3: 从位置 3 开始第一次出现字符 l 的位置
+s.lastIndexOf('l') // => 10: 字符 l 最后一次出现时的游标
+s.split(', ') // 用 ', ' 逗号加空格将字符串分割成数组
+s.replace('l', 'L') // => 'heLlo, world': 替换字符串中首个小写字符 l 为大写字符 L
+s.toUpperCase() // => 'HELLO, WORLD': 字符串中所有字母变为大写
+```
+
+**注意**:前面说过,字符串是不可变类型,所以 `replace()` 和 `toUpperCase()` 这样的方法返回的是新字符串,原字符串不会发生变化,除非用 `str = str.toUpperCase()` 这样的方法对字符串进行重新赋值。
+
+在 ES5 中,字符串可以当做只读数组,就是说可以用访问数组元素的方式来访问字符串中的单个字符:
+
+```javascript
+s = 'hello, world';
+s[0] // => 'h'
+s[s.length - 1] // => 'd'
+```
+
+### 模式匹配
+
+JavaScript 定义了 `RegExp()` 构造函数,用来创建 “表示文本匹配模式” 的对象,这些模式称为 “正则表达式(regular expression)”。
+
+RegExp 并不是 JavaScript 的基本类型,它和 Date 类型一样,只是一种具有实用 API 的特殊对象。
+
+String 和 RegExp 对象均定义了利用正则表达式进行模式匹配和查找/替换的函数。
+
+RegExp 也有直接量写法,可以直接在 JavaScript 程序中使用。在两条斜线 `//` 之间的文本构成了一个正则表达式直接量,第二条斜线之后还可以跟随一个或多个字母,用来修饰匹配模式的含义。
+
+```javascript
+/^HTML/ // 匹配以 HTML 开始的字符串
+/[1-9][0-9]*/ // 匹配一个非零数字,后跟任意个任意数字
+/\bjavascript\b/i // 匹配单词 'javascript',忽略大小写。\b 用于匹配一个词的边界,所有非大小写罗马字母、数字或者下划线的字符,都是一个词的边界
+```
+
+RegExp 对象定义了很多有用的方法,字符串同样具有可以接收 RegExp 参数的方法。
+
+```javascript
+var text = 'testing: 1, 2, 3'; // 定义用于演示文本匹配的字符串
+var pattern = /\d+/g // 匹配包含至少一个数字的实例
+pattern.test(text) // => true: 匹配成功,pattern.test(text) 测试字符串 text 是否匹配 pattern 这个模式
+text.search(pattern) // => 9: 首次匹配成功的字符串中第一个字符的位置,位置下标从 0 开始
+text.match(pattern) // => ['1', '2', '3']: 所有匹配成功的内容组成的数组
+text.replace(pattern, '#') // => 'testing: #, #, #': 将所有匹配成功的内容换成 replace() 方法中第二个参数的值
+// TODO
+text.split(/\D+/) // => ['', '1', '2', '3']: 为什么截取出来的数组,第一个元素是空字符串?text.match(/\D+/) 得到的结果也只是 'testing: `,并不包含后面的 `, `
+```
+
+## 布尔值
+
+用途:通常用于 JavaScript 的控制结构中。
+
+仅有的几个会被转换成 `false` 的假值(可用 `undefined ? true : false` 进行判断,不能用 `undefined = false` 进行判断):
+
+```javascript
+undefined
+null
+0
+-0
+NaN
+'' // 空字符串
+```
+
+### 布尔运算符
+
+```javascript
+a && b // a 和 b 均为真值时,表达式才为真
+a || b // a 或 b 至少有一个为真值时,表达式就为真
+```
+
+## null 和 undefined
+
+| null | undefined |
+| - | - |
+| 表示数字、字符串和对象是“无值”的。 | 表示变量没有初始化。 |
+| | 如果查询对象属性或数组元素的值时返回 undefined,就说明这个属性或者元素不存在。 |
+| | 无返回值的函数也会返回 undefined。 |
+| 适合表示程序级的、正常的或在意料之中的值的空缺 | 适合表示系统级的、出乎意料的或类似错误的值的空缺 |
+
+- 相等判断运算符 `==` 认为两者是相等的,需要用严格相等运算符 `===` 才能判断出两者是不相等的。
+- 两者都不包含任何属性和方法,使用 `.` 或 `[]` 来存取他们的成员或方法时,都会产生一个类型错误:`TypeError: Cannot read property 'toString' of null/undefined`。
+- 如果要赋值给变量或者属性,或者作为参数传入函数,建议用 null。
+
+```javascript
+typeof null // => 'object'
+typeof undefined // => 'undefined'
+```
+
+## 全局对象
+
+当 JavaScript 解释器启动时,或者任何 Web 浏览器加载新页面时,就会创建一个新的全局对象,并给它一组自定义的初始属性:
+
+- 全局属性,比如 undefined、Infinity 和 NaN
+- 全局函数,比如 isNan()、parseInt() 和 eval()
+- 构造函数,比如 Date()、RegExp()、String()、Object() 和 Array()
+- 全局对象,比如 Math 和 JSON
+
+全局对象的初始属性并不是保留字,但应该当做保留字来对待。
+
+在代码的最顶级,可以用 JavaScript 关键字 `this` 来引用全局对象:
+
+```javascript
+var global = this; // 定义一个引用全局对象的全局变量
+```
+
+对于客户端的 JavaScript,在其表示的浏览器窗口中的所有 JavaScript 代码中,`Window` 对象充当了全局对象。这个全局 Window 对象有一个属性 window 引用其自身,它可以代替 this 来引用全局对象。Window 对象不只是定义了核心的全局属性,还针对 Web 浏览器和客户端 JavaScript 定义了一小部分的其它全局属性。
+
+```javascript
+var global = window;
+global.Infinity; // => Infinity
+global.isNaN(1); // => false
+global.Date(); // => "Fri Sep 22 2017 23:46:10 GMT+0800 (CST)"
+global.Math.random() // => 0.26739690031767305
+```
+
+初次创建时,全局对象定义了 JavaScript 中所有的预定义全局值。用户自定义的全局值也包含在其中。如果代码中声明了一个全局变量,那么这个全局变量就是全局对象的一个属性。
+
+## 包装对象
+
+在 JavaScript 中,一般只有对象才有属性和/或方法(方法是不是也可以看作属性的一种?)。但为什么字符串、数字和布尔值也有属性和方法呢?
+
+```javascript
+var s = 'hello world'; // 定义字符串
+var word = s.substring(s.indexOf(' ') + 1, s.length); // 使用字符串的属性
+```
+
+只要引用了字符串 s 的属性,JavaScript 就会将字符串的**值**,通过调用 new String(s) 的方式转换成对象,这个由值转换而来的对象,继承了字符串的方法,并被用来处理**属性的引用**。一旦属性引用结束,这个新创建的对象就会被销毁。
+
+看看下面的代码,思考一下它的执行结果:
+
+```javascript
+var s = 'test'; // 创建一个字符串
+s.len = 4; // 给它设置一个属性
+var t = s.len; // 查询这个属性
+```
+
+运行这段代码时,最后得到的 t 的值是 undefined。为什么会这样?原因在第二行代码中。第二行代码创建了一个临时的字符串对象,并给其 len 属性赋值 4,随即就销毁了这个对象。这样一来,原始的字符串 s 其实并没有 len 这个属性。第三行代码通过原始的字符串值创建一个新字符串对象,并尝试读取其 len 属性,而这个属性其实并不存在,结果自然是 undefined 了。
+
+上面的代码说明,在读取字符串、数字和布尔值的属性或方法时,这些类型表现的像对象一样。但不要试图给其属性赋值:修改只是发生在临时对象身上,并且这个临时对象是立即销毁的。
+
+综上所述,存取字符串、数字或布尔值的属性时,所创建的临时对象被称作**包装对象**,它只是偶尔用来区分字符串/数字/布尔类型的值和对象的。
+
+上面的代码隐式创建了包装对象,也可以通过 String()、Number() 或 Boolean() 构造函数来显式创建包装对象:
+
+```javascript
+var s = 'test', n = 1, b = true; // 分别创建一个字符串、数字和布尔值
+var S = new String(s); // 一个字符串对象
+var N = new Number(n); // 一个数值对象
+var B = new Boolean(b); // 一个布尔对象
+S === s; // => false: s 是一个字符串,而 S 则是一个字符串对象,注意两者的区别
+```
+
+## 不可变的原始值和可变的对象引用
+
+### 不可变类型
+
+JavaScript 中的原始值(undefined、null、布尔值、数字和字符串)与对象(包括数组和函数)的根本区别就是:原始值是不可更改的,任何方法都无法更改/突变(mutate)一个原始值。
+
+改变数字或者布尔值的说法本身就说不通,而对字符串来说,每次修改后的字符串就已经不是之前的字符串了。
+
+原始值的比较是**值**的比较:只有它们的值相等时,两个原始值才相等。
+
+```javascript
+var s = 'hello'; // 定义一个字符串
+s.toUpperCase(); // => 'HELLO': 虽然返回了大写的字符串,但原来的字符串 s 并没有被改变
+s // => 'hello'
+```
+
+### 可变类型(对象引用)
+
+对象和原始值不同,首先,它们是可变的——也就是说它们的值是可以修改的:
+
+```javascript
+var o = { x: 1 }; // 定义一个对象
+o.x = 2; // 修改对象属性值来更改对象
+o.y = 3; // 增加对象属性值来更改对象
+```
+
+### 比较两个对象
+
+比较两个对象并不是比较他们的值,而是比较两个对象的引用。两个属性及值完全相同的对象,也是可以不相等的;各个元素完全相等的两个数组也是可以不相等的。
+
+```javascript
+var o = { x: 1 }, p = { x: 1 }; // 具有相同属性的两个对象
+o === p // => false: 两个单独的对象永不相等
+var a = [], b = []; // 两个单独的空数组
+a === b // => false: 两个单独的数组永不相等
+```
+
+### 可变类型的复制
+
+对象通常被称为“引用类型”,以和 JavaScript 的基本类型相区分。专业点来说就是:对象的值都是引用,比较对象就是比较引用:只有引用了同一个基对象时,两个对象才相等。
+
+```javascript
+var a = []; // 定义一个引用了空数组的变量 a
+var b = a; // 变量 b 引用同一个数组
+b[0] = 1; // 通过变量 b 来修改引用的数组
+a[0] // => 1: 变量 a 也会被修改
+a === b // => true: a 和 b 引用的是同一个数组,当然相等
+```
+
+由上面的代码可以看到,把对象赋值给变量时,只是把对象的“引用”赋值过去了,并没有把对象再复制一份。如果用这种方式把一个对象赋值给多个变量,那么任意一个变量修改了对象,其它变量都会受影响。
+
+如果想要像不可变类型那样,每个变量都对应的是自己的“值”,就要像下面的例子一样,把对象的每个属性(数组的每个元素)显式地复制一份。
+
+```javascript
+var a = { x: 1, y: 2 }; // 待复制的对象
+var b = {}; // 将要复制到的空对象
+for (var i in a) { b[i] = a[i]; } // 遍历 a 并将其属性复制到 b 中
+
+var a = ['a', 'b', 'c']; // 待复制的数组
+var b = []; // 将要复制到的空目标数组
+for (var i = 0; i < a.length; i++) { b[i] = a[i]; } // 遍历 a 并将其元素值复制到 b 中
+```
+
+## 类型转换
+
+### 特殊值
+
+以下仅列出几种特殊情况:
+
+1. 对应的布尔值为 false 的值:undefined、null、""(空字符串)、0、-0、NaN
+1. 对应的数字为 NaN 的值:undefined、"one"、['a']、function(){}(任意函数)
+1. 对应的对象会抛出异常的值:undefined、null(均会 throws TypeError,比如调用 `toString()` 方法时)
+
+参考资料:
+
+- [对于以下现象,有没有一种通用的判断规则?](https://segmentfault.com/q/1010000010976877?):回答中详细讲解了 JavaScript 中的类型转换。
+
+### 显式类型转换
+
+可以使用各种类型的构造函数进行转换。
+
+```javascript
+Number('3') // => 3
+String(false) // => 'false': 使用 false.toString() 也有同样效果
+Boolean([]) // => true: 空数组为 true,空对象也是如此,这是个知识点
+Object(3) // => 结果等同于 new Number(3)
+```
+
+注意:只有 null 或者 undefined 没有 `toString()` 方法,其它值调用该方法的执行结果,一般和 `String()` 方法的返回结果是一样的。
+
+对 null 和 undefined 使用 `Object()` 函数不会抛出异常,只是返回一个新建的空对象。
+
+#### 进制转换
+
+`toString()` 方法可以将数字转换为指定的进制。
+
+```javascript
+var n = 17;
+binarl_string = n.toString(2); // => '10001'
+octal_string = '0' + n.toString(8); // => '021'
+hex_string = '0x' + n.toString(16); // => '0x11'
+special_string = 'xx' + n.toString(7); // => 'xx23'
+```
+
+#### 设置小数点及有效数字位数
+
+`toFixed()` 不使用科学记数法。
+
+```javascript
+var n = 123456.789;
+n.toFixed(0); // => '123457'
+n.toFixed(2); // => '123456.79'
+n.toFixed(5); // => '123456.78900'
+```
+
+`toExponential()` 始终将数字转换为科学记数法,小数点前只有一个数字。
+
+```javascript
+n.toExponential(1); // => '1.2e+5'
+n.toExponential(5); // => '1.23457e+5'
+```
+
+`toPrecision()` 则根据设置的有效位数,来决定是使用普通记数法还是科学记数法。
+
+```javascript
+n.toPrecision(4); // => '1.235e+5'
+n.toPrecision(7); // => '123456.8'
+n.toPrecision(10); // => '123456.7890'
+```
+
+#### 解析字符串中的数字
+
+`Number()` 可将字符串中的数字解析成整数或浮点数直接量,但只按十进制转换,并且字符串尾部不能有非法字符——只能有数字或空格。
+
+`parseInt()` 用于解析字符串中的数字并转换成整数,但是数字之前只能有空格或者正/负号,如果有其它字符,就都会返回 `NaN`。
+
+```javascript
+parseInt('3 a'); // => 3
+parseInt(' +3'); // => 3
+parseInt('0x3'); // => 3
+parseInt('-3.2'); // => -3
+parseInt(' -+3'); // => NaN
+parseInt('.3'); // => NaN
+parseInt('$3'); // => NaN
+parseInt('~3'); // => NaN
+parseInt('a3'); // => NaN
+```
+
+`parseInt()` 还可接收第二个参数,用于指定第一个参数的进制。如果第一个参数中的部分数字不属于第二个参数指定的进制,那么就直接忽略。
+
+```javascript
+parseInt('10', 2); // => 2
+parseInt('112', 2); // => 3
+parseInt('211', 2); // => NaN
+parseInt('077', 8); // => 63
+```
+
+`parseFloat()` 与 `parseInt()` 类似,除了不接受用于指定进制的第二个参数之外,其它方面和 `parseInt()` 都相同。
+
+```javascript
+parseFloat('3.14 ab 2.13'); // => 3.14
+parseFloat('0x112', 16); // => 0
+```
+
+### 运算符的隐式类型转换
+
+```javascript
+1 + '2' // => '12': 有字符串则转换成字符串
++'1' // => 1: 等于 Number('1'),一元 + 将操作数转换为数字
+!!null // => false: 可用于特殊类型的快速判断,一元 ! 将操作数转换为布尔值并取反
+```
+
+### 对象到原始值的转换
+
+#### 到布尔值的转换
+
+所有的对象(数组和函数也是对象)转换为布尔值后都为 true,包装对象也是如此:`new Boolean(false)` 并不是原始值,而是一个对象,转换为布尔值后也为 true。
+
+```javascript
+Boolean({ x: 1 }) // => true
+Boolean([]) // => true
+Boolean(() => { console.log('123'); }) // => true
+```
+
+#### 到字符串的转换
+
+转换规则只适用于本地对象(native object),宿主对象(如浏览器定义的对象)则根据各自规定的规则进行转换。
+
+**注意**:对象和函数在转换成字符串的时候,要先用圆括号括起来,再调用 `toString()` 方法,数组类、正则类和日期类则不需要。当然了,如果不确定什么时候该用括号,那就一直都用括号就好了。
+
+- 数组类返回的是用逗号分隔的各元素。
+- 函数类返回的是函数定义的源码字符串。
+- 正则类返回的是正则字符串直接量。
+- 日期类返回的是方便阅读的日期。
+
+```javascript
+({ x: 1, y: 2}).toString() // => "[object Object]"
+[1, 2, 3, 4].toString() // => "1,2,3,4"
+(function f(x) { x; }).toString() // => "function f(x) { x; }"
+/\d+/g.toString() // => "/\d+/g"
+new Date().toString() // => "Tue Oct 10 2017 14:53:49 GMT+0800 (中国标准时间)"
+```
+
+细节探究:在 JavaScript 中,对象到字符串的转换经历了以下几个步骤:
+
+1. 如果对象有 `toString()` 方法,就调用该方法。如果返回的是原始值并且不是字符串,则转换为字符串。然后返回字符串结果。
+1. 如果对象没有 `toString()` 方法,或者该方法返回的不是原始值,则 JavaScript 就会继续调用 `valueOf()` 方法。如果对象有该方法就调用它,如果返回的是原始值并且不是字符串,则转换为字符串。然后返回字符串结果。
+1. 如果以上都不满足,说明 JavaScript 无法通过 `toString()` 或者 `valueOf()` 方法获得原始值,则将抛出一个类型错误异常。
+
+#### 到数字的转换
+
+转换规则和到字符串的转换一样:只适用于本地对象(native object),宿主对象(如浏览器定义的对象)则根据各自规定的规则进行转换。
+
+如果存在原始值,则默认转换为原始值。由于对象是复合值,并且大多数对象无法真正表示为一个原始值,因此默认的 `valueOf()` 方法只是简单地返回对象本身。
+
+下面这些转换结果中,需要注意的是日期类的转换:它返回的是从 1970 年 1 月 1 日以来的毫秒数。
+
+```javascript
+({ x: 1, y: 2}).valueOf() // => {x: 1, y: 2}
+[1, 2, 3, 4].valueOf() // => (4) [1, 2, 3, 4]
+(function f(x) { x; }).valueOf() // => ƒ f(x) { x; }
+/\d+/g.valueOf() // => /\d+/g
+new Date().valueOf() // => 1507618941654
+```
+
+细节探究:在 JavaScript 中,对象到数字的转换经历了和字符串类似的几个步骤:
+
+1. 如果对象有 `valueOf()` 方法就调用它。如果返回的是原始值并且不是数字,则转换为字符串。然后返回结果。
+1. 如果对象没有 `valueOf()` 方法,或者该方法返回的不是原始值,则 JavaScript 就会继续调用 `toString()` 方法。如果对象有该方法就调用它,如果返回的是原始值并且不是数字,则转换为数字。然后返回结果。
+1. 如果以上都不满足,说明 JavaScript 无法通过 `valueOf()` 或者 `toString()` 方法获得原始值,则将抛出一个类型错误异常。
+
+上面的内容解释了空数组在参与数学运算的时候为什么会被转换为 0,以及为什么只有一个元素的数组会转换成数字。数组继承了默认的 `valueOf()` 方法,该方法返回的是对象。所以数组到数字的转换调用 `toString()` 方法,空数组被转换成空字符串,空字符串又转换成数字 0。只有一个元素的数组同理。
+
+#### 运算符带来的转换
+
+TODO: 这一节没太看明白。
+
+二元 `+` 运算符的其中一个操作数为对象的话,JavaScript 将使用特殊的方法(TODO: 什么方法?)将对象转换为原始值。`==` 运算符也是如此,如果将对象和原始值比较,则会先将对象转换为原始值。
+
+但是,如果上面所说的对象是日期类型的话就不一样了,日期类是 JavaScript 核心类型中唯一的一个预定义类型。对于日期类到字符串和数字的转换,JavaScript 都定义了有意义的实现方式。对于所有的非日期对象来说,对象到原始值的转换基本上都是对象到数字的转换(先调用 `valueOf()`),日期对象则使用对象到字符串的转换模式。但这里的转换模式还和前面所说的不太一样:`valueOf()` 或者 `toString()` 所返回的原始值不会被转换为数字或字符串,而是直接使用。
+
+`<` 以及其它关系运算符和 `==` 一样,也会做对象到原始值的转换,但不包括日期对象:任何其它对象都会先调用 `valueOf()`,再调用 `toString()`。转换后的原始值不会被进一步转换,而是直接使用。
+
+`+`、`==` 和 `!=` 是仅有的几个会执行字符串到原始值的转换的运算符,其他运算符到特定类型的转换都很明确,而且日期对象也没有特殊情况。比如 `-` 减号运算符就会把两个操作数都转换为数字。
+
+```javascript
+var now = new Date();
+typeof(now + 1); // => "string"
+typeof(now - 1); // => "number"
+now == now.toString(); // => true
+now > (now - 1); // => true
+```
+
+## 变量声明
+
+JavaScript 中使用一个变量之前先声明一下是个好习惯,可以使用关键字 `var` 来声明,还可以用一个关键字声明多个变量,而且还能将编创的声明和赋值写在一起:
+
+```javascript
+var message = 'hello';
+var i = 0, j = 0, k = 0;
+```
+
+如果只是声明但没有赋值,那么这个时候该变量的值就是 `undefined`。
+
+另外,在 `for` 循环或者 `for/in` 循环内也可以用 `var` 语句来声明循环变量。
+
+```javascript
+for (var i = 0; i < 5; i++) console.log(i);
+for (var p in obj) console.log(p);
+```
+
+### 变量无类型
+
+JavaScript 中并没有规定变量始终只能为一种类型:
+
+```javascript
+var a = 1.2;
+a = 'Hello';
+a = [1, 2, 3];
+```
+
+### 重复/遗漏的声明
+
+使用 `var` 重复声明变量是合法的,如果重复声明还带赋值,那就会覆盖前一次的赋值。
+
+```javascript
+var a = 1;
+var a = 2;
+a; // => 2
+```
+
+读取一个未声明的变量时,JavaScript 会报错。在 ES5 严格模式中,给未声明的变量赋值也会报错。虽然在非严格模式下,给未声明的变量赋值时,会给全局对象创建一个同名属性,并且工作起来似乎像一个正确声明的全局变量。但非常不建议这样写代码,所以一定要用 `var` 来声明变量。
+
+## 变量作用域
+
+全局变量:具有全局作用域,在 JavaScript 代码中的所有地方都有定义。
+
+局部变量:只在所声明的函数体内有定义。函数参数也是局部变量。
+
+优先级:在函数体内,局部变量的优先级高于同名的全局变量。
+
+### 函数作用域与声明提前
+
+在 JavaScript 中,虽然没有块级作用域(block scope)的概念,但是有函数作用域(function scope):在函数体中声明的变量,在函数及内部嵌套的函数中均有定义。
+
+```javascript
+function test(o) {
+ var i = 0;
+ if (typeof o == 'object') {
+ var j = 0;
+ for (var k = 0; k < 10; k++) {}
+ console.log('k1 = ' + k);
+ }
+ console.log('k2 = ' + k);
+ console.log('j = ' + j);
+}
+
+test({});
+// => k1 = 10
+// => k2 = 10
+// => j = 0
+```
+
+JavaScript 的函数作用域,不仅是指在函数中声明的变量,在函数及内部嵌套的函数中均有定义;而且在函数声明之前就可以被使用。这个特性称作声明提前(hoisting)。但是,只有函数的**声明**会被“提前”至函数体的顶部,赋值并不会被提前,见下面代码的执行结果。
+
+```javascript
+var scope = 'global';
+function f() {
+ console.log(scope);
+ var scope = 'local';
+ console.log(scope);
+};
+f();
+// => undefined
+// => local
+```
+
+上面的函数可以按下面的执行顺序来理解。
+
+```javascript
+function f() {
+ var scope;
+ console.log(scope);
+ scope = 'local';
+ console.log(scope);
+}
+```
+
+由于 JavaScript 函数作用域的特性,同名的局部变量遮盖了全局变量。但是只有在程序执行到 var 语句的时候,局部变量才被赋值。所以在这之前就使用它的话,值自然是 `undefined`。
+
+基于 JavaScript 的这种特性,在函数内定义变量时,可以将变量声明整体放在函数体的顶部,这样就能够清晰、准确地反映真实的变量作用域。
+
+### 作为属性的变量
+
+声明全局变量时,实际上是定义了全局对象的一个属性。
+
+如果用 var 声明全局变量,则这个变量/属性是不可删除的(无法用 `delete` 运算符删除)。
+
+如果未使用严格模式,并且直接给一个未声明的变量赋值的话(不用 var 声明),JavaScript 就会自动创建一个全部变量,并且这个变量/属性是可删除的(可以用 `delete` 运算符删除)。
+
+```javascript
+var truevar = 1;
+fakevar = 2;
+this.fakevar2 = 3;
+console.log(delete truevar); // => false
+console.log(delete fakevar); // => true
+console.log(delete this.fakevar2); // => true
+```
+
+在 ES 规范中,规定全局变量是全局对象的属性。虽然对局部变量没有做类似的规定,但是可以将局部变量理解为跟函数调用相关的某个对象的属性。在 ES5 中,称作该对象为“声明上下文对象”(declarative environment record)。
+
+JavaScript 中可以用 `this` 关键字来引用全局对象,却没有方法引用局部变量中存放的对象。这种存放局部变量对象的特有性质,是对我们不可见的内部实现。但是!可以通过闭包在局部变量的作用域之外使用它,具体请看 [MDN 上关于闭包的文档](https://github.com/Dream4ever/JavaScript/blob/master/topics/mdn-closure.md)。
+
+### 作用域链
+
+JavaScript 是基于词法作用域的语言:只要看看包含变量定义在内的几行源码,就能知道变量的作用域了。全局变量在程序中始终有定义,局部变量则在声明它的**整个**函数体内都有定义。
+
+假设有一类定义了自身实现方式的对象(TODO: 没看懂 => 说的就是函数?),而我们将局部变量看作是这类对象的属性的话,我们就可以换个角度来理解变量作用域了。
+
+每一段 JavaScript 代码(不管是全局代码还是函数)都有一个对应的作用域链(scope chain)。这个作用域链是一系列对象组成的列表(list)或者链表(chain),而这一系列对象定义了它们的“作用域”中的变量。JavaScript 在作用域链上查找变量 x 时(这个过程叫做变量解析 - variable resolution),它会从第一个对象开始,一直找到最后一个对象,如果整个作用域链上都没找到包含属性 x 的对象,就认为 x 不在这个作用域链上,并且会抛出一个引用错误(ReferenceError)的异常。
+
+在 JavaScript 的最顶层(最外层,不在任何函数定义内)代码中,作用域链只有一个对象:就是全局对象。在不包含嵌套的函数体内,作用域链包含两个对象:第一个对象定义了这个函数的参数和函数体内的局部变量,第二个对象为全局对象。在包含嵌套的函数体内,作用域链包含至少三个函数对象。(这么一说,不包含嵌套的函数,是否也可以看作是“嵌套”在全局对象内的函数?)
+
+在**定义**一个函数时,它会保存它的作用域链——非嵌套函数会保存定义了这个函数的参数和局部变量的对象,以及全局对象;嵌套函数则保存从当前嵌套函数直至最顶层函数的相关对象(定义了每个函数的局部变量,含参数),以及全局对象。(这里可以把这个作用域链称作“定义链”。)
+
+当**调用**这个函数时,它会创建一个新对象来保存它的局部变量(前面说过,函数参数也是局部变量),然后把这个新对象添加到定义链上,形成一个新的、更长的作用域链,这个新的作用域链表示函数的**调用**——也就是调用链。
+
+涉及到嵌套函数的时候就更有意思了,因为每次调用外部函数的时候,内部函数就会被重新定义一次(TODO:也没看懂 => 看后面的解释)。每次调用外部函数的时候,作用域链/调用链和前一次是不一样的,内部函数在每次重新定义的时候都会和前一次有微妙的差别——每次调用外部函数时,被重新定义的内部函数的代码虽然是不变的,但是与这段代码关联的作用域链/调用链却是变化的——因为每次调用外部函数时,外部函数都会重新创建一个新对象来保存局部变量,再将这个新对象添加定义链上——所以才说每次调用外部函数时,作用域链/调用链和前一次调用是不同的,因此内部函数也和前一次不同。(TODO: 还是没有理解透彻。)
+
+# 表达式和运算符
+
+表达式:JavaScript 解释器会将其计算(evaluate)出一个结果。
+
+- 常量:最简单的一类表达式。
+- 变量名:也是一种简单的表达式,它的值就是赋给变量的值。
+
+复杂表达式:由简单表达式通过运算符(或其它符号,如数组元素访问或函数调用)组合而成。
+
+## 原始表达式
+
+原始表达式:最简单的表达式,也是表达式的最小单位——不再包含其它表达式。常量、直接量、关键字、变量都是原始表达式。
+
+```javascript
+1.23 // 数字直接量
+'hello' // 字符串直接量
+/pattern/ // 正则表达式直接量
+```
+
+一些保留字也构成原始表达式:
+
+```javascript
+true // 返回布尔值:真
+false // 返回布尔值:假
+null // 返回值:空
+this // 返回“当前”对象
+```
+
+还有一种原始表达式就是变量:
+
+```javascript
+i // 返回变量 i 的值
+undefined // undefined 是全局变量,而 null 是一个关键字,它俩是不一样的
+```
+
+## 对象和数组的初始化表达式
+
+对象和数组的初始化表达式其实是新建的对象和数组,有时候也称作“对象直接量”和“数组直接量”。但是,它们不是原始表达式,因为它们所包含的成员或者元素都是子表达式。
+
+```javascript
+[] // 空数组
+[1 + 2, 3 + 4] // 数组拥有两个元素,3 和 7
+var matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; // 嵌套表达式
+```
+
+JavaScript 对数组初始化表达式进行求值的时候,表达式中的元素表达式也会各计算一次。也就是说,数组初始化表达式每次计算的值有可能是不同的。
+
+```javascript
+var i = 0;
+var a = [++i, ++i, ++i]; // [1, 2, 3]
+```
+
+数组直接量中的逗号间的元素可省略,会填充为 undefined。但是如果元素列表结尾处有一个逗号,就不会再创建一个 undefined 元素了。
+
+```javascript
+var a = [1,,,,3]; // => [1, empty × 3, 3]
+var b = [1,]; // => [1]
+```
+
+对象的初始化和数组非常类似。
+
+```javascript
+var obj = { x: 1, y: 2 }; // 拥有两个属性成员的对象
+var emp = {}; // 空对象
+var rectangle = { upperLeft: { x: 2, y: 2 },
+ lowerRight: { x: 4, y: 5 } }; // 也可以嵌套
+```
+
+和数组一样,求对象初始化表达式的值的时候,对象表达式也会各自计算一次。
+
+```javascript
+var side = 1;
+var square = { 'upperLeft': { x: p.x, y: p.y }, 'lowerRight': { x: p.x + side, y: p.y + side } };
+// => { upperLeft: {x: 2.3, y: -1.2}, lowerRight: {x: 3.3, y: -0.19999999999999996} }
+```
+
+## 函数定义表达式
+
+函数定义表达式的值是这个新定义的函数,也可以叫做函数直接量。
+
+```javascript
+var square = function(x) { return x * x; }
+```
+
+## 属性访问表达式
+
+属性访问表达式会计算得到一个对象属性或一个数组元素的值。
+
+```javascript
+expression.identifier
+expression[expression]
+```
+
+获取数组元素时只能用上面的第二种写法,而对象则两种都可以用。
+
+```javascript
+var o = { x: 1, y: { z: 3 } }; // 示例对象
+var a = [o, 4, [5, 6]]; // 包含示例对象的数组
+o.x // => 1: 表达式 o 的属性 x
+o.y.z // => 3: 表达式 o.y 的属性 z
+o["x"] // => 1: 表达式 o 的属性 x
+a[1] // => 4: 表达式 a 中索引为 1 的元素
+a[2]["1"] // => 6: 表达式 a[2] 中索引为 1 的元素
+a[0].x // => 1: 表达式 a[0] 的属性 x
+```
+
+- 对于上面两种属性访问表达式,在 `.` 或者 `[` 之前的表达式都会首先计算。
+- 如果计算结果是 null 或 undefined,表达式会抛出一个类型错误异常,因为这两个值都不能包含任何属性。
+- 如果运算结果不是对象(或数组),JavaScript 会先将其转换为对象。
+- 如果表达式后跟句点和标识符,则会查找标识符所指定的属性的值,并作为整个表达式的值返回。
+- 如果表达式后跟一对方括号,则先计算方括号内的表达式的值**并转换为字符串**,然后查找字符串所指定的属性的值并返回。
+- 如果查找的属性不存在,则整个属性访问表达式的值就是 undefined。
+
+- 虽然用标识符访问属性的写法更简单,但这种写法只适用于属性名是合法标识符,并且已经知道属性名的情况。
+- 如果属性名是保留字或者包含空格和标点符号,或者是数字(对于数组而言),就必须使用方括号。
+- 属性名不是固定值而是计算得出的值,也必须用方括号。
+
+## 调用表达式
+
+调用表达式(invocation expression):调用(或者执行)函数或方法的语法表示。任何一个调用表达式都包含一对圆括号和左圆括号之前的表达式。
+
+```javascript
+f(0) // f 是函数表达式,0 是参数表达式
+Math.max(x, y, z) // Math.max 是函数,x、y 和 z 是参数
+a.sort() // a.sort 是函数,没有参数
+```
+
+对调用表达式求值:
+
+- 先计算函数表达式,然后计算参数表达式,得到一组参数值。
+- 如果函数表达式不是一个可调用的对象,则抛出一个类型错误异常。
+- 函数表达式可调用,将实参的值依次赋给形参,然后执行函数体。
+- 函数使用 return 语句给出返回值的话,这个值就是整个调用表达式的值。
+- 否则,调用表达式的值就是 undefined。
+
+方法调用(method invocation):调用表达式是属性访问表达式的情况。在方法调用中,执行函数体的时候,作为属性访问主体的对象和数组,就是其调用方法内 this 的指向。借由这种特性,在面向对象编程中,函数可以调用其宿主对象。
+
+对于调用表达式不属于方法调用的情况,通常将全局对象作为 this 的值。但是在 ES5 严格模式中定义的函数,this 的值是 undefined 而不是全局对象。
+
+## 对象创建表达式
+
+对象创建表达式:创建对象并调用函数(构造函数)来初始化新对象的属性。和函数调用表达式很类似,只是多了一个关键字 `new`。
+
+```javascript
+new Object()
+new Point(2, 3)
+```
+
+如果对象创建表达式不需要传入参数的话,一对空的圆括号都可以省略掉。
+
+```javascript
+new Object
+new Date
+```
+
+计算对象创建表达式的值:
+
+- 先创建一个新的空对象。
+- 将参数传入指定的函数,并将新对象当作这个函数里的 this 的值,函数可以使用 this 来初始化这个新创建的对象的属性。
+- 如果构造函数不返回值,那么对象创建表达式的值就是这个新创建的并且被初始化了的对象。
+- 如果构造函数返回对象,那么这个返回的对象就是对象创建表达式的值,新创建的对象就被丢弃了。
+
+## 运算符概述
+
+绝大多数运算符都是标点符号,比如 `+` 和 `=`,只有少数是由关键字表示的,比如 `delete` 和 `instanceof`。
+
+### 操作数的个数
+
+JavaScript 中大部分运算符都是二元运算符(也就是有两个操作数),将两个表达式合并成一个稍微复杂一点的表达式。也有一少部分运算符是一元运算符,将一个表达式转换为另一个稍微复杂一点的表达式。唯一的一个三元运算符是条件判断运算符 `? :`,它将三个表达式合并成一个表达式。
+
+### 操作数类型和结果类型
+
+虽然有些运算符可以用于所有数据类型,但操作数是指定类型数据的话就更好了;并且大多数运算符返回(或计算出)的也是一个特定类型的值。比如逻辑非运算符 `!` 期望的操作数就是 `bool` 类型,如果不是,则会先将其转换为该类型。
+
+### 左值
+
+赋值及其它几个运算符期望的操作数是 `lval` 类型,表示该操作数(表达式)只能出现在赋值运算符的左侧。在 JavaScript 中,变量、对象属性和数组元素都是左值。
+
+ES规范允许内置函数返回一个左值,但自定义函数则不能返回左值。(TODO: 不太懂)
+
+### 运算符的副作用
+
+计算简单的表达式(比如 2*3)不会影响程序的运行状态,后续执行的状态也不会受影响。但有些表达式就会对程序有影响了,比如赋值运算符:给一个变量或属性赋值的话,后续使用这个变量或属性的表达式的值都会发生变化。自增和自减运算符也是这样,因为它们包含隐式的赋值。`delete` 运算符也是如此:删除一个属性就类似于(但不等于)给这个属性赋值 `undefined`。
+
+其它的 JavaScript 运算符都没有副作用,除了函数调用表达式和对象创建表达式:在函数体或者构造函数内部运用了这些运算符并产生了副作用的时候,就说函数调用表达式和对象创建表达式是有副作用的(TODO: 也没太看懂……)。
+
+### 运算符优先级
+
+属性访问表达式和调用表达式的优先级要比所有其它运算符都高:
+
+```javascript
+typeof my.functions[x](y)
+```
+
+虽然 `typeof` 是优先级最高的运算符之一,但也是在属性访问和函数调用之后执行的。
+
+最保险的保证优先级的方法,就是用圆括号来强行指定。
+
+注意:乘法和除法的优先级高于加法和减法,赋值运算符的优先级非常低,通常总是最后执行的。
+
+### 运算符的结合性
+
+结合性:多个具有同样优先级的运算符表达式中的运算顺序。比如减法运算符具有从左至右的结合性,因此下面两行代码的执行效果是一样的:
+
+```javascript
+w = x - y - z;
+w = ((x - y) - z);
+```
+
+### 运算顺序
+
+运算符的优先级和结合性规定了它们在复杂的表达式中的运算顺序,但并没有规定子表达式在计算过程中的运算顺序 —— JavaScript 总是严格按照从左至右的顺序来计算表达式。
+
+```javascript
+w = x + y * z
+```
+
+比如在上面的表达式中,先依次计算表达式 w、x、y 和 z,然后计算 `y * z`,再计算 `x + y * z`,最后将其赋值给 w 所代表的变量或属性。
+
+给表达式添加括号可以改变乘法、加法和赋值运算等运算符的关系,但从左至右计算子表达式的顺序是不会改变的。
+
+只有在任一表达式具有副作用而影响到其它表达式的时候,其求值顺序才会和看上去有所不同。
+
+```javascript
+var a = 1;
+var b = (a++)+a;
+```
+
+上面的表达式计算顺序是这样的:
+
+1. 先计算子表达式 b 的值;
+1. 计算 a++,子表达式的计算结果为 1,但是计算完成后 a 的值已经是 2 了;
+1. 计算 a,值为 2;
+1. 计算 (a++)+a,值为 3;
+1. 将该表达式的结果 3 赋给 b。
+
+## 算术表达式
+
+基本的算术运算符:*(乘法)、/(除法)、%(取余)、+(加法)和 -(减法)。
+
+加法之外的运算符都是在必要的时候将操作数转换为数字,然后求积、商、余数和差。无法转换为数字的操作数,都转换为 NaN。如果操作数是 NaN,算术运算的结果也是 NaN。
+
+对于 JavaScript 来说,所有的数字都是浮点数,所以除法运算的结果总是浮点型。
+
+取余运算符不限于整数,浮点数也可以,比如 `6.5 % 2.1 === 0.2(实际输出 0.19999999999999973)`。
+
+### `+` 运算符
+
+该运算符既可以将两个数字相加,也可以连接两个字符串。
+
+一般来说,优先进行字符串连接。只要其中一个操作数是字符串或者转换为字符串的对象,另外一个操作数也会转换为字符串,然后加法运算符连接这两个字符串。
+
+只有两个操作数都不是类字符串(string-like)的时候,才会进行算术加法运算。
+
+加法运算符的表现如下:
+
+1. 其中一个操作数是对象的话,就会遵循对象到原始值的转换规则进行转换:日期对象通过 `toString()` 方法转换,其它对象则通过 `valueOf()` 方法转换(如果 `valueOf()` 方法返回一个原始值的话)。因为大部分对象都没有可用的 `valueOf()` 方法,所以这些对象其实还是会通过 `toString()` 方法进行转换。
+1. 对象转换到原始值后,如果其中一个操作数是字符串,则另一个操作数也会转换为字符串,然后加号运算符连接这两个字符串。
+1. 两个操作数都不是对象的话,就会都转换为数字(或者 NaN),然后相加。
+
+```javascript
+1 + 2 // => 3: 加法
+'1' + '2' // => '12': 字符串连接
+'1' + 2 // => '12': 数字转换为字符串之后连接字符串
+1 + {} // => '1[object Object]': 对象转换为字符串后连接字符串
+true + true // => 2: 布尔值转换为数字后做加法
+2 + null // => 2: null 转换为 0 之后做加法
+2 + undefined // => NaN: undefined 转换为 NaN 之后做加法
+```
+
+另外,加号运算符和数字一起使用的时候,还要注意加法的结合性对运算顺序的影响。
+
+```javascript
+1 + 2 + ' blind mice' // => '3 blind mice'
+1 + (2 + 'blind mice') // => '12blind mice'
+```
+
+### 一元算术运算符
+
+一元运算符作用于一个操作数并产生一个新值。JavaScript 中的一元运算符都有很高的优先级,并且都是右结合。一元运算符在必要的时候会将操作数转换为数字。
+
+一元加法(+):该运算符把操作数转换为数字或者 NaN,并返回转换后的数字。如果操作数本身就是数字的话则直接返回(该运算符并不会改变操作数的正负号)。
+一元减法(-):该运算符根据需要把操作数转换为数字,然后改变运算结果的符号。
+
+递增(++):运算符将操作数(变量、数组元素或对象属性)转换为数字之后加 1,并将加 1 后的数值重新赋给变量、数组元素或对象属性。该运算符的返回值依赖于它相对于操作数的位置。运算符在操作数之前时,称为“前增量”,它将操作数加一之后,返回计算后的值。而运算符在操作数之后的话,称为“后增量”运算符,它对操作数进行加一运算,但返回的是加一之前的值。
+
+```javascript
+var i = 1, j = ++i; // => i: 2, j: 2
+var i = 1, j = i++; // => i: 2, j: 1
+```
+
+这里还要注意区分 `++x` 和 `x = x + 1`:`++`运算符只执行数值运算操作,而 `+` 运算符有可能执行字符串连接操作。
+
+```javascript
+var x = '1'; ++x; // => 2
+var x = '1'; x = x + 1; // => '11'
+```
+
+此外,由于 JavaScript 会自动进行分号补全,所以不能在后增量运算符和操作数之间插入换行符。如果插入了换行符,JavaScript 会把操作数当作一条单独的语句,并在其之前补上一个分号。
+
+```javascript
+var x = 1;
+x
+++ // => x: 1
+```
+
+递减(--):与递增运算符相同。
+
+### 位运算符
+
+先 pass 这一小节。
+
+## 关系表达式
+
+关系运算符用于测试两个值之间的关系(比如“相等”、“小于”,或者“是……的属性”),并根据关系是否存在而返回 true 或者 false。
+
+### 相等和不等运算符
+
+`==` 和 `===` 运算符都用于比较两个值是否相等,都允许任意类型的操作数。
+
+`===` 也称为“严格相等运算符”,
+
+`!=` 和 `!==` 运算符是 `==` 和 `===` 运算符的求反:如果两个值通过 `==` 或 `===` 比较的结果为 true,则 `!=` 或 `!==` 的比较结果则为 false,反之亦然。
+
+在 JavaScript 中,比较两个对象时,比较的是引用而不是值。对象只和它本身相等,和其它任何对象都不相等:即使具有相同数量的属性、相同的属性名和值也依然是不相等的。数组也是如此。
+
+严格相等运算符 `===` 的比较流程如下:
+
+- 如果两个值的类型不相等,则它们不相等。
+- 如果两个值都是 null 或者 undefined ,则它们不相等。
+- 如果两个值都是布尔值 true 或 false,则它们相等。
+- 只要有一个值是 NaN,它们就不相等:NaN 和自身也不相等。所以可以用 `x !== x` 来判断是否为 NaN。
+- 如果两个值为数字且相等,则它们相等。0 和 -0 也相等。
+- 如果两个值为字符串,且各个对应位上的 16 位数完全相等,则它们相等。如果它们的长度或内容不同,则不相等。具有不同编码的 16 位值的两个字符串,所显示的字符可能是一样的。JavaScript 并不对 Unicode 进行标准化的转换,所以这样的字符通过 `===` 和 `==` 的比较结果也是不相等的。(TODO: 这里需要进一步了解,貌似有个有关特殊网址的 0day 漏洞应用的就是这个知识点?)
+- 如果两个引用值均指向同一个对象、数组或函数,则它们相等。如果指向的是不同的对象,肯定不相等。
+
+相等运算符 `==` 的判断就没那么严格了,如果两个操作数类型不同,相等运算符会先转换为相同类型,再进行比较:
+
+- 如果两个操作数类型相同,则和上文所述的严格相等的比较规则和结果一样。
+- 如果两个操作数类型不相同,则依据如下规则进行转换和比较:
+ - 如果一个值是 null,另一个是 undefined,则它们相等。
+ - 如果一个值是数字,另一个是字符串,则先将字符串转换为数字,然后比较两个数字。
+ - 如果一个值是 true,则将其转换为 1 再进行比较;为 false 的话,则转换为 0 再进行比较。
+ - 如果一个值是对象,另一个值是数字或字符串,则按照对象转换为原始值的规则,先将对象转换为原始值,再进行比较。JavaScript 语言核心的内置类中,只有对象使用 `toString()` 转换,其余类都是先尝试使用 `valueOf()` 转换,再尝试使用 `toString()` 转换。非核心的对象,则通过各自定义的方法转换为原始值。
+ - 其它不同类型之间的比较均不相等。
+
+以 `'1' == true` 为例:布尔值 true 首先转换为数字 1,然后字符串 '1' 也转换为数字 1,最后两个数字 1 相等,因此比较结果为 true。
+
+### 比较运算符
+
+虽然比较运算符的操作数可以是任意类型,但只有数字和字符串才能真正进行比较。其它类型的操作数的转换规则如下:
+
+- 操作数为对象,则首先尝试用 `valueOf()` 转换成一个原始值,否则再用 `toString()` 的转换结果进行比较。
+- 对象转换为原始值之后,如果两个操作数都是字符串,则依照字母表的顺序对两个字符串进行比较。这里的字母表顺序,是指组成字符串的 16 位 Unicode 字符的索引顺序。
+- 对象转换为原始值之后,如果至少有一个操作数不是字符串,则两个操作数都转换为数字。0 和 -0 相等,Infinity 大于任何其它数(除了自己),-Infinity 小于任何其它数(除了自己)。如果其中一个操作数是(或者转换后是)NaN,则比较结果为 false。
+
+注意:由于 JavaScript 字符串是由 16 位整数值组成的序列,所以字符串的比较就是这些数值的比较。而 Unicode 字符编码的顺序和传统字符编码顺序不太一样,其中所有大写的 ASCII 字母都“小于”小写字母。而 `String.localCompare()` 则使用本地语言的字母表中定义的字符次序进行比较,更符合用户习惯。
+
+另外,对于数字和字符串来说,加号运算符和比较运算符也有所不同:加号运算符更偏爱字符串,至少有一个操作数是字符串,它就会进行字符串连接操作;比较运算符则更偏爱数字,只要有一个操作数是数字,它就进行数学加法操作。
+
+```javascript
+1 + 2 // => 3
+'1' + '2' // => '12'
+'1' + 2 // => '12'
+11 < 3 // => false
+'11' < '3' // => true
+'11' < 3 // => false
+'one' < 3 // => false
+```
+
+最后,`<=` 和 `>=` 则判断相等的时候,只是简单的“不大于”和“不小于”,并不依赖于相等运算符和严格相等运算符的比较规则。仅有一个例外:当其中一个操作数是(或者转换后是)NaN 的时候,所有 4 个比较运算符均返回 false。
+
+### `in` 运算符
+
+该运算符检查右侧的对象是否拥有一个名为左侧操作数的值的属性名。
+
+```javascript
+var point = { x: 1, y: 1 };
+'x' in point // => true: 对象包含属性 x
+'z' in point // => false: 对象不包含属性 z
+'toString' in point // => true: 对象继承了 toString() 方法
+
+var data = [7, 8, 9];
+0 in data // => true: 数组包含索引为 0 的元素
+'1' in data // => true: 数组包含索引为 1 的元素
+3 in data // => false: 数组不包含索引为 3 的元素
+7 in data // => false: 数组不包含索引为 7 的元素
+```
diff --git a/topics/lesson11.md b/topics/lesson11.md
new file mode 100644
index 0000000..8b16a91
--- /dev/null
+++ b/topics/lesson11.md
@@ -0,0 +1,165 @@
+# 第11课笔记
+
+## 一、前端leader的分享
+
+### 1. JS学习的基础
+
+1. 找到对象
+1. 操作对象
+
+### 2. 进步的途径
+
+1. 看优秀代码
+1. 要多写代码,才能逐渐找到更优秀的编程方式,只是看书看代码还不够,一定要有自己的亲身实践
+
+## 课程知识梳理
+
+每次分数范围:1~10分
+
+### 1. 两个运行环境
+
+给自己打10分~~~后面还可以继续研究浏览器的引擎和node.js的引擎。
+
+1. 浏览器:Chrome, Firefox, Safari, QQ, 360,提供HTML、CSS、JS的运行环境,具体的环境各不相同,所以会有兼容性的问题,因此新大推荐大家都用Chrome浏览器
+1. node.js:Ayo.js并不会对生态圈带来太大的影响,专注node.js的学习就可以了。
+
+### 2. 浏览器
+
+给自己打10分,都听懂了~
+
+浏览器会为用户构建一个沙箱环境,用来做下面几件事:
+
+1. 运行JS标准库
+1. 提供内置库
+1. 虚拟化HTML,为什么要虚拟化?因为拿过来的HTML页面都是节点/标签,要把这些文件虚拟化成一个DOM对象,而JS代码就是在操作对象。 -> 根元素是doument对象
+1. window对象,浏览器窗口的大小、标签等等
+
+### 3. 基础的操作DOM的方式
+
+这个自己很熟悉了,10分~
+
+在前端,浏览器把HTML虚拟化成DOM对象,原生的JS再通过document的方法来操作DOM。
+
+### 4. jQuery
+
+还是比较熟悉的内容,10分~
+
+除了虚拟化出来的DOM对象,还有标准库、内置库、window对象、HTTP等各种东西。
+
+为了方便操作这些内容,就有了jQuery。
+
+jQuery的优势:
+
+1. 更清晰的DOM API
+1. 整合了HTTP相关的API
+1. 性能优化
+
+### 5. DOM与jQuery的异同
+
+这个听得很明白,10分!
+
+JS操作DOM(虚拟化的HTML),DOM有一些API。虽然有更方便一点的jQuery,但最终操作的还是DOM,然后去更新底层的HTML节点。DOM的API很难用,jQuery只是把这些API整合得好用一些了。
+
+但不管是DOM的API,还是jQuery,操作方法还是没变化的。学会了基础的JS,还要再去学习jQuery(倒是可以不用学习DOM的API了),学习量是减少了,但学习成本还是很高。
+
+### 6. 数据绑定
+
+这个老师也讲得浅显易懂,10分!
+
+如何改变JS操作DOM的方式呢?
+
+VUE屏蔽了大量的API,只需要少量的代码,就能用JS改变DOM直至背后的HTML。
+
+VUE会将HTML锚点里面的内容重新虚拟化一遍,这样就屏蔽了大量的API。
+
+VUE将HTML元素与数据进行绑定,构建了一一对应的关系。这样只需要用JS去操作数据,HTML中的内容就会自动变化。
+
+1. 事先建立关系
+1. 事后改变数据
+
+1. JS代码改变vue中的值
+1. vue自动去刷新数据
+
+### 7. 巩固VUE的价值
+
+也听懂了,再给自己打10分。
+
+HTML
+JS逻辑代码
+Server
+
+1. JS逻辑代码先从服务器get数据
+1. JS逻辑代码获得到服务器的数据
+1. JS代码再用数据去更新前端的HTML
+
+VUE代替了第三步,工程师不用自己去手动更新数据了,只需要从后端拿数据,前端页面就自动更新了,棒不棒!
+
+### 8. Node.js => 服务器/WebAPP/脚本
+
+自己的思维还需要再活跃一些,不过老师讲的完全听懂了,10分!
+
+Node.js会提供什么?
+
+1. JS标准库(和前端浏览器的一样?为什么?)
+1. Node.js API
+1. 第三方库
+ 1. fs
+ 1. jsonfile
+ 1. express
+ 1. axios
+
+上面这些第三方库可以怎样组合应用呢?
+
+1. fs + jsonfile => 能够自己写代码扫描json文件了 => 脚本
+1. fs + jsonfile + express => 显示json文件内容的webapp
+1. fs + jsonfile + axios => 扫描json文件并上传到网络上 => 也是一个脚本
+
+现在即使不会数据库也暂时OK,可以用jsonfile来保存大家的输入,或者读取json文件,要学会灵活变通。
+
+### 9. 基本功:数据操作
+
+学得很嗨!哈哈。
+
+知道了上面的这些东西之后,什么最重要?基本功最重要。
+
+课程给大家引入了JS标准库,提供了处理各种数据的能力。
+
+去哪里学习?
+
+1. MDN
+1. W3C
+1. 犀牛书
+
+什么最基本?数据格式的操作。这个学习有技巧,不要被各种材料限制住了。
+
+#### 示例:如何学习字符串?
+
+字符串 => "xiaoming.json"
+=> 如何操作? => 有长度,有内容
+要知道自己想要做什么操作,然后去看相关的文档
+
+#### 示例:数组
+
+```
+var list = [1, 3, 2, '四', 5, 6];
+```
+
+有这么一个数组,可以有各种操作,语法不是关键,要弄清楚有哪些可用的功能。
+
+### 10. 函数
+
+函数的几个关键点:
+
+1. 定义方式:语法定义 + 表达式定义。差异是什么?语法定义会将定义提前,一定要把这个概念吃透!
+ 1. 函数定义的两个法则:先声明再定义 + 先定义再使用。
+1. 返回结果的方式:
+1. 立即执行函数的技巧:前端加载第三方库的一种方式。
+
+### 11. 语法
+
+下面这些就是我们学习JS的目标,慢慢积累这四点知识。
+
+1. 一个对象:要不断地去研究它,内容很多的。
+1. 两个函数:同步 + 异步。
+1. 三个结构:顺序 + 条件 + 循环。
+1. n种数据结构。
\ No newline at end of file
diff --git a/topics/lesson12.md b/topics/lesson12.md
new file mode 100644
index 0000000..5b2a387
--- /dev/null
+++ b/topics/lesson12.md
@@ -0,0 +1,94 @@
+# 第12课笔记
+
+## 二狗闪亮登场!!!
+
+二狗如何学习JS?
+
+### 学习
+
+文章:《十年学编程》,Google研究中心主任。
+
+JS发展这么多年,有很多缺陷,一些公司做了些改进,这些语言都能编译成JS,可以很好的开拓JS的编码思路:
+
+1. TypeScript
+1. Dart
+1. ClojureScript
+1. Elm
+
+### 多练
+
+1. 业余的话,写自己需要的东西
+1. 实在不知道要什么的话,就上网做一些算法题 => 锻炼逻辑思维能力,提升自己解决问题的能力
+
+#### 练习算法的网站
+
+1. www.spoj.com
+1. www.leetcode.com
+1. www.codewars.com
+1. www.hackerrank.com
+
+## 美女运营分享
+
+五年计算机,网络通信监控,转做运营。
+
+### 例一:方法论
+
+学计算机的人逻辑性非常强,训练思维很好。
+
+遇到陌生的问题,下面三步走:
+
+1. 二分法
+1. 比较法
+1. 顺序排查
+
+### 例二:转行
+
+程序员出身的人,和互联网的关联程度非常高。
+
+## 徐帅归来
+
+### 编程带来的改变
+
+在想任何事情的时候,脑子里都有一张关系图。
+
+### 编程与个人性格
+
+#### 和聪明无关
+
+不要求很聪明,但要快准狠 => 严谨、细心、踏实。
+
+不要怕问问题,回答问题的也不要觉得不耐烦。
+
+### 如何成长
+
+1. 一定不要追求表面上的东西,要培养阅读、解决问题的能力。
+1. 做事之前一定要分析:把问题吃透,把流程捋顺。
+1. 学习成功的开发经验,来构建自己的能力树。不要求自己完全从头做起,站在巨人的肩膀上也很好。
+1. 阅读文档的能力非常重要。
+1. 做技术一定要多和专业的人士沟通,要想办法打入这个圈子。
+1. 学了一段技术之后,就要慢慢构建技术型的思维方式,让自己越来越专业。
+1. 诚实,不懂就是不懂,努力去弄懂就好了。
+
+### 几个注意事项
+
+1. **不要上来就干!**
+1. 简历上的东西,列出来的做过的项目根本是不够的。敢把自己的技术栈、能力树写出来就很棒。
+1. 可以去show自己的产品,但千万不要装自己的能力、水平。
+1. 技术是怎么做出来的?就是靠交流。
+1. 不一定什么都要靠技术,可以自己做一个网站。hexo其实技术并不难,只是换模板而已。
+1. 不要做一个编程狂人:
+ 1. 不要狂妄。
+ 1. 不要只是沉迷于技术,不要成为偏执狂。
+
+### 职业发展方向
+
+1. 只想练习编程思维:可以用需求来锻炼自己。
+1. 想从事技术行业:欠缺的是一个好项目,环境是次要的,公司没有好项目,可以自己找自己的需求。codewars,选JavaScript,做完第一道题,然后去看大家各种厉害的方法,学习他们。有了想法,缺的是一个好的方法来实现自己的想法。
+1. 想转型的同学,现在千万不要太着急。想想学习技术的曲线,现在大家都在一个蜜月期,千万别着急,要稳扎稳打,清楚自己目前的能力、定位,先做好自己的本职工作,在工作之余可以研究研究技术。
+
+### 工程师成长
+
+可以没有规矩,但不能没有原则。
+
+1. 员工成长快于公司,跳槽是理所应当。
+1. 公司成长快于员工,辞退跟不上公司步伐或者严重拖后腿的员工也是理所应当。
diff --git a/topics/mdn-closure.md b/topics/mdn-closure.md
new file mode 100644
index 0000000..591b959
--- /dev/null
+++ b/topics/mdn-closure.md
@@ -0,0 +1,384 @@
+# MDN - 闭包
+
+原文链接:[Closures - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures)。
+
+> 什么是闭包?闭包就是函数及声明函数时的词法环境(lexical environment)。
+
+## 词法作用域(Lexical scoping)
+
+先看下面的代码:
+
+```javascript
+function init() {
+ var name = 'Mozilla'; // name 是 init 创建的局部变量
+ function displayName() { // displayName() 是内部函数,也是闭包
+ alert(name); // displayName() 使用了父函数中声明的变量
+ }
+ displayName();
+}
+init();
+```
+
+`init()` 函数在其内部创建了一个局部变量 `name` 和一个函数 `displayName()`。因为 `displayName()` 是定义在 `init()` 中的内部函数,所以只能在函数 `init()` 内访问。虽然 `displayName()` 本身没有局部变量,但是由于内部函数可以访问包含它的外部函数中的变量,所以 `displayName()` 可以访问父函数 `init()` 中的变量 `name`。
+
+上面这段代码就是词法作用域的示例:它描述了函数有嵌套的时候,语法分析器(parser)是如何解析变量名的。词法(lexical)这个词指的就是:在代码中的某个位置上声明了变量,词法作用域则根据这个位置来决定变量在何处可以访问。因此,嵌套函数才可以访问在其作用域之外声明的变量。
+
+## 闭包
+
+现在再来看看下面的代码:
+
+```javascript
+function makeFunc() {
+ var name = 'Mozilla';
+ function displayName() {
+ alert(name);
+ }
+ return displayName; // 注意这里返回了内部函数
+}
+
+var myFunc = makeFunc();
+myFunc();
+```
+
+这段代码和前面一段代码的执行结果没有区别,不同的地方在于——内部函数 `displayName()` 在执行之前,从外部函数中返回了。
+
+乍一看会觉得,这样的代码怎么能正常运行呢?在一些编程语言中,函数内的局部变量只在函数执行期间可用。按理说,`makeFunc()` 一旦执行完毕,内部变量 `name` 就无法访问了。可是在这里代码竟然还能正常运行,看来需要重新认识一下 JavaScript 了。
+
+其实原因并不复杂:JavaScript 中的函数会形成闭包。正如文章开头所说,闭包就是函数及声明函数时的词法环境。这个“环境”包含了创建闭包时,所有在作用域中的(in-scope)的局部变量。
+
+拿上面的代码来说,运行函数 `makeFunc` 时,创建了函数 `displayName` 的实例(因为在 `makeFunc` 里 `displayName` 将自己返回到函数外了),而 `myFunc` 就是对这个实例的引用。`displayName` 的实例保持对其词法环境的引用,而这个词法环境中就包括了变量 `name`。因此,当调用函数 `myFunc` 时,变量 `name` 是可用的,所以在浏览器中能够弹窗显示该变量的值。
+
+再来看一段更好玩的代码 —— `makeAdder` 函数:
+
+```javascript
+function makeAdder(x) {
+ return function(y) {
+ return x + y;
+ };
+}
+
+var add5 = makeAdder(5);
+var add10 = makeAdder(10);
+
+console.log(add5(2)); // => 7
+console.log(add10(2)); // => 12
+```
+
+在上面这段代码中,定义了函数 `makeAdder(x)`,这个函数接受一个参数 `x`,并返回一个新函数。它返回的函数也接受一个参数 `y`,并返回 `x` 与 `y` 之和。
+
+实际上,`makeAdder` 就是一个函数工厂——它创建出了一批函数,这批函数将一个特定的值与传入它们的参数相加。上面的代码用这个函数工厂创建了两个新函数——一个是将参数的值加 5,另一个则是加 10。
+
+`add5` 和 `add10` 都是闭包,它们的函数体定义是相同的,但是保存了不同的词法环境。在 `add5` 的词法环境中,`x` 是 5,对 `add10` 而言,`x` 则是 10。
+
+## 实战闭包
+
+闭包的作用,就在于它能够将一些数据(词法环境)和操作这些数据的函数关联起来,这显然和面向对象编程是很相似的——在面向对象编程中,对象可以将数据(对象的属性)与方法关联起来。
+
+因此,如果对象只需要一个方法(method)的话——用闭包就好了。
+
+在 Web 开发中,这种场景太常见了。大部分的前端 JavaScript 代码都是基于事件的——定义某种行为,然后关联到用户触发的事件上(比如鼠标点击或者键盘的按键行为)。通常将代码关联到回调上:回调就是为了响应某个事件而执行的一个函数。
+
+比如,我们想要往页面上添加几个更改文本尺寸的按钮。一种方法就是:先以绝对尺寸——像素(px)为单位,设置 `body` 元素的字号(font-size);然后再用相对尺寸 —— `em` 来设置页面上其它元素的尺寸(比如标题、段落)。
+
+```css
+body {
+ font-family: Helvetica, Arial, sans-serif;
+ font-size: 12px;
+}
+
+h1 {
+ font-size: 1.5em;
+}
+
+h2 {
+ font-size: 1.2em;
+}
+```
+
+我们先让调整文本尺寸的按钮改变 `body` 元素的 `font-size` 属性,因为其它元素用的都是相对尺寸,这些元素就能自动调整尺寸了。
+
+代码如下:
+
+```javascript
+function makeSizer(size) {
+ return function() {
+ document.body.style.fontSize = size + 'px';
+ };
+}
+
+var size12 = makeSizer(12);
+var size14 = makeSizer(14);
+var size16 = makeSizer(16);
+```
+
+这个时候,`size12`、`size14` 和 `size16` 就能够分别将 `body` 元素的字号调整至 `12px`、`14px` 或 `16px` 了。然后我们再将其关联到按钮的点击事件上:
+
+```javascript
+document.getElementById('size-12').onclick = size12;
+document.getElementById('size-14').onclick = size14;
+document.getElementById('size-16').onclick = size16;
+```
+
+```html
+
12
+
14
+
16
+```
+
+## 用闭包来模拟私有方法
+
+Java 之类的语言可以声明私有方法,这样一来,这些私有方法就只能被所属的同一个类中的其它方法访问了。
+
+JavaScript 并没有提供原生的方法来实现此需求,但是可以用闭包来模拟私有方法。私有方法不仅可以限制对代码的访问,它还提供了强大的功能来管理全局命名空间、避免方法弄乱代码中的公共接口。
+
+下面的代码展示了如何用闭包来定义可以访问私有函数和变量的公共函数。闭包的这种用法叫做模块模式(module pattern)。
+
+```javascript
+var counter = (function() {
+ var privateCounter = 0;
+ function changeBy(val) {
+ privateCounter += val;
+ }
+ return {
+ increment: function() {
+ changeBy(1);
+ },
+ decrement: function() {
+ changeBy(-1);
+ },
+ value: function() {
+ return privateCounter;
+ }
+ };
+})();
+
+console.log(counter.value()); // => 0
+counter.increment();
+counter.increment();
+console.log(counter.value()); // => 2
+counter.decrement();
+console.log(counter.value()); // => 1
+```
+
+在前面的那些示例代码中,每个闭包都有自己的词法环境;但是在这里的示例代码中,三个函数共享同一个词法环境:`counter.increment`、`counter.decrement` 和 `counter.value`。
+
+共享的词法环境是在匿名函数的函数体中创建的,而这个匿名函数一定义就被执行了。词法环境包含两个私有项:变量 `privateCounter` 和函数 `changeBy`。在匿名函数之外无法直接访问这两个私有项,只能通过匿名的包装函数里的三个公共函数来访问。
+
+这三个公共函数都是闭包,并且共享同一个词法环境。多亏了 JavaScript 的词法作用域,这三个公共函数才都能够访问私有变量 `privateCounter` 和私有函数 `changeBy`,这样就不用为每个公共函数都创建一个词法环境了。
+
+> 上面代码中定义的匿名函数会创建计数器,我们立即调用该函数并将其执行结果——也就是计数器——赋给了变量 `counter`。其实还可以将这个匿名函数保存在一个独立的变量 `makeCounter` 中,然后用这个变量来创建任意多个计数器。
+
+```javascript
+var makeCounter = function() {
+ var privateCounter = 0;
+ function changeBy(val) {
+ privateCounter += val;
+ }
+ return {
+ increment: function() {
+ changeBy(1);
+ },
+ decrement: function() {
+ changeBy(-1);
+ },
+ value: function() {
+ return privateCounter;
+ }
+ }
+};
+
+var counter1 = makeCounter();
+var counter2 = makeCounter();
+console.log(counter1.value()); // => 0
+counter1.increment();
+counter1.increment();
+console.log(counter1.value()); // => 2
+counter1.decrement();
+console.log(counter1.value()); // => 1
+console.log(counter2.value()); // => 0
+```
+
+注意这里的两个计数器 `counter1` 和 `counter2` 是如何互不影响的。每个(计数器的)闭包都引用了各自版本的私有变量 `privateCounter`,每次调用某个计数器的时候,一旦 `privateCounter` 的值改变,该计数器的词法环境也会对应改变。但是,一个闭包中变量值的变化并不会影响另一个闭包。
+
+> 闭包的这种用法带来了很多便利性——尤其是数据隐藏和封装,这些便利性通常都是面向对象编程语言中所拥有的。
+
+## 在循环中创建闭包:一种常见的误用方式
+
+在 ES2015 引入 `let` 关键字之前,使用闭包时的一种常见错误,就是在循环中创建了闭包。看下面的代码:
+
+```html
+
Helpful notes will appear here
+
E-mail:
+
Name:
+
Age:
+```
+
+```javascript
+function showHelp(help) {
+ document.getElementById('help').innerHTML = help;
+}
+
+function setupHelp() {
+ var helpText = [
+ {'id': 'email', 'help': 'Your e-mail address'},
+ {'id': 'name', 'help': 'Your full name'},
+ {'id': 'age', 'help': 'Your age (you must be over 16)'}
+ ];
+
+ for (var i = 0; i < helpText.length; i++) {
+ var item = helpText[i];
+ document.getElementById(item.id).onfocus = function() {
+ showHelp(item.help);
+ }
+ }
+}
+
+setupHelp();
+```
+
+`helpText` 数组定义了三个提示信息,每个都和网页中一个 input 元素的 ID 相关联。`for` 循环遍历这个数组,将 `onfocus` 事件与显示对应提示信息的方法绑定在一起。
+
+执行一下上面的代码,你就会发现结果并不是预期中的那样——不管焦点在哪个 input 元素上,提示的都是年龄相关的那条信息。
+
+为什么会这样?罪魁祸首还是 **闭包**。与 `onfocus` 事件绑定的方法是闭包——它们包含 `setupHelp` 函数的定义,以及从该函数作用域中捕获到的(词法)环境。循环创建了三个闭包,但是它们共享同一个词法环境——其中包含自身的值在不断变化的变量 `item.help`。执行 `onfocus` 事件的回调时,`item.help` 的值才能确定。而这个时候,循环已经执行完毕了,那么 `item` 这个变量的值最终指向的就是 `helpText` 数组中的最后一个元素了。
+
+要解决这个问题,一种方法就是使用更多的闭包:比如利用前面讲过的函数工厂:
+
+```javascript
+function showHelp(help) {
+ document.getElementById('help').innerHTML = help;
+}
+
+function makeHelpCallback(help) {
+ return function() {
+ showHelp(help);
+ };
+}
+
+function setupHelp() {
+ var helpText = [
+ {'id': 'email', 'help': 'Your e-mail address'},
+ {'id': 'name', 'help': 'Your full name'},
+ {'id': 'age', 'help': 'Your age (you must be over 16)'}
+ ];
+
+ for (var i = 0; i < helpText.length; i++) {
+ var item = helpText[i];
+ document.getElementById(item.id).onfocus = makeHelpCallback(item.help);
+ }
+}
+
+setupHelp();
+```
+
+用这种方法能解决前面的问题——因为上面的 `makeHelpCallback` 函数为每次回调都单独创建了一个新的词法环境,在这个词法环境中,`help` 指向的是 `helpText` 数组中对应元素的 `help` 属性。
+
+还有一种方法,就是用前面说过的另一个知识点——匿名闭包:
+
+```javascript
+function showHelp(help) {
+ document.getElementById('help').innerHTML = help;
+}
+
+function setupHelp() {
+ var helpText = [
+ {'id': 'email', 'help': 'Your e-mail address'},
+ {'id': 'name', 'help': 'Your full name'},
+ {'id': 'age', 'help': 'Your age (you must be over 16)'}
+ ];
+
+ for (var i = 0; i < helpText.length; i++) {
+ (function() {
+ var item = helpText[i];
+ document.getElementById(item.id).onfocus = function() {
+ showHelp(item.help);
+ }
+ })(); // 会立刻将 item 当前的值与 onfocus 事件相关联
+ }
+}
+
+setupHelp();
+```
+
+如果不喜欢用这么多闭包的话,还可以用 ES2015/ES6 中新引入的关键字 `let`:
+
+```javascript
+function showHelp(help) {
+ document.getElementById('help').innerHTML = help;
+}
+
+function setupHelp() {
+ var helpText = [
+ {'id': 'email', 'help': 'Your e-mail address'},
+ {'id': 'name', 'help': 'Your full name'},
+ {'id': 'age', 'help': 'Your age (you must be over 16)'}
+ ];
+
+ for (var i = 0; i < helpText.length; i++) {
+ let item = helpText[i];
+ document.getElementById(item.id).onfocus = function() {
+ showHelp(item.help);
+ }
+ }
+}
+
+setupHelp();
+```
+
+这个例子中用的是 `let` 而不是 `var`,所以每个闭包都会与块级作用域变量相绑定,这样就不需要额外的闭包了(TODO: 没看懂……)。
+
+## 代码性能问题
+
+由于嵌套函数产生的闭包会显著影响代码的运行速度以及内存占用,所以要注意闭包的使用场合。
+
+比如在创建一个新的对象/类时,通常都会将方法关联到对象的原型上,而不是定义在构造函数内。因为每次调用构造函数的时候,在其中的方法都会被重新分配,如果要创建很多对象的话,这可是相当可观的一笔硬件开销。
+
+先看看反面例子:
+
+```javascript
+function MyObject(name, message) {
+ this.name = name.toString();
+ this.message = message.toString();
+ this.getName = function() {
+ return this.name;
+ };
+
+ this.getMessage = function() {
+ return this.message;
+ };
+}
+```
+
+上面的代码并没有利用闭包的优点,我们来改写成下面这样的:
+
+```javascript
+function MyObject(name, message) {
+ this.name = name.toString();
+ this.message = message.toString();
+}
+MyObject.prototype = {
+ getName: function() {
+ return this.name;
+ },
+ getMessage: function() {
+ return this.message;
+ }
+};
+```
+
+上面的代码比之前的是好一些,但一般不建议重新定义原型,所以下面的代码更好一些:
+
+```javascript
+function MyObject(name, message) {
+ this.name = name.toString();
+ this.message = message.toString();
+}
+MyObject.prototype.getName = function() {
+ return this.name;
+};
+MyObject.prototype.getMessage = function() {
+ return this.message;
+};
+```
+
+在后两段示例代码中,所有对象都共享继承的原型,所以就不需要在每次创建对象的时候都出现一次方法的定义了,这样就不用消耗额外的硬件资源了。可以查看[《Details of the Object Model》](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model)以了解更深入的内容。
diff --git a/topics/nodeclub.md b/topics/nodeclub.md
new file mode 100644
index 0000000..5ef4524
--- /dev/null
+++ b/topics/nodeclub.md
@@ -0,0 +1,5 @@
+# Nodeclub 项目学习笔记
+
+项目链接:[cnodejs/nodeclub](https://github.com/cnodejs/nodeclub)
+
+---
diff --git a/topics/promises.md b/topics/promises.md
new file mode 100644
index 0000000..845245e
--- /dev/null
+++ b/topics/promises.md
@@ -0,0 +1,318 @@
+# [翻译] Promises 入门 - 从菜鸡到吃鸡
+
+原文链接:[JavaScript Promises for Dummies](https://scotch.io/tutorials/javascript-promises-for-dummies)
+
+译者注:对于刚接触 JavaScript Promises 这个概念的人来说,要真正理解它还是有些困难的,比如我就找了好几篇文章,看来看去也没弄明白。还好在网上看到了上面的这篇文章,全方位、多角度、接地气地为我们把 Promises 的方方面面讲得清清楚楚,妈妈再也不怕我不会用 Promises 啦。
+
+好,下面开始上课。
+
+---
+
+## 理解 Promises
+
+想象这么一个场景:
+
+> 你是一个小孩子,妈妈答应你(promises)下周会给你买一部新手机。
+
+好了,问题来了,在此时此刻,你并不知道下周妈妈到底会不会给你买一部新手机,对不对?她开心的话,也许会给你买一部;但你要是把妈妈惹生气了——新手机?别想了。
+
+嗯,这就是一个 **promise**(承诺)。一个 promise(承诺)有三种状态:
+
+1. 等待(**pending**)承诺的结果:你不知道下周会不会有新手机。
+1. 实现了(**resolved**)承诺:妈妈真的给你买了一部新手机诶!
+1. 违背了(**rejected**)承诺:你太闹腾了,妈妈不给你买手机了,别想了。
+
+## Creating a Promise(许下承诺)
+
+让我们来把上面的场景转换为实际的 JavaScript 代码:
+
+```javascript
+/* ES5 */
+
+// 妈妈的心情是个随机数,得看你作不作
+// 就算你不作,妈妈也不一定高兴哦
+var isMomHappy = Math.random() > 0.5;
+
+// Promise
+var willIGetNewPhone = new Promise(
+ function (resolve, reject) {
+ if (isMomHappy) {
+ var phone = {
+ '品牌': '苹果',
+ '颜色': '亮黑'
+ };
+ resolve(phone); // 嗯,妈妈心情不错,给你买手机了,实现承诺了
+ } else {
+ var reason = new Error('妈妈不高兴');
+ reject(reason); // 妈妈不高兴,不要问为什么,不然揍你哦
+ }
+ }
+);
+```
+
+上面的代码还算比较容易懂吧?不懂的话就补补相关的基础知识。下面来解释解释这段代码:
+
+1. 首先有一个布尔型变量 `isMomHappy`,它决定了妈妈的心情。
+1. 然后是一个 promise(承诺) `willIGetNewPhone`,它可能会被 `resolved`(实现)——妈妈给你买了一部新手机——`resolve(phone)`;也可能会被 `rejected`(拒绝)——妈妈不开心,不给你买手机了。
+1. [MDN上的文档](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise)给出了定义一个 `Promise` 的标准格式:
+
+```javascript
+// 定义promise的格式如下所示
+new Promise(/* executor */ function (resolve, reject) { ... });
+```
+
+1. 当实现承诺的时候,就会执行 `resolve(要实现的内容)` 这个函数,否则的话,就会执行 `reject(拒绝的原因)` 这个函数。在上面的例子中,如果妈妈高兴,就会买手机,所以执行 `resolve` 函数并传入 `phone` 这个对象;如果妈妈不高兴,就执行 `reject` 函数并传入 `reason` 这个 `Error` 对象作为拒绝买手机的理由:`reject(reason)`。
+
+## Consuming Promises(执行承诺)
+
+既然许下了承诺,那就让我们来执行(consume)它。
+
+```javascript
+// 执行承诺
+var askMom = function () {
+ willIGetNewPhone
+ .then(function (fulfilled) {
+ // 哈哈,妈妈真的买手机啦
+ console.log(fulfilled);
+ // 输出:'品牌': '苹果', '颜色': '亮黑'
+ })
+ .catch(function (error) {
+ // 唉,妈妈没有买手机
+ console.log(error.message);
+ // 输出: '妈妈不高兴'
+ });
+};
+
+askMom();
+```
+
+解释一下上面这段代码:
+
+1. 定义了函数 `askMom`,在这个函数中执行承诺 `willIGetNewPhone`(consume promise)。
+1. 想在实现承诺或者违背承诺的时候有所表示,所以用 `.then` 和 `.catch` 来控制我们的行为。
+1. 在这个示例中,把 `function(fulfilled) { ... }` 放到了 `.then` 中。`fuifilled` 的值是什么?其实就是在前面的 `resolve(要实现的内容)` 这个函数中,传到 `resolve` 里的参数。所以在这个示例中,传入的就是 `phone` 这个对象。
+1. 示例中还把 `function(error) { ... }` 放到了 `.catch` 中,`error` 的值你大概能猜到,就是在 `reject(拒绝的原因)` 这个函数中,传到 `reject` 里的参数。在这里,就是 `reason` 这个 `Error` 对象。
+
+## Chaining Promises(链式承诺)
+
+Promises 是可以链式调用的。
+
+我们接着前面的例子说。妈妈**答应**给你买新手机之后,你又**答应**你的小伙伴们,等你拿到了你的新手机就给他们看。
+
+嗯,这又是一个 promise(承诺)。Talk is cheap, show you the code!
+
+```javascript
+var showOff = function (phone) {
+ return new Promise(
+ function (resolve, reject) {
+ var message = '小伙伴们,我有新的' + phone['颜色'] + phone['品牌'] + '牌手机啦!';
+
+ resolve(message);
+ }
+ );
+};
+```
+
+注意:
+
+1. 在这段代码中,并没有调用 `reject` 函数,只是调用了 `resolve` 函数。因为 `reject` 函数并不是必需的。
+1. 上面的代码还可以用 `Promise.resolve` 来进行精简。
+
+```javascript
+var showOff = function (phone) {
+ var message = '小伙伴们,我有新的' + phone['颜色'] + phone['品牌'] + '牌手机啦!';
+
+ return Promise.resolve(message);
+};
+```
+
+在这个精简版的代码中,在声明了 `message` 并给它赋值之后,直接将该变量作为参数传入了 `Promise.resolve()` 并返回。不需要像前面的代码一样完整地声明,却还有相同的效果,少花力气多办事,何乐而不为呢?
+
+写完了第二个 `promise` 的代码,我们就可以链式调用这两个 `promise` 了。要注意,`showOff` 这个 `promise` 一定要在 `willIGetNewPhone` 的后面,因为只有拿到了手机,才能向小伙伴们炫耀哦。
+
+```javascript
+// 开始要求兑现承诺
+var askMom = function () {
+ willIGetNewPhone
+ .then(showOff) // 在这里进行链式调用
+ .then(function (fulfilled) {
+ console.log(fulfilled);
+ // 输出:'小伙伴们,我有新的亮黑色苹果手机啦!'
+ })
+ .catch(function (error) {
+ // 唉,妈妈果然还是没给我买手机
+ console.log(error.message);
+ // 输出: '妈妈不高兴'
+ });
+};
+```
+
+怎么样?看了上面的代码,是不是觉得链式调用很简单呢?
+
+## Promises 是异步的
+
+Promises 是异步的,我们在调用 promise 之前和之后加上调试信息,这样便于我们了解代码的执行过程。
+
+```javascript
+// 开始要求兑现承诺
+var askMom = function () {
+ console.log('一会儿要问问妈妈买手机了没'); // 开始调用 promise 之前
+
+ willIGetNewPhone
+ .then(showOff) // 在这里进行链式调用
+ .then(function (fulfilled) {
+ console.log(fulfilled);
+ // 输出:'小伙伴们,我有新的亮黑色苹果手机啦!'
+ })
+ .catch(function (error) {
+ // 唉,妈妈果然还是没给我买手机
+ console.log(error.message);
+ // 输出: '妈妈不高兴'
+ });
+
+ console.log('问过妈妈了……'); // 开始调用 promise 之后
+};
+```
+
+代码的输出会是什么呢?你期望中的输出结果应该是这样的:
+
+```shell
+1. 一会儿要问问妈妈买手机了没
+2. 小伙伴们,我有新的亮黑色苹果手机啦!
+3. 问过妈妈了……
+```
+
+但是!实际的输出结果其实是这样的:
+
+```shell
+1. 一会儿要问问妈妈买手机了没
+2. 问过妈妈了……
+3. 小伙伴们,我有新的亮黑色苹果手机啦!
+```
+
+为什么会这样?因为时间不等人啊(异步函数在调用之后就会一边执行异步函数里的代码,一边继续执行后面的代码。并不会像同步函数那样,等待前面的代码执行完毕再执行后面的)。
+
+打个比方:你这个小朋友在等妈妈买新手机的时候,肯定不是干等着吧?肯定是该玩玩,该吃吃,该睡睡吧?这就叫**异步**,当 JS 执行异步函数的之后,代码并不会停在这里等待结果,而是继续执行后面的代码。
+
+所以,如果有些事情是必须等 promise 执行完成之后才能做的,那就一定要把它放到 `.then` 里面去执行,就像上面的 `willIGetNewPhone.then(showOff)` 一样。
+
+## ES5, ES6/2015, ES7 及之后版本中的 Promises
+
+### ES5 - 大多数浏览器(文章发布时间:2016 年 12 月 1 日)
+
+如果引用了 [Bluebird](http://bluebirdjs.com/docs/getting-started.html) 这个 promise 库的话,文中的演示代码在所有的 ES5 环境中均可正常执行(所有的主流浏览器和 Node.js)。这是因为目前 ES5 对 promises 的支持还不够好,另一个著名的 promise 则是 Kris Kowal 写的 [Q](https://github.com/kriskowal/q)。
+
+### ES6/ES2015 - 现代浏览器,Node.js v6
+
+由于 ES6 原生支持 promises,所以文中的演示代码在 ES6 环境中无需额外设置,直接就可以执行。而且因为有了 ES6 的新特性,就可以用 `胖箭头(箭头函数)=>` 和 `const` 以及 `let` 来将代码进一步优化。
+
+下面是 ES6 版本的演示代码。
+
+```javascript
+/* ES6 */
+const isMomHappy = true;
+
+// Promise
+const willIGetNewPhone = new Promise(
+ (resolve, reject) => { // 箭头函数
+ if (isMomHappy) {
+ const phone = {
+ '品牌': '苹果',
+ '颜色': '亮黑'
+ };
+ resolve(phone);
+ } else {
+ const reason = new Error('妈妈不高兴');
+ reject(reason);
+ }
+ }
+);
+
+const showOff = function (phone) {
+ const message = '小伙伴们,我有新的' + phone['颜色'] + phone['品牌'] + '手机啦';
+ return Promise.resolve(message);
+};
+
+// 开始要求兑现承诺
+const askMom = function () {
+ willIGetNewPhone
+ .then(showOff)
+ .then(fulfilled => console.log(fulfilled)) // 箭头函数
+ .catch(error => console.log(error.message)); // 箭头函数
+}
+```
+
+看见上面的代码了么?所有的 `var` 关键字都替换成了 `const`。所有的 `function(resolve, reject)` 都简化成了 `(resolve, reject) =>`,这些新的写法有几个好处,具体请看下面两篇文章:
+
+- [JavaScript ES6 Variable Declarations with let and const](https://strongloop.com/strongblog/es6-variable-declarations/)
+- [An introduction to Javascript ES6 arrow functions](https://strongloop.com/strongblog/an-introduction-to-javascript-es6-arrow-functions/)
+
+### ES7 - Async Await 让代码看起来更舒服
+
+ES7 中引入了 `async` 和 `await` 这两个关键字,这两个关键字让异步代码看起来更美观,也更容易理解,相比 `.then` 和 `.catch` 而言。
+
+下面我们再用 ES7 的语法来重写 ES6 版本的示例代码。
+
+```javascript
+/* ES7 */
+const isMomHappy = Math.random() > 0.5;
+
+// 承诺
+const willIGetNewPhone = new Promise(
+ (resolve, reject) => {
+ if (isMomHappy) {
+ const phone = {
+ '品牌': '苹果',
+ '颜色': '亮黑'
+ };
+ resolve(phone);
+ } else {
+ const reason = new Error('妈妈不高兴');
+ reject(reason);
+ }
+ }
+)
+
+// 第二个承诺
+async function showOff(phone) {
+ return new Promise(
+ (resolve, reject) => {
+ var message = '小伙伴们,我有新的' + phone['颜色'] + phone['品牌'] + '手机啦'; // 这里为什么用 var 而不是 const?
+ resolve(message);
+ }
+ )
+}
+
+// 开始要求兑现承诺
+async function askMom() {
+ try {
+ console.log('一会儿要问问妈妈买手机了没');
+
+ let phone = await willIGetNewPhone;
+ let message = await showOff(phone);
+
+ console.log(message);
+ console.log('问过妈妈了……');
+ } catch (error) {
+ console.log(error.message);
+ }
+};
+
+(async () => {
+ await askMom();
+});
+```
+
+然后来解释一下上面的代码:
+
+1. 需要在函数中返回 promise 的时候,定义函数时在代码最前面加上 `async` 关键字就行了,比如:`async function showOff(phone)`。
+1. 需要调用 promise 的时候,在函数名前面加上 `await` 关键字就行了,比如 `let phone = await willIGetNewPhone;` 和 `let message = await showOff(phone)`。
+1. 对于被 rejected - 拒绝了的 promise,用 `try { ... } catch (error) { ... }` 来捕获 promise 中的 error。
+
+---
+
+## 为什么要用 Promises?什么时候用?
+
+## 小区里的新朋友:Observables
+
+## 总结
diff --git a/topics/record.md b/topics/record.md
new file mode 100644
index 0000000..33ebf04
--- /dev/null
+++ b/topics/record.md
@@ -0,0 +1,90 @@
+# 新生群精华摘录
+
+## 前言
+
+新生大学的[《JavaScript 编程入门》](https://web.xinshengdaxue.com/user/lessons/details/schedules?course_id=40)这门课已经结束了几个星期了,从八月初到现在(9 月 24 日),徐老师建立的微信群里有很多有价值的讨论内容,就这样让它们湮没在聊天记录中着实可惜,因此一直有这么一个想法,就是要把这些有价值的讨论内容整理记录下来。拖延了好久,今天终于动手了。由于每个人的编程水平、关注方向不同,所以这篇[新生群精华摘录](https://github.com/Dream4ever/JavaScript/blob/master/topics/record.md)只记录了自己觉得有价值的内容。也欢迎大家 [fork 本项目](https://github.com/Dream4ever/JavaScript),共同做出贡献,毕竟还是众人拾柴火焰高嘛~~~
+
+## 方法论:一法通,万法通
+
+### 提问的技巧
+
+如何提出一个高质量的问题?
+
+尽量描述清楚问题的来龙去脉。
+
+有时可能不知道这个问题是怎么产生的,那就尽量回忆一下在问题出现之前做了哪些操作,都列出来。如果在问题出现之后也做了操作,那么操作的步骤和产生的结果也要记下来。
+
+详尽且准确的记录能够让别人更快、更准确地定位问题的出处,而且往往会在自己准确记录的过程中就发现了问题的出处,惊不惊喜?意不意外?哈哈。
+
+### 学习的“秘诀”
+
+相比于编码能力而言,更重要的是思考的能力。刚开始入门的时候,可以只是知其然却不知其所以然。但是想要不断进步,就一定要学着去琢磨背后的道理。正所谓一法通万法通,在学习一门编程语言的过程中,如果能在掌握好基础知识的前提下,再去探究内部的原理、思想、适用环境,并加以提炼、总结,那么在这个过程中的收获,是远比单纯的**写代码**要多得多。比如老师在某堂课上讲的[学习语法时的四大块关键内容](https://github.com/xugy0926/getting-started-with-javascript/blob/master/topics/JavaScript%E7%9A%84%E8%AF%AD%E6%B3%95%E5%AD%A6%E4%B9%A0%E6%8C%87%E5%BC%95.md#学习语法时的自问技巧):一个数据集合,两种函数,三大结构,多种数据格式,就把JS语法中关键的部分都提炼出来了。自己在学习的时候,就可以一边学习,一边往这个知识树里不断添枝加叶。这样有目的的、系统性的学习的效果,就不会让人越学越乱,反而越学越清楚、越明白。
+
+### 读技术书的正确姿势
+
+入门的时候,不管看什么书,别贪多,也别轻易放弃,一本书从头到尾看完,比看一百本书却都没看完可能价值更大。有太多的年轻人从入门到放弃,不一定是因为不够勤奋,而是因为贪多嚼不烂。
+
+作为初学者,当你完整的从头到尾搞清楚一本书之后,形成了初步的知识体系,之后就可以快速的海量阅读了,这样就是在不断地往之前的这个知识体系中补充细节。
+
+这个时候,建议多买几本讲同一类主题的书,这样可以针对某个知识点,来看每本书中作者的理解角度。站在不同的角度上去思考这个知识点,会带来更深的理解。
+
+## 具体的学习技巧
+
+### 学习别人的网页
+
+在 Chrome 浏览器中,打开别人的网页,然后在页面中空白区域点击右键,选择“检查”,就能够看到这个网页的源代码了,HTML、CSS、JS,尽在其中。代码在手,天下我有。
+
+### 关注 GitHub 项目
+
+想要时时关注 GitHub 上某个项目的进展,可以进入这个项目的首页,点击页面右上方带眼睛图标的“Watch”按钮,选择下拉菜单中的“Watching”,就能够在注册 GitHub 帐号时使用的邮箱中,及时接收到这个项目的最新动态了。
+
+### 多人合作开发 GitHub 项目
+
+每次要提交自己的更改之前,先执行一下 `git pull`,将远程仓库上最新版本的代码更新到本地。如果遇到了“本地所更改的文件,在远程(服务器)仓库上也被更改了”的情况,这个时候就需要解决这个冲突,因为一个文件不能同时存在两个版本。在解决冲突之后,就可以将代码推送到远程仓库了。
+
+### 终端/命令行的学习和操作
+
+1. 在初学终端指令的时候,把所有的指令打印一份出来,放在手边随时可以看到的地方,时不时地看一看、练一练,这样很快就能学会了。
+1. 看到不会的命令,可以执行 `man ls`(Mac)或者 `dir /?`(Windows)查看当前命令的说明,建议同时通过谷歌/百度查找该命令的解释和实例,这样能对这个命令的用法和适用情形有一个更清晰的了解。
+1. 多用 `ls`(Mac)或者 `dir`(Windows)命令查看一下当前文件夹里的内容。有时候可能会新建了一个文件,编辑了半天,但是并没有保存且没注意到这个情况,然后就发现网页或者程序还是旧的样子。这个时候在终端里执行一下 `ls` 或者 `dir`,就能够看到新建的文件并不存在,这样就会意识到文件并没有保存,问题的根源就找到了。**建议**:尽量开启编辑器的自动保存功能,一方面能够保证程序的执行结果是在最新代码的基础上出来的,另一方面也能够避免忘记保存又不小心关闭了文件导致前功尽弃的情况。
+1. 多用 `pwd`(Mac)或者 `cd`(Windows)查看当前目录的完整路径,有时候进错了目录,执行程序失败还找不到原因的,可以用这个命令看看是不是进错了目录。
+
+注:Unix 和 Mac 算是同根同源的兄弟,所以命令行的操作应该都是差不多的(此处未做严谨论证,了解大意即可)。
+
+延伸阅读:
+
+- [Windows 和 Unix 命令行对应表](https://www.lemoda.net/windows/windows2unix/windows2unix.html):这个表里列出来了在 Windows 和 Unix 下效果相似/相同的命令,网上的文章有时只会列出来 Windows 或者 Unix 下的命令,这个时候就可以根据这个表来查来一套系统下对应的命令了。
+- [What's the relationship between unix, BSD, Mac OS X, linux and GNU? [closed]](https://stackoverflow.com/a/26700489/2667665):讲述了 Unix 这个操作系统大家族的简史。
+- [Is there a beginners guide to Unix from the OS X point of view?](https://apple.stackexchange.com/questions/9973/):介绍了几个学习 Unix/macOS 终端命令的资源,可参考。
+- [Windows 下的类 Unix 工具](https://alternativeto.net/software/cygwin/):对于想要在 Windows 下体验 Unix 命令行的朋友们,可以查看这里提到的几款软件,比如 Cygwin、MSYS2、Babun 等。
+- [Windows 10 Installation Guide](https://msdn.microsoft.com/en-us/commandline/wsl/install_guide):对于 Win 10 用户,还可以参考这篇文章里的方法,来安装 Linux 子系统(可选择 Ubuntu),这样就能在命令行中使用 `bash` 了 —— 在命令行中输入 `bash`,就会进入其运行环境了。
+
+### 学习 Markdown
+
+建议大家都要学会 md(markdown 的缩写)。在平时工作时,用 md 来写会议记录、学习笔记、文章都很不错,通过 md 导出 html 或 pdf 格式的文件也很方便。
+
+那么 md 是如何实现呢?它的本质就是把符号变成 html。
+
+比如 md 格式的文本 `# 标题一` 就会被转换成 html 代码 `
标题一
`。
+
+背后其实是有一个解析器在做这个工作的,我们可以研究这个解析器,进而定制它,来得到我们想要的效果。
+
+### 定制 Markdown 的 CSS 样式
+
+想要定制 markdown 文本样式的同学,可以去参考一下 [sindresorhus/github-markdown-css](https://github.com/sindresorhus/github-markdown-css) 这个项目。
+
+### Git 小知识
+
+建议使用 https 协议克隆项目,因为这样更安全,并且配置简单。
+
+项目克隆到本地之后,克隆下来的项目,从严格意义上并不叫项目,而是叫项目**仓库**,一定要带上仓库这个词。因为对于仓库,才能衍伸出 `git add`、`git commit`、`git push` 的差异。
+
+`git add` 用于将改动过的文件添加到本地仓库的缓冲区域,`git commit` 则用于将缓冲区域中的文件提交到本地仓库,这两步操作的对象都是本地仓库。
+
+`git add`、`git commit` 可以在执行 `git push` 之前多次操作,这有什么意义呢?比如我的电脑暂时没网,而我有几个或者十几个小需求需要完成。为了代码的回溯或者更改上的方便,我就可以每完成一个小需求之后,便 `git add` 并 `git commit` 一次,等之后联网了再把这些 commits 一起上传。这样在之后做 bug 排查时,就可以通过每次回滚一个 commit 的方式,来查看究竟是哪个需求的代码出了问题。如果把所有需求全部完成之后,才做一次 `git add` 及 `git commit`,那后面排查问题就相当麻烦了。
+
+`git push` 则是将前一次 `git push` 之后的所有 commits 都推送到远程仓库,只有执行了这一步操作之后,远程仓库才会被更改。
+
+---
+
+已记录至 2017/8/13 10:04。
diff --git a/topics/relative-path.md b/topics/relative-path.md
new file mode 100644
index 0000000..6051bd6
--- /dev/null
+++ b/topics/relative-path.md
@@ -0,0 +1,35 @@
+# 茴字的七种写法 - 论 Web 页面中的相对路径
+
+在 HTML 文件中,都要引入外部文件来丰富及样式及互动效果。那么该用什么样的路径来引入外部文件呢?今天就和大家来探讨一下这个话题。
+
+下面这张图,是 Web 服务器上,网站文件夹的目录结构。
+
+在 `getting-started-with-javascript` 这个网站的根目录,有文件 `index.html` 和 `banner.png`,以及两个文件夹:`register` 和 `public`。
+
+在 `register` 文件夹中,有文件 `reg.html`。
+
+在 `public` 文件夹中,又有子文件夹 `css`、`js`、`images` 以及 `error`。而在各个子文件夹中,又分别有文件 `style.css`、`main.js`、`bg.png` 以及 `error.html`。
+
+
+
+## 一、引用当前目录中的其它同级文件
+
+说明文字
+
+
+
+## 二、引用同级的文件夹里的内容
+
+说明文字
+
+
+
+## 三、引用其它位置的文件
+
+说明文字一
+
+
+
+说明文字二
+
+
\ No newline at end of file
diff --git a/topics/server.md b/topics/server.md
new file mode 100644
index 0000000..023f72e
--- /dev/null
+++ b/topics/server.md
@@ -0,0 +1,520 @@
+# 阿里云轻量应用服务器教程
+
+## 一、服务器购买及开通
+
+这个步骤很简单,选好配置,下单,付款,等几分钟服务器就自动运行起来了。
+
+我购买的服务器配置:
+
+- CPU:1核
+- 内存:1G
+- 硬盘:20G SSD云盘
+- 区域:北京(离自己所在城市最近)
+- 操作系统:CentOS 7
+- 应用镜像:Node.js 4.8.4
+
+## 二、远程登录服务器
+
+### 设置密钥
+
+服务器运行起来之后,有两种方式可以登录服务器,一种是在浏览器中登录,便捷,但功能不够强大。
+
+另一种就是在 Windows 或者 Mac 中通过专门的软件来登录。
+
+为了保证远程登录的安全,阿里云会要求生成密钥并下载 pem 文件至本地,登录时需要用到这个文件。下面就分别说一下在 Windows 和 Mac 下如何建立 SSH 安全连接。
+
+### Windows 连接至服务器
+
+Windows 下的操作流程,按照官方文档来就可以了,每一步都列出来了,照着操作就行。
+
+具体操作步骤请查看[通过本地 SSH 客户端连接服务器](https://help.aliyun.com/document_detail/59083.html?spm=5176.10173289.0.0.378f90fd0Orgcq)一文中,“本地为 Windows 环境”这一小节。
+
+### Mac 连接至服务器
+
+Mac 自带的终端或者 iTerm2 就可以很好地完成这件事,无需另外安装软件。
+
+#### 步骤一:准备 pem 密钥文件
+
+本机存放 SSH 相关文件的目录位于 `~/.ssh` ,所以把前面下载到本地的 pem 文件复制到这里就行。
+
+```shell
+> cd ~/.ssh
+> sudo cp ~/Downloads/swas.pem swas.pem
+```
+
+然后设置 pem 文件的权限。
+
+```shell
+> chmod 400 swas.pem
+```
+
+#### 步骤二:SSH 连接至服务器
+
+```shell
+// 10.10.10.10仅作说明用,请将这个IP改成服务器的实际IP
+> ssh root@10.10.10.10 -i ~/.ssh/swas.pem
+```
+
+输入上面的命令之后,如果成功登录,则会显示类似下面的信息,说明登录成功。
+
+```shell
+Last login: Wed Sep 27 10:18:43 2017 from 22.22.22.22
+
+Welcome to Alibaba Cloud Elastic Compute Service !
+
+[root@XXXX ~]#
+```
+
+然后我们再输入 `exit` 关闭 SSH 连接,进行下面的操作。
+
+#### 步骤三:保存 SSH 会话
+
+在 Mac 下,自然要用 iTerm2 这款强大的终端软件。通过在软件中设置 Profile,就能方便地一键连接至服务器。
+
+1. 运行 iTerm2,按下快捷键 `⌘+,`,打开 iTerm2 的选项设置对话框。
+1. 点击 Profiles 这个标签,我们来新建一个 Profile(配置文件),用于实现一键连接服务器的功能。
+1. 参照下图,点击界面左下角的加号 +,新建一个 Profile。Name 为这个 Profile 的名称,Tag 可以当做注释,Shortcut key 是快速启动这个 Profile 的快捷键,由于在 Mac 下,微信占用了 ^⌘A 这个快捷键用作截图,所以在这里我把快捷键设置为 ^⌘1。Command 那里,就填第二步中的一长串命令。
+1. 设置完成,关闭选项设置对话框,然后在 iTerm2 中按下快捷键 ^⌘1,开始玩服务器吧!
+
+
+
+参考资料:
+
+- [通过本地 SSH 客户端连接服务器 - 本地为 Linux 或支持 SSH 命令的环境](https://help.aliyun.com/document_detail/59083.html?spm=5176.10173289.0.0.2d2fedd63Boph1):按照教程“本地为 Linux 或支持 SSH 命令的环境”这一小节里的说明,用 `chmod` 命令设置 pem 文件的权限。
+- [connecting to amazon aws linux server by ssh on mac](https://stackoverflow.com/a/14230817):参考这个回答,将 pem 文件放到 `~/.ssh` 目录下。
+- [Fast SSH Windows With iTerm 2](https://hiltmon.com/blog/2013/07/18/fast-ssh-windows-with-iterm-2/):参考这个回答,在 iTerm2 中保存 SSH 会话,通过快捷键可立即连接至服务器。
+
+#### 步骤四:启用密码登录(可选)
+
+可以正常登录的,不用看这一步。
+
+由于启用 SSH 登录方式之后,服务器默认会将 root 帐号密码登录的方式禁用掉。而自己不知道做了什么修改,使得在 Mac 下无法通过密钥登录,只好再次开启密码登录的方式。
+
+在 Windows 上登录服务器,然后做如下操作。
+
+```shell
+sudo vi /etc/ssh/sshd_config
+// 在 vim 中将 PasswordAuthentication no 改为 PasswordAuthentication yes,然后保存退出
+sudo systemctl restart sshd
+// 上面的命令重启了 sshd,这样在 Mac 中就可以用密码登录 root 帐号了
+```
+
+参考资料:
+
+- [启用密钥后恢复账号密码登录](https://help.aliyun.com/document_detail/59083.html?spm=5176.10173289.0.0.244123376jXRwl#activeroot)
+- [ssh : Permission denied (publickey,gssapi-with-mic)](https://stackoverflow.com/questions/36300446/ssh-permission-denied-publickey-gssapi-with-mic)
+
+#### 解决 macOS SSH 登录时的警告
+
+在 macOS 下通过终端登录时,会给出下面的提示:
+
+```shell
+-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
+```
+
+上网查了一下,原来是终端试图将本机的环境变量传入到服务器中,这肯定是不需要的。
+
+解决方法:在前面设置好的 iTerm2 的 Profile 中,将 Terminal 标签下的 `Set locale variables automaticlly` 取消选择。
+
+
+
+参考资料:
+
+- [OS X Terminal: -bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory Fix](https://www.cyberciti.biz/faq/os-x-terminal-bash-warning-setlocale-lc_ctype-cannot-change-locale/)
+
+## 三、更新服务器系统所有程序包(package)
+
+装好了系统,先把所有程序都更新到最新版。
+
+```shell
+> yum update
+```
+
+执行了上面的命令之后,会提示有许多 packages 需要更新,可能还有附带的 packages 需要安装,按下 `y` 键并回车,开始更新即可。
+
+## 四、服务器安全设置(可选)
+
+### 服务器建立普通权限用户
+
+由于用 root 用户登录服务器可能带来安全问题,比如误删文件等等,所以需要建立一个普通权限的用户进行日常操作。
+
+```shell
+> adduser www
+> passwd www
+// 输入第二条命令之后,会提示输入两次密码,输入密码的过程中不会显示任何内容,盲打即可
+```
+
+### 赋予 root 权限
+
+有时候需要用 root 权限的用户进行操作,但是注销当前普通权限的用户,再用 root 用户登录实在太麻烦了,直接给普通用户赋予 root 权限就好了,这样以后就可以在这个用户下直接用 `sudo` 执行命令了。
+
+```shell
+> gpasswd -a www wheel
+```
+
+上面的命令将前面新建的 www 用户加入了 `wheel` 这个用户组,而这个用户组是有权限执行 `sudo` 命令的。
+
+### 添加公钥验证
+
+通过在用户的电脑上生成 SSH 密钥对,并将公钥放到服务器上,可以增强服务器安全。
+
+#### 本机生成密钥对
+
+执行下面的命令(Windows 下在 Git Bash 中,Mac 下在终端里),一路回车即可。
+
+```shell
+> ssh-keygen
+```
+
+上面的命令,会在本机当前用户的 `.ssh` 目录下,生成 `id_rsa` 和 `id_rsa.pub` 两个文件。前面的一个文件是用户的私钥,后面的一个文件是用户的公钥。
+
+#### 复制公钥至服务器
+
+首先在本机的终端里显示公钥的内容。
+
+```shell
+> cat ~/.ssh/id_rsa.pub
+```
+
+然后完整复制显示出来的一长串文字。
+
+接着在服务器上切换至用户 www。
+
+```shell
+> su - www
+```
+
+然后新建 `.ssh` 目录并设置权限。
+
+```shell
+> mkdir .ssh
+> chmod 700 .ssh
+```
+
+接着新建 `authorized_keys` 文件。
+
+```shell
+> vi .ssh/authorized_keys
+```
+
+按下 `i` 键进入编辑模式,然后按下 `Shift+Insert` 键将刚才在本机上复制的公钥粘贴进去。按下 `Esc` 键退出编辑模式,输入 `:x` 保存修改并关闭文件。
+
+然后再设置 `authorized_keys` 文件的权限。
+
+```shell
+> chmod 600 .ssh/authorized_keys
+```
+
+最后执行 `exit` 便可退出 www 用户,切换回 root 用户。
+
+这个时候,用户在本机就可以通过 `ssh www@10.10.10.10 -i ~/.ssh/id_rsa` 这样的命令,以 www 用户的身份登录至服务器了。
+
+### 配置 SSH 守护进程
+
+配置好了普通用户之后,还可以禁止 root 用户的 SSH 登录,以进一步提升安全性。
+
+执行下面的命令,将会进入 vim,编辑 SSH 配置文件。
+
+```shell
+> vi /etc/ssh/sshd_config
+```
+
+需要修改的这一行为 `#PermitRootLogin yes`。输入 `/PermitRoot` 并回车,会定位至 `#PermitRoot` 所在的行,并且定位在字母 P 上。
+
+按下快捷键 `Shift+x`,删除字母 P 前面的井号 `#`。
+
+按下快捷键 `Ctrl+→`,光标跳到下一个单词的 yes 首字母上。
+
+按下快捷键 `cw`,删除 yes 整个单词;再输入 no,然后按下 `Esc` 退出编辑模式,输入 `:x` 保存修改并关闭文件。
+
+执行完上面这些操作之后,重启 SSH 服务,使其生效。如果重启 SSH 服务还不能禁止 root 用户的登录,那就执行 `reboot` 命令重启一下服务器吧。
+
+```shell
+> systemctl reload sshd
+```
+
+注意!前面的操作禁止了 root 用户的 SSH 登录,为了安全起见,需要先测试一下 www 用户是否真的能够成功 SSH 登录,确保 www 用户的登录没问题之后,才可以注销当前的 root 用户。
+
+参考资料:
+
+- [Initial Server Setup with CentOS 7](https://www.digitalocean.com/community/tutorials/initial-server-setup-with-centos-7)
+
+## 五、配置 node 环境
+
+建立 www 用户之后,就可以用这个用户登录了。
+
+~~首次登录时,提示 `-bash: /root/nvm/nvm.sh: Permission denied`。可以看出来,因为用非 root 用户登录,默认是没有权限使用 root 用户安装的 nvm的,那该怎么办呢?跟我来。~~(按照下面的设置依然无法解决每次登录时显示该提示的问题。)
+
+### 为普通权限用户安装 nvm
+
+先根据官网的教程,安装最新版的 nvm。
+
+```shell
+> curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.4/install.sh | bash
+```
+
+然后执行下面的命令,完成 nvm 的设置。
+
+```shell
+export NVM_DIR="$HOME/.nvm"
+[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
+[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
+```
+
+### 安装最新版 node.js
+
+所购买的服务器,自带的 node.js 版本为 4.8.4,实在是有点儿老,果断给它升级一下。
+
+```shell
+> nvm install node
+// 如果 nvm 不识别 node 参数,就得明确指定 node 的版本了
+> nvm install 8.6.0
+```
+
+上面的命令,会安装最新版 8.6.0。安装完成后,我们再看看系统中有哪些版本的 node.js。
+
+```shell
+> nvm ls
+-> v8.6.0
+default -> 8.6.0 (-> v8.6.0)
+node -> stable (-> v8.6.0) (default)
+stable -> 8.6 (-> v8.6.0) (default)
+iojs -> N/A (default)
+lts/* -> lts/boron (-> N/A)
+lts/argon -> v4.8.4 (-> N/A)
+lts/boron -> v6.11.3 (-> N/A)
+```
+
+从上面的输出结果可以看到,普通使用的话,有最新的 8.6.0 就够了。这样基础的 node 环境就配置好了。
+
+参考资料:
+
+- [creationix/nvm](https://github.com/creationix/nvm):nvm的官网,参考上面的安装流程。
+- [ubuntu中npm安装全局插件提示没有root管理员权限](https://zhouyuexie.github.io/ubuntu%E4%B8%ADnpm%E5%AE%89%E8%A3%85%E5%85%A8%E5%B1%80%E6%8F%92%E4%BB%B6%E6%8F%90%E7%A4%BA%E6%B2%A1%E6%9C%89root%E7%AE%A1%E7%90%86%E5%91%98%E6%9D%83%E9%99%90/)
+- [线上node服务的配置和维护,使用非root账户运行和sudo管理](https://cnodejs.org/topic/57216ea1fa48138c41110ec8)
+
+## 六、配置 Express 框架
+
+### 安装 Express
+
+基本的 node.js 环境建立起来了,那就先用 Express 搭建一个简单的网页框架,首先把 Express 框架安装好。
+
+```shell
+> npm install -g express
+> npm install -g express-generator
+```
+
+### 创建项目
+
+然后再用 Express 框架创建项目 blog。
+
+```shell
+> express -v ejs blog
+> cd blog && npm install
+```
+
+### 启动项目
+
+项目建立起来之后,当然要运行一下看看啦。好,那就执行 `npm start`,然后在网页中访问 [http://10.10.10.10:3000](http://10.10.10.10:3000),嗯?为什么打不开呢?想起来购买的这个服务器还装了 nginx 这个反向代理,是不是和它有关?
+
+Google 一番,发现原来需要在服务器控制台的“防火墙”中开放 3000 这个端口,于是新建一个应用类型为“自定义”的端口,协议选择“TCP”,端口号设置为“3000”。
+
+然后再重启刚才新建的 Express 项目,并访问上面的那个网址,啊哈,可以访问了!
+
+参考资料:
+
+- [阿里云ubuntu nginx无法访问,求解答](https://segmentfault.com/q/1010000009437407)
+
+## 七、配置 nginx 映射项目
+
+由于 Express 默认用的是 3000 端口号,每次访问服务器的时候还要加上端口号实在是麻烦,那就在 nginx 中将来自 80 端口的请求都指向本机的 3000 端口。
+
+注意,以下 nginx 相关的操作,都要在 root 用户中执行,为什么非 root 用户不能操作呢?请看这篇文章:[Why does nginx starts process as root?](https://unix.stackexchange.com/questions/134301/why-does-nginx-starts-process-as-root)。
+
+### 安装 nginx
+
+```shell
+> sudo yum install epel-release
+> sudo yum install nginx
+```
+
+然后启动 nginx,并使其开机自动启动。
+
+```shell
+> reboot
+> sudo systemctl start nginx
+> sudo systemctl enable nginx
+```
+
+参考资料:
+
+- [How To Install Nginx on CentOS 7](https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-centos-7)
+
+### 转发至 Express 程序
+
+首先,查找 nginx 所在的路径。
+
+```shell
+> whereis nginx
+nginx: /usr/sbin/nginx /usr/lib64/nginx /etc/nginx /usr/share/nginx /usr/share/man/man8/nginx.8.gz /usr/share/man/man3/nginx.3pm.gz
+```
+
+依次查看上面几个路径可知,/etc/nginx 文件夹里包含了 nginx.conf 这个配置文件。
+
+```shell
+> sudo vi /etc/nginx/nginx.conf
+```
+
+在 location 字段中增加下面这段代码,记得先将 10.10.10.10 改成服务器的外网 IP。
+
+```shell
+location / {
+ proxy_pass http://10.10.10.10:3000;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection 'upgrade';
+ proxy_set_header Host $host;
+ proxy_cache_bypass $http_upgrade;
+}
+```
+
+然后重启 nginx,设置完成。
+
+```shell
+> sudo systemctl restart nginx
+```
+
+参考资料:
+
+- [How To Set Up a Node.js Application for Production on CentOS 7](https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-centos-7):参考其中的“Set Up Reverse Proxy Server”这一小节。
+
+### 重定向 www 域名至非 www 域名
+
+待完成。
+
+## 八、配置域名
+
+### 购买域名
+
+买了服务器,不能只是用 IP 来访问,当然要买个域名了。上网查了一番,决定购买 GoDaddy 家的域名,比了比后缀和价格,最后买下了 [hewei.in](http://hewei.in) 这个域名。
+
+### 设置 GoDaddy 域名解析
+
+买了域名之后,还要设置 DNS 用于域名的解析。有两种方式:
+
+第一种方式是用 GoDaddy 自家的域名解析服务,参照下图中设置 GoDaddy 的域名解析。红圈标注的地方设置为服务器的 IP,其它选项全用默认值。
+
+
+
+然后还要在阿里云的云解析中,添加域名的 A 记录和 CNAME 记录。
+
+
+
+然后等待十分钟左右,域名解析生效了,就可以访问啦~
+
+小知识:什么是 A 记录?什么又是 CNAME 记录?
+
+A 记录,就是将前面购买的域名,指向自己的服务器 IP,这样域名才能真正生效。设置 A 记录之前,只能通过 IP 访问服务器;添加了 A 记录之后,就可以通过域名访问服务器了。
+
+而 CNAME 记录,则是将其它域名重定向到自己购买的域名,最常见的,就是将带了 `www.` 前缀的域名,指向自己购买的域名。像上图中那样,添加了主机记录为 www 的 CNAME 记录之后,访问 www.hewei.in,就会自动重定向到 hewei.in 了。
+
+### 设置阿里云云解析
+
+第二种设置域名解析的方式,是完全由阿里云来解析域名。这个就留给大家来自行探索吧!哈哈~
+
+参考资料:
+
+- [GoDaddy 域名修改 DNS 方法](https://help.aliyun.com/knowledge_detail/39851.html)
+
+### 服务器/域名备案
+
+待完成。
+
+## 九、设置 Git 仓库
+
+**本节内容有问题,待修改**。
+
+### 安装最新版 Git
+
+参考这篇文章进行:[How to Install Git 2.0.5 on CentOS/RHEL 7/6/5 and Fedora 22/21](https://tecadmin.net/install-git-2-0-on-centos-rhel-fedora/)。
+
+### 服务器开启 RSA 认证
+
+在文件 `/etc/ssh/sshd_config` 中添加下列三行内容(如果已经有则不必重复添加):
+
+```shell
+RSAAuthentication yes
+PubkeyAuthentication yes
+AuthorizedKeysFile .ssh/authorized_keys
+```
+
+### 初始化仓库
+
+在当前用户的根目录下(`/home/www`),专门新建一个 repo 文件夹,用于接收本地的推送并自动更新至前面建立的项目目录。
+
+```shell
+> cd ~
+> mkdir repo && cd repo
+> mkdir blog.git && cd blog.git
+> git init --bare
+```
+
+上面最后一步的命令会新建 branches、hooks、info、objects、refs 这几个文件夹,和 HEAD、config、description 这几个文件。
+
+### 关联仓库和项目
+
+```shell
+> cd hooks
+> cat > post-receive
+```
+
+执行完这两行指令之后,输入下面的文字,并按 Ctrl+d 键保存。
+
+```shell
+#!/bin/sh
+git --work-tree=/home/www/blog --git-dir=/home/www/repo/blog.git checkout -f
+```
+
+上面的两行文字中,`/home/www/blog` 为前面新建的网站项目所在的目录,由于已经申请了域名,所以用域名为名称重新建立了网站项目;`home/www/repo/blog.git` 则是刚才新建的仓库文件夹。这两个目录的实际路径要结合自己的实际情况来确定,不要照搬。
+
+然后再执行下面的命令,设置刚才新建文件的权限,以保证它能够正常运行。
+
+```shell
+> chmod +x post-receive
+```
+
+### 本机建立对应项目
+
+在本机上也建立同名的项目,便于管理。下面的命令行代码以 Mac 为例,Windows 类似。
+
+```shell
+> cd ~/Code
+> mkdir blog && cd blog
+> mkdir .git && cd .git
+> git init
+> git remote add blog www@10.10.10.10:/home/www/repo/blog.git
+```
+
+上面命令中的最后一行代码,将远程服务器上刚才新建的仓库,命名为 blog,并与本地仓库关联。
+
+### 更改本地项目并推送
+
+建立了关联之后,测试一下在本地的修改是否能成功推送到服务器上。将之前做的一个简单的网页内容复制到了 `/views/index.ejs` 中,然后执行下面的命令,开始上传。
+
+```shell
+git add .
+git commit -m "init"
+git push --set-upstream blog master
+```
+
+由于是首次往服务器通过 git 上传文件,所以需要用最后一条命令,在远程服务器建立 master 分支,并将本地当前 master 分支的内容推送上去。
+
+之后需要推送的话,只用执行 `git push` 命令就可以了。
+
+参考资料:
+
+- [How To Set Up Automatic Deployment with Git with a VPS](https://www.digitalocean.com/community/tutorials/how-to-set-up-automatic-deployment-with-git-with-a-vps):大体思路参考这篇文章,但是在此基础上有所修改。
+
+## 十、配置守护进程
+
+待完成。
diff --git a/topics/vscode.md b/topics/vscode.md
new file mode 100644
index 0000000..f3ba267
--- /dev/null
+++ b/topics/vscode.md
@@ -0,0 +1,99 @@
+# VSCode 应用笔记
+
+## 自带功能
+
+### 笔记说明
+
+#### 快捷键
+
+VSCode 自身的功能,都可以通过编辑设置文件来进行修改,打开该文件的编辑界面的快捷键,在 Windows 下为 `Win+,`,在 Mac 下为 `Command (⌘)+,`。
+
+为方便起见,后文中提到 Windows/Mac 快捷键的地方,均采用下面对应关系表中,最右侧一列的简介形式:Cmd、Alt、Ctr。
+
+| Win | Mac | Mac 下的图标 | 本文中采用的简写 |
+| - | - | - | - |
+| Windows | Command | ⌘ | Cmd |
+| Alt | Option/Alt | ⌥ | Alt |
+| Control | Control | ^ | Ctr |
+
+
+
+#### 建议选项
+
+VSCode 中的很多设置都有多个选项可供选择,在列出各个选项的时候,会以粗体显示建议使用的选项名称。
+
+- **选项 A**
+- 选项 B
+- 选项 C
+
+#### 编辑方式
+
+VSCode 中的自带功能均可进行修改,下图中右侧的内容为用户设置(User Settings),这里的设置会覆盖 VSCode 中的默认设置。
+
+用户设置中的内容,需按照标准的 JSON 文件的格式进行编写,即:
+
+```markdown
+"选项名称": 选项的可选值,
+// 示例
+"files.autoSave": "afterDelay",
+```
+
+如果选项的可选值仅有 true/false 两项,那么在填写选项的值时,不用加双引号;选项的可选值为数字时,也不用加双引号;只有在选项的值为其它字符串时,才需加双引号。
+
+最后一个选项之前的选项,在行末都要加上分号,这个分号必须有。
+
+如果一个选项包含多个子选项,则必须按照原来的格式,在父选项内部写上子选项的设置:
+
+```markdown
+"[markdown]": {
+ "editor.quickSuggestions": true
+},
+```
+
+
+
+### 自动保存 - `files.autoSave`
+
+VSCode 贴心地提供了自动保存的功能,这样写完代码之后就不用担心因为忘记自动保存,而看不到修改后的代码的执行结果了。如果要开启自动保存功能,有三个选项可供选择:
+
+- **afterDelay**: 延迟一定时间后自动保存,这个时间由选项 `"files.autoSaveDelay": 1000,` 中的值 `1000` 决定。
+- onFocusChange: 编辑器失去焦点后自动保存。
+- onWindowChange: 窗口失去焦点后自动保存。
+
+第二和第三个选项的区别是什么呢?VSCode 的窗口包含若干个部分,编辑器只是其中的一个部分,我们借用下面这张来自 VSCode 官方网站的图来说明一下:在主界面的几部分中,区域 C 为编辑器,剩下的区域则是 VSCode 窗口的其它部分。
+
+如果应用第二个选项,即使没有切换到别的程序中,而只是点击了 VSCode 窗口编辑器以外的部分,VSCode 也会自动保存。
+
+而应用第三个选项的话,则必须切换到别的程序中,VSCode 才会自动保存。
+
+
+
+### 自动展开文件夹 - `explorer.autoReveal`
+
+在浏览或编辑文件时,可以选择让 VSCode 在左侧的 `Explorer`(项目管理器)中自动展开当前文件所属的文件夹。是否要开启这个功能因人而异,我自己是关闭了这个功能的,因为实在是用不上。
+
+- true/false: 开启或关闭该功能,下同。
+
+## 插件推荐
+
+### Code Outline
+
+### ESLint
+
+### Git History
+
+### Git Project Manager
+
+### markdownlint
+
+### npm
+
+### Quick and Simple Text Selection
+
+### Vue 2 Snippets
+
+---
+
+## 参考资料
+
+[为什么我选择使用 VS Code进行前端开发?](https://segmentfault.com/a/1190000010750647?utm_source=weekly&utm_medium=email&utm_campaign=email_weekly):用到了里面介绍的 Dash、Path Intellisense 这两个扩展。