Emily's blog


  • 首页

  • 分类

  • 关于

  • 归档

  • 标签

  • 搜索
close
Emily's blog

从浏览器输入一个地址到渲染出网页的过程

发表于 2017-06-14 |
  1. http://abc.com:80/z/c?i=1#b
    http协议 uri 端口号 路径 参数 片段

  2. 域名通过dns解析成ip

    • 首先查询浏览器缓存
    • 再查询系统缓存
    • 再递归查询dns服务器
  3. 建立tcp链接,三次握手

    • syn-》
    • 《- syn/ack
    • ack -》
  4. http报文生成

    • 报文首部
      1. 请求行 PUT example.html HTTP1.1
      2. 请求首部字段:Accept等
    • 报文体
  5. 包装报文,经过链路层(mac),传输层(tcp),网络层(ip),应用层(http)
  6. 服务器接收到HTTP请求

服务器接收到数据之后,会经过链路层,网络层,传输层逐层将该层对应的首部信息去掉

7. 服务器根据收到的HTTP数据,生成对应的响应报文,结构如下:

状态行:由HTTP 版本 状态码 原因短语构成
响应首部字段 通用首部字段 实体首部字段 都可以查手册得知其具体内容以及含义这里不再展开

  1. 客户端接收到了响应报文之后,浏览器渲染呈现
    1. 浏览器通常的主要组件分为以下几部分:
      • 用户界面:如地址栏 书签菜单等等
      • 浏览器引擎:在用户界面和呈现引擎之间传送之类
      • 呈现引擎:负责显示请求的内容。例如HTMLhe CSS
      • JAVAScript解释器:用于解释和执行JavaScript 代码
      • 数据存储
    2. 渲染文档主要使用呈现引擎。
      过程如下:
      1. 呈现引擎从网络层获取请求文档的内容HTML文件,内容大小一般在8000个块以内。
      2. 引擎解析HTML文档 将各个标记转化为内容树上的DOM节点 ,同时解析CSS文件 样式数据
      3. 样式信息和 内容树共同构建成为 呈现树
      4. 呈现树构建完毕以后,进入布局阶段, 为每一个节点分配一个应该出现在屏幕上的确切坐标
      5. 呈现引擎遍历呈现树 由用户界面后端层将每个节点绘制出来。
  • 参考链接1
  • 参考链接2
Emily's blog

this的四种用法

发表于 2017-06-14 |

在函数执行时,this 总是指向调用该函数的对象。
要判断 this 的指向,其实就是判断 this 所在的函数属于谁。
在《javaScript语言精粹》这本书中,把 this出现的场景分为四类,简单的说就是:
有对象就指向调用对象,没调用对象就指向全局对象,用new构造就指向新对象,
通过 apply 或 call 或 bind 来改变 this 的所指。

1. 函数有所属对象时:指向所属对象

函数有所属对象时,通常通过 . 表达式调用,这时 this自然指向所属对象。比如下面的例子:

1
2
3
4
5
6
7
8
var myObject = {value: 100};
myObject.getValue = function () {
console.log(this.value); // 输出 100
console.log(this);// 输出 { value: 100, getValue: [Function] },
// 其实就是 myObject 对象本身
return this.value;
};
console.log(myObject.getValue()); // => 100

getValue() 属于对象 myObject,并由 myOjbect 进行 . 调用,因此 this 指向对象 myObject。

2. 函数没有所属对象:指向全局对象

1
2
3
4
5
6
7
8
9
10
var myObject = {value: 100};
myObject.getValue = function () {
var foo = function () {
console.log(this);// 输出全局对象 global
console.log(this.value) // => undefined
};
foo();
return this.value;
};
console.log(myObject.getValue()); // => 100

在上述代码块中,foo 函数虽然定义在 getValue的函数体内,但实际上它既不属于 getValue 也不属于 myObject。foo 并没有被绑定在任何对象上,所以当调用时,它的 this 指针指向了全局对象 global。据说这是个设计错误。

3. 构造器中的 this:指向新对象

js 中,我们通过 new 关键词来调用构造函数,此时 this会绑定在该新对象上。

1
2
3
4
5
var SomeClass = function(){
this.value = 100;
}
var myCreate = new SomeClass();
console.log(myCreate.value); // 输出100

顺便说一句,在 js 中,构造函数、普通函数、对象方法、闭包,这四者没有明确界线。界线都在人的心中。

4. apply 和 call 调用以及 bind 绑定:指向绑定的对象

  • apply() 方法接受两个参数第一个是函数运行的作用域,另外一个是一个参数数组(arguments)。
  • call() 方法第一个参数的意义与apply()方法相同,只是其他的参数需要一个个列举出来。
    简单来说,call 的方式更接近我们平时调用函数,而 apply 需要我们传递 Array 形式的数组给它。它们是可以互相转换的。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var myObject = {value: 100};
    var foo = function(){
    console.log(this);
    };
    foo(); // 全局变量 global
    foo.apply(myObject); // { value: 100 }
    foo.call(myObject); // { value: 100 }
    var newFoo = foo.bind(myObject);
    newFoo(); // { value: 100 }
Emily's blog

ECMAScript 6 变量解构赋值

发表于 2016-12-06 | 分类于 理解ECMAScript 6 |

为什么解构很有用

ECMAScript 5以及以前的版本:

1
2
3
4
5
6
7
let options = {
repeat: true,
save: false
};
// extract data from the object
let repeat = options.repeat,
save = options.save;

虽然这段代码看上去也挺简单的,但想象一下如果你要给大量的变量赋值,你得一个一个的赋值。
或者你需要取一个嵌套结构数据的某个值,也许你得遍历整个结构。
如果你能把数据解构成一些小小的片段,那获取信息将会更加容易。

对象的解构

1
2
3
4
5
6
7
let node = {
type: "Identifier",
name: "foo"
};
let { type, name } = node;
console.log(type); // "Identifier"
console.log(name); // "foo"

注意: 必须初始化

1
2
3
4
5
6
// syntax error!
var { type, name };
// syntax error!
let { type, name };
// syntax error!
const { type, name };

解构赋值

可以赋值给已经定义过的变量:

1
2
3
4
5
6
7
8
9
10
let node = {
type: "Identifier",
name: "foo"
},
type = "Literal",
name = 5;
// assign different values using destructuring
({ type, name } = node);
console.log(type); // "Identifier"
console.log(name); // "foo"

默认值

1
2
3
4
5
6
7
8
let node = {
type: "Identifier",
name: "foo"
};
let { type, name, value = true } = node;
console.log(type); // "Identifier"
console.log(name); // "foo"
console.log(value); // true

给不同名本地变量赋值

1
2
3
4
5
6
7
let node = {
type: "Identifier",
name: "foo"
};
let { type: localType, name: localName } = node;
console.log(localType); // "Identifier"
console.log(localName); // "foo"

嵌套对象解构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let node = {
type: "Identifier",
name: "foo",
loc: {
start: {
line: 1,
column: 1
},
end: {
line: 1,
column: 4
}
}
};
let { loc: { start }} = node;
console.log(start.line); // 1
console.log(start.column); // 1

数组的解构

1
2
3
4
let colors = [ "red", "green", "blue" ];
let [ firstColor, secondColor ] = colors;
console.log(firstColor); // "red"
console.log(secondColor); // "green"

只取你需要的部分

1
2
3
let colors = [ "red", "green", "blue" ];
let [ , , thirdColor ] = colors;
console.log(thirdColor); // "blue"

注意: 和对象的解构一样,必须初始化

解构赋值

可以赋值给已经定义过的变量:

1
2
3
4
5
6
let colors = [ "red", "green", "blue" ],
firstColor = "black",
secondColor = "purple";
[ firstColor, secondColor ] = colors;
console.log(firstColor); // "red"
console.log(secondColor); // "green"

在ECMAScript 5 中交换变量值

1
2
3
4
5
6
7
let a = 1,
b = 2, tmp;
tmp = a;
a = b;
b = tmp;
console.log(a); // 2
console.log(b); // 1

在ECMAScript 6 中交换变量值

1
2
3
4
5
let a = 1,
b = 2;
[ a, b ] = [ b, a ];
console.log(a); // 2
console.log(b); // 1

默认值

1
2
3
4
let colors = [ "red" ];
let [ firstColor, secondColor = "green" ] = colors;
console.log(firstColor); // "red"
console.log(secondColor); // "green"

嵌套数组解构

1
2
3
4
5
let colors = [ "red", [ "green", "lightgreen" ], "blue" ];
// later
let [ firstColor, [ secondColor ] ] = colors;
console.log(firstColor); // "red"
console.log(secondColor); // "green"

剩余的元素

1
2
3
4
5
6
let colors = [ "red", "green", "blue" ];
let [ firstColor, ...restColors ] = colors;
console.log(firstColor); // "red"
console.log(restColors.length); // 2
console.log(restColors[0]); // "green"
console.log(restColors[1]); // "blue"

数组的第一个值赋给了firstColor,剩下的值组成了一个新的数组赋给了restColors。

ECMAScript 5克隆一个数组:

1
2
3
var colors = [ "red", "green", "blue" ];
var clonedColors = colors.concat();
console.log(clonedColors); // "[red,green,blue]"

ECMAScript 6克隆一个数组:

1
2
3
let colors = [ "red", "green", "blue" ];
let [ ...clonedColors ] = colors;
console.log(clonedColors); // "[red,green,blue]"

注意: 剩余的元素必须是解构数组的最后一个元素,后面不能有逗号。

混合解构

对象与数组嵌套混合的解构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let node = {
type: "Identifier",
name: "foo",
loc: {
start: {
line: 1,
column: 1 },
end: {
line: 1,
column: 4 }
},
range: [0, 3]
};
let {
loc: { start },
range: [ startIndex ]
} = node;
console.log(start.line); // 1
console.log(start.column); // 1
console.log(startIndex); // 0

参数解构

1
2
3
4
5
6
7
function setCookie(name, value, { secure, path, domain, expires }) {
// code to set the cookie
}
setCookie("type", "js", {
secure: true,
expires: 60000
});

解构的参数是必需的

1
2
// error!
setCookie("type", "js");

它实际上是这样运行的:

1
2
3
4
function setCookie(name, value, options) {
let { secure, path, domain, expires } = options;
// code to set the cookie
}

当解构赋值的右边是null或者undefined,就会抛出错误。

如果你希望解构参数是可选的,你可以这样写:

1
2
function setCookie(name, value, { secure, path, domain, expires } = {}) {
// empty }

解构参数的默认值

1
2
3
4
5
6
7
8
function setCookie(name, value,
{
secure = false,
path = "/",
domain = "example.com",
expires = new Date(Date.now() + 360000000)
} = {} ){
// empty }
Emily's blog

node连接mysql数据库实例

发表于 2016-11-18 |

Express生成应用

首先假定你已经安装了Node.js,接下来通过应用生成器工具 express 可以快速创建一个应用的骨架。
通过如下命令安装express和express-generator:

1
2
$ npm install express -g
$ npm install express-generator -g

当前工作目录下创建一个命名为 myapp 的应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ express myapp
create : myapp
create : myapp/package.json
create : myapp/app.js
create : myapp/public
create : myapp/public/javascripts
create : myapp/public/images
create : myapp/routes
create : myapp/routes/index.js
create : myapp/routes/users.js
create : myapp/public/stylesheets
create : myapp/public/stylesheets/style.css
create : myapp/views
create : myapp/views/index.jade
create : myapp/views/layout.jade
create : myapp/views/error.jade
create : myapp/bin
create : myapp/bin/www

然后安装所有依赖包:

1
2
$ cd myapp
$ npm install

启动这个应用(MacOS 或 Linux 平台):

1
$ DEBUG=myapp npm start

Windows 平台使用如下命令:

1
> set DEBUG=myapp & npm start

然后在浏览器中打开 http://localhost:3000/ 网址就可以看到这个应用了。
通过 Express 应用生成器创建的应用一般都有如下目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.
├── app.js
├── bin
│ └── www
├── package.json
├── public
│ ├── images
│ ├── javascripts
│ └── stylesheets
│ └── style.css
├── routes
│ ├── index.js
│ └── users.js
└── views
├── error.jade
├── index.jade
└── layout.jade
7 directories, 9 files

MySQL数据库

连接本地数据库

安装navicat和MySQL。
进入【系统偏好设置】启动本地mysql服务:
run mysql
在navicat中连接本地数据库:
connect mysql

创建数据库

创建一个测试数据库nodesample,在数据库中建一个userinfo表

1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE DATABASE IF NOT EXISTS nodesample CHARACTER SET UTF8;
USE nodesample;
SET FOREIGN_KEY_CHECKS=0;
DROP TABLE IF EXISTS `userinfo`;
CREATE TABLE `userinfo` (
`Id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`UserName` varchar(64) NOT NULL COMMENT '用户名',
`UserPass` varchar(64) NOT NULL COMMENT '用户密码',
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户信息表';

node连接数据库

Node.js与MySQL交互操作有很多库,这里选择felixge/node-mysql。
安装mysql模块

1
$ npm install mysql --save

打开routes/users.js,引入mysql模块

1
var mysql = require('mysql');

建立连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var connection = mysql.createConnection({
host: '127.0.0.1',
user: 'root',
password: '123',
port: '3306',
database: 'nodesample'
});
connection.connect(function(err){
if(!err) {
console.log("Database is connected ... nn");
} else {
console.log("Error connecting database ... nn");
}
});

实现RESTFUL接口

  1. 增

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /*
    * PUT to updateuser.
    */
    router.put('/updateuser/:id', function(req, res) {
    var userUpSql = 'UPDATE userinfo SET ? WHERE Id='+req.params.id;
    connection.query(userUpSql, req.body, function(err, result) {
    res.send(
    (err === null) ? { msg: '' } : { msg: err }
    );
    });
    });
  2. 删

    1
    2
    3
    4
    5
    6
    7
    8
    9
    /*
    * DELETE to deleteuser.
    */
    router.delete('/deleteuser/:id', function(req, res) {
    var userDelSql = 'DELETE FROM userinfo where Id='+req.params.id;
    connection.query(userDelSql, function (err, result) {
    res.send((err === null) ? { msg: '' } : { msg:'error: ' + err });
    });
    });
  3. 改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /*
    * POST to adduser.
    */
    router.post('/adduser', function(req, res) {
    connection.query('INSERT INTO userinfo SET ?', req.body, function(err, result) {
    res.send(
    (err === null) ? { msg: '' } : { msg: err }
    );
    });
    });
  4. 查

    1
    2
    3
    4
    5
    6
    7
    8
    9
    /* GET users listing. */
    router.get("/userlist",function(req,res){
    connection.query('SELECT * from userinfo', function(err, rows, fields) {
    if (!err)
    res.json(rows);
    else
    console.log('Error while performing Query.');
    });
    });

画页面

在public/javascripts中新建global.js,并打开views/layout.jade,
在末尾引入jquery和global.js。

1
2
script(src='http://cdn.bootcss.com/jquery/1.11.1/jquery.min.js')
script(src='/javascripts/global.js')

打开views/index.jade,写好页面结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
extends layout
block content
// Wrapper
#wrapper
// USER INFO
#userInfo
h2 User Info
p
strong Name:
| <span id='UserName'></span>
br
strong Pass:
| <span id='UserPass'></span>
// /USER INFO
// USER LIST
h2 User List
#userList
table
thead
th UserName
th UserPass
th Delete?
th Edit?
tbody
// /USER LIST
// ADD USER
h2 Add User
#addUser
fieldset
input#inputUserName(type='text', placeholder='Username')
input#inputUserPass(type='text', placeholder='UserPass')
br
button#btnAddUser Add User
// /ADD USER
.mask
#upUser.alert
fieldset
input#modId(type='hidden')
input#modUserName(type='text', placeholder='Username')
input#modUserPass(type='text', placeholder='UserPass')
br
button#btnModUser Modify User

样式写在public/stylesheets/style.css里,可以看我放到github上的源码。

调用接口

在上面新建的global.js里编写调用接口的代码

  1. 查数据并画表格

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function populateTable() {
    var tableContent = '';
    $.getJSON( '/users/userlist', function( data ) {
    userListData = data;
    $.each(data, function(){
    tableContent += '<tr>';
    tableContent += '<td><a href="#" class="linkshowuser" rel="' + this.UserName + '" title="Show Details">' + this.UserName + '</a></td>';
    tableContent += '<td>' + this.UserPass + '</td>';
    tableContent += '<td><a href="#" class="linkdeleteuser" rel="' + this.Id + '">delete</a></td>';
    tableContent += '<td><a href="#" class="linkupdateuser" rel="' + this.Id + '">edit</a></td>';
    tableContent += '</tr>';
    });
    $('#userList table tbody').html(tableContent);
    });
    };
  2. 增

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    function addUser(event) {
    event.preventDefault();
    // 每个输入框必填
    var errorCount = 0;
    $('#addUser input').each(function(index, val) {
    if($(this).val() === '') { errorCount++; }
    });
    if(errorCount === 0) {
    var newUser = {
    'UserName': $('#addUser fieldset input#inputUserName').val(),
    'UserPass': $('#addUser fieldset input#inputUserPass').val()
    };
    $.ajax({
    type: 'POST',
    url: '/users/adduser',
    data: newUser,
    dataType: 'JSON'
    }).done(function( response ) {
    if (response.msg === '') {
    // Clear the form inputs
    $('#addUser fieldset input').val('');
    // Update the table
    populateTable();
    }
    else {
    alert('Error: ' + response.msg);
    }
    });
    }
    else {
    alert('Please fill in all fields');
    return false;
    }
    };
  3. 删

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    function deleteUser(event) {
    event.preventDefault();
    // 确定删除吗
    var confirmation = confirm('Are you sure you want to delete this user?');
    if (confirmation === true) {
    $.ajax({
    type: 'DELETE',
    url: '/users/deleteuser/' + $(this).attr('rel')
    }).done(function( response ) {
    if (response.msg === '') {
    }
    else {
    alert('Error: ' + response.msg);
    }
    populateTable();
    });
    }
    else {
    return false;
    }
    };
  4. 改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    function updateUser(event) {
    event.preventDefault();
    // 每个输入框必填
    var errorCount = 0;
    $('#upUser input').each(function(index, val) {
    if($(this).val() === '') { errorCount++; }
    });
    if(errorCount === 0) {
    var upUser = {
    'UserName': $('#upUser fieldset input#modUserName').val(),
    'UserPass': $('#upUser fieldset input#modUserPass').val()
    };
    $.ajax({
    type: 'PUT',
    url: '/users/updateuser/' + $('#upUser fieldset input#modId').val(),
    data: upUser,
    dataType: 'JSON'
    }).done(function( response ) {
    if (response.msg === '') {
    $('.mask').hide();
    $('.alert').hide();
    populateTable();
    }
    else {
    alert('Error: ' + response.msg);
    }
    });
    }
    else {
    return false;
    }
    };

完整的代码可以去github上查看,以下是最终效果:
final view

参考文章

express

用NODE.JS,EXPRESS,MONGODB创建一个简单的RESTFUL WEB APP

express中文网

mysql与node

Nodejs学习笔记(四)与MySQL交互(felixge/node-mysql)

Node.js and MySQL tutorial

Emily's blog

JS中Math.random()的使用和扩展

发表于 2016-09-21 | 分类于 学习笔记 |

Math.random()方法返回大于等于 0 小于 1 的一个随机数。对于某些站点来说,这个方法非常实用,因为可以利用它来随机显示一些名人名言和新闻事件。

在连续整数中取得一个随机数

1
值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)

例:产生1-10的随机数

1
var rand1 = Math.floor(Math.random() * 10 + 1);

编写产生startNumber至endNumber随机数的函数

1
2
3
4
5
function selectFrom(startNumber, endNumber) {
var choice = endNumber - startNumber + 1;
return Math.floor(Math.random() * choice + startNumber)
}
var rand2 = selectFrom(2,8);//产生2至8的随机数

在不相邻整数中取得一个随机数

在不相邻的两个整数中取得一个随机数

例:随机产生2或4中的一个数

1
var rand3 = Math.random() < 0.5 ? 2 : 4;

在不相邻的多个整数中产生一个随机数

结合函数参数数组,可编写在不相邻的多个整数中产生一个随机值的函数

1
2
3
4
5
6
7
8
function selectFromMess() {
return arguments[Math.floor(Math.random() * arguments.length)]
}
//随机产生1、6、8中的一个数
var rand4 = selectFromMess(1, 6, 8);
//也可随机产生文本
var randomTxt1 = selectFromMess("安慰奖", "二等奖", "一等奖");

每次要输入这么多参数比较麻烦,可以改写一下函数

1
2
3
4
5
function selectFromMessArray(arr) {
return arr[Math.floor(Math.random() * arr.length)]
}
var arrayTxt=["一","二","三","四","五"];
var randTxt2 = selectFromMessArray(arrayTxt);

或者不改变原有方法,可以利用apply()这个方法传递数组参数

1
var randTxt3 = selectFromMess.apply(null,arrayTxt);

关于apply方法的使用可以看这里

Emily's blog

将本地仓库提交到github上

发表于 2016-09-19 |
  1. 先在github上新建一个仓库,取名,例test

  2. 本地新建文件夹

  3. 打开命令行工具cd进这个文件夹

  4. 执行git init,执行后会在该文件夹下生成一个名为.git的文件夹,里面有有关git的配置

  5. 关联到远程仓库
    git remote add origin https://YehanZhou@github.com/YehanZhou/test.git

  6. 添加所有文件到暂存区
    git add .

  7. 提交
    git commit -m "description"

  8. 推送
    git push -u origin master

Emily's blog

hexo命令

发表于 2016-09-18 | 分类于 学习笔记 |

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

Emily Zhou

Emily Zhou

7 日志
2 分类
8 标签
RSS
GitHub Email
© 2017 Emily Zhou
由 Hexo 强力驱动
主题 - NexT.Pisces