liziyu 发布的文章

# Virtual hosts
Include /Applications/MAMP/conf/apache/extra/httpd-vhosts.conf

<VirtualHost *:80>
    DocumentRoot "/Users/liziyu/website/xfcms_base/public"
    ServerName xfcms-base.local
    Options Indexes FollowSymLinks
    <Directory />
        AllowOverride All
        Order Deny,Allow
        Deny from all
        Allow from 127.0.0.1
    </Directory>
</VirtualHost>


PKprimary key 主键
NNnot null 非空
UQunique 唯一索引
BINbinary 二进制数据(比text更大的二进制数据)
UNunsigned 无符号 整数(非负数)
ZFzero fill 填充0 例如字段内容是1 int(4), 则内容显示为0001
AIauto increment 自增
Ggenerated column 生成列

在mysql查询语句中加\g、\G的意思:

\g 的作用是分号和在sql语句中写“;”是等效的
\G 的作用是将查到的结构旋转90度变成纵向(换行打印)

1位=1比特;

1字节=8位;

1字=2字节;

1字=16位。

1、位

位是计算机存储的最小单位,简记为b,也称为比特(bit)计算机中用二进制中的0和1来表示数据,一个0或1就代表一位。位数通常指计算机中一次能处理的数据大小;

2、比特

比特(bit)是由英文BIT音译而来,比特同时也是二进制数字中的位,是信息量的度量单位,为信息量的最小单位;

3、字节

字节,英文Byte,是计算机用于计量存储容量的一种计量单位,通常情况下一字节等于八位,字节同时也在一些计算机编程语言中表示数据类型和语言字符,在现代计算机中,一个字节等于八位;

4、字

字是表示计算机自然数据单位的术语,在某个特定计算机中,字是其用来一次性处理事务的一个固定长度的位(bit)组,在现代计算机中,一个字等于两个字节。

一、先给定义:

什么是大端?什么是小端?
主要针对的是CPU向内存写入数据的两种方式:

大端序:将高位字节保存在内存的低地址(高位字节在前)的方式。
小端序:将高位字节保存在内在存的高地址(低位字节在前)的方式。

二、下面引入详细说明:

假设在 0x20 号开始的地址中保存4字节 int 型数据 0x12345678,大端序CPU保存方式如下图所示:
1.png
上图1:整数 0x12345678 的大端序字节表示。
比如说1在高位就是高位字节,相反8就在低位是低位字节

对于大端序,最高位字节 0x12 存放到低位地址,最低位字节 0x78 存放到高位地址。小端序的保存方式如下图所示:
2.png
上图2:整数 0x12345678 的小端序字节表示。
比如说1在高位就是高位字节,相反8就在低位是低位字节

不同CPU保存和解析数据的方式不同(主流的Intel系列CPU为小端序),小端序系统和大端序系统通信时会发生数据解析错误。因此在发送数据前,要将数据转换为统一的格式——网络字节序(Network Byte Order)。网络字节序统一为大端序。主机A先把数据转换成大端序再进行网络传输,主机B收到数据后先转换为自己的格式再解析。网络字节序转换函数
sockaddr_in 结构体,其中就用到了网络字节序转换函数,如下所示:

//创建sockaddr_in结构体变量
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
serv_addr.sin_port = htons(1234); //端口号

htons() 用来将当前主机字节序转换为网络字节序,其中
h代表主机(host)字节序,
n代表网络(network)字节序,
s代表shorthtonsh、to、n、s 的组合,可以理解为”将short型数据从当前主机字节序转换为网络字节序“。常见的网络字节转换函数有:htons()host to network short,将short类型数据从主机字节序转换为网络字节序。
ntohs():network to host short,将short类型数据从网络字节序转换为主机字节序。
htonl():host to network long,将long类型数据从主机字节序转换为网络字节序。
ntohl():network to host long,将long类型数据从网络字节序转换为主机字节序。

通常,以s为后缀的函数中,s代表2个字节short,因此用于端口号转换;以l为后缀的函数中,l代表4个字节的long,因此用于IP地址转换。举例说明上述函数的调用过程:

#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
int main(){
unsigned short host_port = 0x1234, net_port;
unsigned long host_addr = 0x12345678, net_addr;

net_port = htons(host_port);
net_addr = htonl(host_addr);

printf("Host ordered port: %#x\n", host_port);
printf("Network ordered port: %#x\n", net_port);
printf("Host ordered address: %#lx\n", host_addr);
printf("Network ordered address: %#lx\n", net_addr);
system("pause");
return 0;
}

运行结果:

Host ordered port: 0x1234
Network ordered port: 0x3412
Host ordered address: 0x12345678
Network ordered address: 0x78563412

另外需要说明的是,sockaddr_in 中保存IP地址的成员为32位整数,而我们熟悉的是点分十进制表示法,例如 127.0.0.1,它是一个字符串,因此为了分配IP地址,需要将字符串转换为4字节整数。inet_addr() 函数可以完成这种转换。inet_addr() 除了将字符串转换为32位整数,同时还进行网络字节序转换。请看下面的代码:

#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")

int main(){
char *addr1 = "1.2.3.4";
char *addr2 = "1.2.3.256";

unsigned long conv_addr = inet_addr(addr1);
if(conv_addr == INADDR_NONE){
puts("Error occured!");
}else{
printf("Network ordered integer addr: %#lx\n", conv_addr);
}

conv_addr = inet_addr(addr2);
if(conv_addr == INADDR_NONE){
puts("Error occured!");
}else{
printf("Network ordered integer addr: %#lx\n", conv_addr);
}

system("pause");
return 0;
}

运行结果:
Network ordered integer addr: 0x4030201

Error occured!从运行结果可以看出,inet_addr() 不仅可以把IP地址转换为32位整数,还可以检测无效IP地址。注意:为 sockaddr_in 成员赋值时需要显式地将主机字节序转换为网络字节序,而通过 write()/send() 发送数据时TCP协议会自动转换为网络字节序,不需要再调用相应的函数。

本文摘自:https://www.jianshu.com/p/68735394db7a

不能将箭头函数用于定义对象的方法且内含有this

const cat = {
  lives: 9,
  jumps: () => {
    this.lives--;
  }
}

调用cat.jumps()时,如果是普通函数,该方法内部的this指向cat;如果写成上面那样的箭头函数,使得this指向全局对象,因此不会得到预期结果。这是因为对象不构成单独的作用域,导致jumps箭头函数定义时的作用域就是全局作用域。

关键问题是:对象不构成单独的作用域。

// 正确的写法
let x;
({x} = {x: 1});


// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error

  1. 当线程创建的时候,操作系统(OS)为每一个系统级(system-level)的线程分配栈。通常情况下,操作系统通过调用语言的运行时(runtime)去为应用程序分配堆。
  2. 栈附属于线程,因此当线程结束时栈被回收。堆通常通过运行时在应用程序启动时被分配,当应用程序(进程)退出时被回收。
  3. 当线程被创建的时候,设置栈的大小。在应用程序启动的时候,设置堆的大小,但是可以在需要的时候扩展(分配器向操作系统申请更多的内存)。
  4. 栈比堆要快,因为它存取模式使它可以轻松的分配和重新分配内存(指针/整型只是进行简单的递增或者递减运算),然而堆在分配和释放的时候有更多的复杂的 bookkeeping 参与。另外,在栈上的每个字节频繁的被复用也就意味着它可能映射到处理器缓存中,所以很快。

栈【Stack】:

a.和堆一样存储在计算机 RAM 中。
b.在栈上创建变量的时候会扩展,并且会自动回收。
c.相比堆而言在栈上分配要快的多。
d.用数据结构中的栈实现。
e.存储局部数据,返回地址,用做参数传递。
f.当用栈过多时可导致栈溢出(无穷次(大量的)的递归调用,或者大量的内存分配)。
g.在栈上的数据可以直接访问(不是非要使用指针访问)。
h.如果你在编译之前精确的知道你需要分配数据的大小并且不是太大的时候,可以使用栈。
i.当你程序启动时决定栈的容量上限。

堆【Heap】:

a.和栈一样存储在计算机RAM。
b.在堆上的变量必须要手动释放,不存在作用域的问题。数据可用 delete, delete[] 或者 free 来释放。
c.相比在栈上分配内存要慢。
d.通过程序按需分配。
e.大量的分配和释放可造成内存碎片。
f.在 C++ 中,在堆上创建数的据使用指针访问,用 new 或者 malloc 分配内存。
g.如果申请的缓冲区过大的话,可能申请失败。
h.在运行期间你不知道会需要多大的数据或者你需要分配大量的内存的时候,建议你使用堆。
i.可能造成内存泄露。