0%

一.什么是 REST?

REST即表述性状态传递(英文:Representational State Transfer,简称REST)是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。

表述性状态转移是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是RESTful。需要注意的是,REST是设计风格而不是标准。REST通常基于使用HTTP,URI,和XML(标准通用标记语言下的一个子集)以及HTML(标准通用标记语言下的一个应用)这些现有的广泛流行的协议和标准。REST 通常使用 JSON 数据格式。

二.HTTP 方法

以下为 REST 基本架构的四个方法:

  1. GET - 用于获取数据。
  2. PUT - 用于添加数据。
  3. DELETE - 用于删除数据。
  4. POST - 用于更新或添加数据。

三.RESTful Web Services

Web service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的互操作的应用程序。

基于 REST 架构的 Web Services 即是 RESTful。

由于轻量级以及通过 HTTP 直接传输数据的特性,Web 服务的 RESTful 方法已经成为最常见的替代方法。可以使用各种语言(比如 Java 程序、Perl、Ruby、Python、PHP 和 Javascript[包括 Ajax])实现客户端。

RESTful Web 服务通常可以通过自动客户端或代表用户的应用程序访问。但是,这种服务的简便性让用户能够与之直接交互,使用它们的 Web 浏览器构建一个 GET URL 并读取返回的内容。

首先,创建一个 json 数据资源文件 users.json,内容如下:

{
   "user1" : {
   "name" : "mahesh",
   "password" : "password1",
   "profession" : "teacher",
   "id": 1
},
"user2" : {
   "name" : "suresh",
   "password" : "password2",
   "profession" : "librarian",
   "id": 2
},
"user3" : {
   "name" : "ramesh",
   "password" : "password3",
   "profession" : "clerk",
   "id": 3
   }
}

获取用户列表:

以下代码,我们创建了 RESTful API listUsers,用于读取用户的信息列表, server.js 文件代码如下所示:

var express = require('express');
var app = express();
var fs = require("fs");

app.get('/listUsers', function (req, res) {
    fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
       console.log( data );
       res.end( data );
   });
})

var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port

  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

接下来执行以下命令:

$ node server.js 
应用实例,访问地址为 http://0.0.0.0:8081

在浏览器中访问 http://127.0.0.1:8081/listUsers,结果如下所示:

{
   "user1" : {
   "name" : "mahesh",
   "password" : "password1",
   "profession" : "teacher",
   "id": 1
},
"user2" : {
   "name" : "suresh",
   "password" : "password2",
   "profession" : "librarian",
   "id": 2
},
"user3" : {
   "name" : "ramesh",
   "password" : "password3",
   "profession" : "clerk",
   "id": 3
}
}

添加用户

以下代码,我们创建了 RESTful API addUser, 用于添加新的用户数据,server.js 文件代码如下所示:

var express = require('express');
var app = express();
var fs = require("fs");

//添加的新用户数据
var user = {
  "user4" : {
  "name" : "mohit",
  "password" : "password4",
  "profession" : "teacher",
  "id": 4
 }
}

app.get('/addUser', function (req, res) {
// 读取已存在的数据
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
   data = JSON.parse( data );
   data["user4"] = user["user4"];
   console.log( data );
   res.end( JSON.stringify(data));
});
})

var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port
  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

接下来执行以下命令:

$ node server.js 
 应用实例,访问地址为 http://0.0.0.0:8081

在浏览器中访问 http://127.0.0.1:8081/addUser,结果如下所示:

{ user1:
   { name: 'mahesh',
     password: 'password1',
     profession: 'teacher',
     id: 1 },
  user2:
   { name: 'suresh',
     password: 'password2',
     profession: 'librarian',
     id: 2 },
  user3:
   { name: 'ramesh',
     password: 'password3',
     profession: 'clerk',
     id: 3 },
  user4:
       { name: 'mohit',
     password: 'password4',
     profession: 'teacher',
     id: 4 } 
}

显示用户详情

以下代码,我们创建了 RESTful API :id(用户id), 用于读取指定用户的详细信息,server.js 文件代码如下所示:

var express = require('express');
var app = express();
var fs = require("fs");

app.get('/:id', function (req, res) {
// 首先我们读取已存在的用户
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
   data = JSON.parse( data );
   var user = data["user" + req.params.id] 
   console.log( user );
   res.end( JSON.stringify(user));
 });
})

var server = app.listen(8081, function () {

   var host = server.address().address
   var port = server.address().port
   console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

接下来执行以下命令:

$ node server.js 
应用实例,访问地址为 http://0.0.0.0:8081

在浏览器中访问 http://127.0.0.1:8081/2,结果如下所示:

{
   "name":"suresh",
   "password":"password2",
   "profession":"librarian",
   "id":2
}

删除用户

以下代码,我们创建了 RESTful API deleteUser, 用于删除指定用户的详细信息,以下实例中,用户 id 为 2,server.js 文件代码如下所示:

var express = require('express');
var app = express();
var fs = require("fs");

var id = 2;

app.get('/deleteUser', function (req, res) {

   // First read existing users.
   fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
       data = JSON.parse( data );
       delete data["user" + 2];
   
       console.log( data );
       res.end( JSON.stringify(data));
   });
})

var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port
  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

接下来执行以下命令:

$ node server.js 
应用实例,访问地址为 http://0.0.0.0:8081

在浏览器中访问 http://127.0.0.1:8081/deleteUser,结果如下所示:

{ user1:
   { name: 'mahesh',
     password: 'password1',
     profession: 'teacher',
     id: 1 },
  user3:
   { name: 'ramesh',
     password: 'password3',
     profession: 'clerk',
     id: 3 } 
}

注意:

  1. Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。

  2. Node.js里面的许多对象都会分发事件:一个net.Server对象会在每次有新连接时分发一个事件, 一个fs.readStream对象会在文件被打开的时候发出一个事件。 所有这些产生事件的对象都是 events.EventEmitter 的实例。


一.EventEmitter类

events 模块只提供了一个对象: events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装。可以通过require(“events”);来访问该模块。

// 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();

EventEmitter 对象如果在实例化时发生错误,会触发 ‘error’ 事件。当添加新的监听器时,’newListener’ 事件会触发,当监听器被移除时,’removeListener’ 事件被触发。

二.EventEmitter 的用法:

//event.js 文件
var EventEmitter = require('events').EventEmitter; 
var event = new EventEmitter(); 
event.on('some_event', function() { 
    console.log('some_event 事件触发'); 
}); 
setTimeout(function() { 
    event.emit('some_event'); 
}, 1000); 

执行结果如下:
运行这段代码,1 秒后控制台输出了 ‘some_event 事件触发’。其原理是 event 对象注册了事件 some_event 的一个监听器,然后我们通过 setTimeout 在 1000 毫秒以后向 event 对象发送事件 some_event,此时会调用some_event 的监听器。

$ node event.js 
some_event 事件触发

EventEmitter 的每个事件由一个事件名和若干个参数组成,事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter 支持 若干个事件监听器。

当事件触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。
让我们以下面的例子解释这个过程:

//event.js 文件
var events = require('events'); 
var emitter = new events.EventEmitter(); 
emitter.on('someEvent', function(arg1, arg2) { 
    console.log('listener1', arg1, arg2); 
}); 
emitter.on('someEvent', function(arg1, arg2) { 
    console.log('listener2', arg1, arg2); 
}); 
emitter.emit('someEvent', 'arg1 参数', 'arg2 参数'); 

执行以上代码,运行的结果如下:

$ node event.js 
listener1 arg1 参数 arg2 参数
listener2 arg1 参数 arg2 参数

以上例子中,emitter 为事件 someEvent 注册了两个事件监听器,然后触发了 someEvent 事件。
运行结果中可以看到两个事件监听器回调函数被先后调用。 这就是EventEmitter最简单的用法。

三.EventEmitter 的属性

EventEmitter 提供了多个属性,如 on 和 emit。on 函数用于绑定事件函数,emit 属性用于触发一个事件。接下来我们来具体看下 EventEmitter 的属性介绍。

  1. addListener(event, listener)
    为指定事件添加一个监听器到监听器数组的尾部。

  2. on(event, listener)
    为指定事件注册一个监听器,接受一个字符串 event 和一个回调函数。

     erver.on('connection', function (stream) {
         console.('someone connected!');
     });
    
  3. once(event, listener)
    为指定事件注册一个单次监听器,即 监听器最多只会触发一次,触发后立刻解除该监听器。

     server.once('connection', function (stream){
         console.log('Ah, we have our first user!');
     });
    
  4. removeListener(event, listener)
    移除指定事件的某个监听器,监听器 必须是该事件已经注册过的监听器。

     var callback = function(stream) {
            console.log('someone connected!');
     };
     server.on('connection', callback);
     // ...
     server.removeListener('connection', callback);
    
  5. removeAllListeners([event])
    移除所有事件的所有监听器, 如果指定事件,则移除指定事件的所有监听器。

  6. setMaxListeners(n)
    默认情况下, EventEmitters 如果你添加的监听器超过 10 个就会输出警告信息。 setMaxListeners 函数用于提高监听器的默认限制的数量。

  7. listeners(event)
    返回指定事件的监听器数组。

  8. emit(event, [arg1], [arg2], […])
    按参数的顺序执行每个监听器,如果事件有注册监听返回 true,否则返回 false。

四.继承 EventEmitter

  • 大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。
  • 为什么要这样做呢?原因有两点:
    首先,具有某个实体功能的对象实现事件符合语义, 事件的监听和发射应该是一个对象的方法。
    其次 JavaScript 的对象机制是基于原型的,支持 部分多重继承,继承 EventEmitter 不会打乱对象原有的继承关系。

Node.js内置的fs模块就是文件系统模块,负责读写文件。和所有其它JavaScript模块不同的是,fs模块同时提供了异步和同步的方法。

一.同步读文件

  1. 创建一个文件 input.txt ,内容如下:

     你好,我是于禤。
         Hello!my name is yuxuan.
    
  2. 创建 main.js 文件, 代码如下:

     var fs = require("fs");
    
         var data = fs.readFileSync('input.txt');
    
         console.log(data.toString());
         console.log("程序执行结束!");
    
  3. 以上代码执行结果如下:

     $ node main.js
     
      你好,我是于禤。
         Hello!my name is yuxuan.
         程序执行结束!
    

    二.异步读文件

  4. 创建一个文件 input.txt ,内容如下:

     你好,我是于禤。
            Hello!my name is yuxuan.
    
  5. 创建 main.js 文件, 代码如下:

     var fs = require("fs");
    
         fs.readFile('input.txt', function (err, data) {
         if (err) return console.error(err);
         console.log(data.toString());
         });
    
         console.log("程序执行结束!");
    
  6. 以上代码执行结果如下:

      程序执行结束!
           你好,我是于禤。
         Hello!my name is yuxuan.
    

    三.写文件(fs.writeFile())

  7. 创建一个空文件 output.txt

  8. 创建 main.js 文件, 代码如下:

     var fs = require('fs');
    
         var data = 'Hello, Node.js';
         fs.writeFile('output.txt', data, function (err) {
         if (err) {
             console.log(err);
         } else {
             console.log('ok.');
         }
         });
    
  9. 执行结果:空文件 output.txt里的内容变为Hello, Node.js。
    writeFile()的参数依次为文件名、数据和回调函数。如果传入的数据是String,默认按UTF-8编码写入文本文件,如果传入的参数是Buffer,则写入的是二进制文件。回调函数由于只关心成功与否,因此只需要一个err参数。

  10. 和readFile()类似,writeFile()也有一个同步方法,叫writeFileSync():

     var fs = require('fs');
         var data = 'Hello, Node.js';
         fs.writeFileSync('output.txt', data);
    

四.获取文件的详细信息(fs.stat())

  1. 创建一个文件 input.txt ,内容如下:

     你好,我是于禤。
         Hello!my name is yuxuan.
    
  2. 创建 main.js 文件, 代码如下:

     var fs = require('fs');
    
         fs.stat('input.txt', function (err, stat) {
         if (err) {
         console.log(err);
         } else {
         // 是否是文件:
         console.log('isFile: ' + stat.isFile());
         // 是否是目录:
         console.log('isDirectory: ' + stat.isDirectory());
         if (stat.isFile()) {
             // 文件大小:
             console.log('size: ' + stat.size);
             // 创建时间, Date对象:
             console.log('birth time: ' + stat.birthtime);
             // 修改时间, Date对象:
             console.log('modified time: ' + stat.mtime);
             }
      }
         });
    
  3. 运行结果如下:

     isFile: true
         isDirectory: false
         size: 51
         birth time: Thu Oct 20 2016 13:40:21 GMT+0800 (中国标准时间)
         modified time: Thu Oct 20 2016 14:04:41 GMT+0800 (中国标准时间)
    

最近在学习Node.js的基本模块,现用Node.js实现一个HTTP服务器程序

注意:

  1. 要开发HTTP服务器程序,从头处理TCP连接,解析HTTP是不现实的。这些工作实际上已经由Node.js自带的http模块完成了。应用程序并不直接和HTTP协议打交道,而是操作http模块提供的request和response对象。

  2. request对象封装了HTTP请求,我们调用request对象的属性和方法就可以拿到所有HTTP请求的信息;

  3. response对象封装了HTTP响应,我们操作response对象的方法,就可以把HTTP响应返回给浏览器。


一.让我们先了解下 Node.js 应用是由哪几部分组成的:

  1. 引入 required 模块:我们可以使用 require 指令来载入 Node.js 模块。

  2. 创建服务器:服务器可以监听客户端的请求,类似于 Apache 、Nginx 等 HTTP 服务器。

  3. **接收请求与响应请求:**服务器很容易创建,客户端可以使用浏览器或终端发送 HTTP 请求,服务器接收请求后返回响应数据。

二.Node.js实现一个HTTP服务器程序的步骤:

1. 引入requried模块:

我们使用 require 指令来载入 http 模块,并将实例化的 HTTP 赋值给变量 http,实例如下:

var http = require("http");

2. 创建服务器,接收请求与响应请求:

接下来我们使用 http.createServer() 方法创建服务器,并使用 listen 方法绑定 8080 端口。 函数通过 request, response 参数来接收和响应数据。实例如下:

// 创建http server,并传入回调函数:
var server = http.createServer(function (request, response) {
      
      // 将HTTP响应200写入response, 同时设置Content-Type: text/html:
      response.writeHead(200, {'Content-Type': 'text/html'});

      // 将HTTP响应的HTML内容写入response:
      response.end('<h1>Hello world!</h1>');
});

// 让服务器监听8080端口:
server.listen(8080,'127.0.0.1');

//// 终端打印如下信息
console.log('Server is running at http://127.0.0.1:8080/');

3. 在命令提示符下运行该程序,可以看到以下输出:

$ node hello.js 
Server is running at http://127.0.0.1:8080/

4. 不要关闭命令提示符,直接打开浏览器输入http://127.0.0.1:8080,即可看到服务器响应的内容:

Hello world!

三.分析Node.js 的 HTTP 服务器

  • 第一行请求(require)Node.js 自带的 http 模块,并且把它赋值给 http 变量。
  • 接下来我们调用 http 模块提供的函数: createServer 。这个函数会返回 一个对象,这个对象有一个叫做 listen 的方法,这个方法有一个数值参数, 指定这个 HTTP 服务器监听的端口号。

注意:

  1. stream是Node.js提供的又一个仅在服务区端可用的模块,目的是支持“流”这种数据结构。

  2. 什么是流?流是一种抽象的数据结构。想象水流,当在水管中流动时,就可以从某个地方(例如自来水厂)源源不断地到达另一个地方(比如你家的洗手池)。我们也可以把数据看成是数据流,比如你敲键盘的时候,就可以把每个字符依次连起来,看成字符流。这个流是从键盘输入到应用程序,实际上它还对应着一个名字:标准输入流(stdin)。

  3. Node.js,Stream 有四种流类型:

  • Readable - 可读操作。
  • Writable - 可写操作。
  • Duplex - 可读可写操作.
  • Transform - 操作被写入数据,然后读出结果。
  1. 所有的 Stream 对象都是 EventEmitter 的实例。常用的事件有:

    • data - 当有数据可读时触发。
    • end - 没有更多的数据可读时触发。
    • error - 在接收和写入过程中发生错误时触发。
    • finish - 所有数据已被写入到底层系统时触发。

一.从流中读取数据

  1. 创建 input.txt 文件,内容如下:

     hello world !
    
  2. 创建 main.js 文件, 代码如下:

     var fs = require("fs");
         var data = '';
    
         // 创建可读流
         var readerStream = fs.createReadStream('input.txt');
    
         // 设置编码为 utf8。
         readerStream.setEncoding('UTF8');
    
         // 处理流事件 --> data, end, and error
         readerStream.on('data', function(chunk) {
            data += chunk;
           });
    
         readerStream.on('end',function(){
            console.log(data);
         });
    
         readerStream.on('error', function(err){
            console.log(err.stack);
         });
    
            console.log("程序执行完毕");
    
  1. 以上代码执行结果如下:

     程序执行完毕
         hello world !
    

二.写入流

  1. 创建 main.js 文件, 代码如下:

     var fs = require("fs");
         var data = 'hello world !';
    
         // 创建一个可以写入的流,写入到文件 output.txt 中
         var writerStream = fs.createWriteStream('output.txt');
    
         // 使用 utf8 编码写入数据
         writerStream.write(data,'UTF8');
    
         // 标记文件末尾
         writerStream.end();
    
         // 处理流事件 --> data, end, and error
         writerStream.on('finish', function() {
         console.log("写入完成。");
         });
    
         writerStream.on('error', function(err){
            console.log(err.stack);
         });
    
             console.log("程序执行完毕");
    
  2. 以上程序会将 data 变量的数据写入到 output.txt 文件中。代码执行结果如下:

        $ node main.js 
         程序执行完毕
         写入完成。
    
  3. 查看 output.txt 文件的内容:

     $ cat output.txt 
         hello world !
    

三.管道流

管道提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另外一个流中。

以下实例我们通过读取一个文件内容并将内容写入到另外一个文件中。

  1. 设置 input.txt 文件内容如下:

     Hello! my name is yuxuan.
    
  2. 创建 main.js 文件, 代码如下:

     var fs = require("fs");
    
         // 创建一个可读流
         var readerStream = fs.createReadStream('input.txt');
    
         // 创建一个可写流
         var writerStream = fs.createWriteStream('output.txt');
    
         // 管道读写操作
         // 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中
         readerStream.pipe(writerStream);
    
         console.log("程序执行完毕");
    
  3. 代码执行结果如下:

     $ node main.js 
         程序执行完毕
    
  4. 查看 output.txt 文件的内容:

     $ cat output.txt 
         Hello! my name is yuxuan.
    

四.链式流

  • 链式是通过连接输出流到另外一个流并创建多个对个流操作链的机制。链式流一般用于管道操作。
    接下来我们就是用管道和链式来压缩和解压文件。

a. 压缩文件

  1. 创建 compress.js 文件, 代码如下:

     var fs = require("fs");
         var zlib = require('zlib');
    
         // 压缩 input.txt 文件为 input.txt.gz
         fs.createReadStream('input.txt')
         .pipe(zlib.createGzip())
         .pipe(fs.createWriteStream('input.txt.gz'));
     
         console.log("文件压缩完成。");
    
  2. 代码执行结果如下:

     $ node compress.js 
     文件压缩完成。
    
  3. 执行完以上操作后,我们可以看到当前目录下生成了 input.txt 的压缩文件 input.txt.gz。

b. 解压该文件

  1. 创建 decompress.js 文件,代码如下:

     var fs = require("fs");
         var zlib = require('zlib');
    
            // 解压 input.txt.gz 文件为 input.txt
         fs.createReadStream('input.txt.gz')
       .pipe(zlib.createGunzip())
       .pipe(fs.createWriteStream('input.txt'));
    
         console.log("文件解压完成。");
    
  2. 代码执行结果如下:

     $ node decompress.js 
      文件解压完成。
    

学习React时,碰到一些需要注意的地方。现整理如下:

一.关于JSX 语法

React 不是一定要使用 JSX 语法,可以直接使用原生 JS。JSX语法看上去像是在Javascript代码里直接写起了XML标签,实质上这只是一个语法糖,每一个XML标签都会被JSX转换工具转换成纯Javascript代码,所以建议使用 JSX 是因为它能精确定义和反应组件及属性的树状结构,使得组件的结构和组件之间的关系看上去更加清晰。方便MXML和XAML的开发人员 – 因为他们已经使用过类似的语法。

二.HTML 标签 和 React 组件

在JSX语法中,遇到HTML标签(以<开头)就用HTML规则解析,遇到代码块(以{开头)就用JavaScript规则解析。React 可以渲染 HTML 标签 (strings) 或 React 组件 (classes)。

要渲染 HTML 标签,只需在 JSX 里使用小写字母开头的标签名。

 var myDivElement=<div className="foo"/>;

 React.render(myDivElement,document.body);

要渲染 React 模块,只需创建一个大写字母开头的本地变量。

var MyComponent = React.createClass({/*...*/});
var myElement = <MyComponent someProperty={true} />;
React.render(myElement, document.body);
React 的 JSX 里约定分别使用首字母大、小写来区分本地模块的类和 HTML 标签。

三.不建议作为 XML 属性名

由于 JSX 就是 JavaScript,一些标识符像 class 和 for 不建议作为 XML 属性名。作为替代,React DOM 使用 className 和 htmlFor 来做对应的属性。

四.大小写敏感

上面说了JSX是一个XML语法的预处理器。 XML 语法对大小写敏感,所以习惯了HTML的同学要特别注意这点,否则折腾了半天,都不知道错在哪里。比如:

var Events = React.createClass({
    clickHandler: function(){
        console.log('You got me!');
    },
    render: function(){
      return <div onClick={this.clickHandler}>Hello, world!</div>;
    }
});
 
React.render( <Events />,document.body);

这里绑定click事件的onClick中C是大写的。

五.React 注释特点

  1. jsx 标签内容注释

    hello{// 或 /**/}

  2. jsx 标签属性注释 <p name=”123”{// /**/}>123

  3. 其实上面提到的大括号的内容都是js 可以参考求值表达式

六.React Css样式与标签嵌套

  1. 定义方式与定义对象一样。 css的写法少有变化,属性值需要加引号,属性与属性之间使用逗号分隔,而不在是分号例如

    var style={color:”red”, border:”1px #000 solid”}

  2. 样式的引用,React采用style的方式来引用样式;例如

Git是目前世界上最先进的分布式版本控制系统,关于Git的常用命令整理如下:

1.创建版本库

$ mkdir learngit
$ cd learngit
$ pwd
/Users/michael/learngit

2.通过git init命令把这个目录变成Git可以管理的仓库,在新建版本库路径下:

$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/

3.添加文件到Git仓库,分两步:

第一步,用命令git add告诉Git,把文件添加到仓库:

$ git add readme.txt

执行上面的命令,没有任何显示,这就对了,Unix的哲学是“没有消息就是好消息”,说明添加成功。

第二步,用命令git commit告诉Git,把文件提交到仓库:

$ git commit -m "wrote a readme file"
[master (root-commit) cb926e7] wrote a readme file
 1 file changed, 2 insertions(+)
 create mode 100644 readme.txt

4.要随时掌握工作区的状态,使用git status命令。

git diff readme.txt

如果git status告诉你有文件被修改过,可以用git diff readme.txt查看修改内容。

5.版本回退

git log  //显示从最近到最远的提交日志,以便确定要回退到哪个版本,每次提交都有一个唯一的id。

git reflog  //用来记录你的每一次命令,以便确定要回到未来的哪个版本。

把当前版本“append GPL”回退到上一个版本“add distributed”,就可以使用git reset命令:
$ git reset --hard HEAD^
HEAD is now at ea34578 add distributed

返回某个指定id号的那个版本的提交:

$ git reset --hard 3628164

查看readme.txt的内容是不是版本add distributed:

$ cat readme.txt
Git is a distributed version control system.
Git is free software.

git 允许我们将某个特定的文件回滚到特定的提交,使用的也是 git checkout。

例子:将hello.txt回滚到最初的状态,需要指定回滚到哪个提交,以及文件的全路径。

$ git checkout 09bd8cc1 hello.txt

6.撤销修改

git checkout -- file  //丢弃工作区的修改:

$ git checkout -- readme.txt
命令git checkout -- readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:
一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
总之,就是让这个文件回到最近一次git commit或git add时的状态。

git add到暂存区了,git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回工作区,
git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本。

7.删除文件

一种是确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit:

$ git rm test.txt
rm 'test.txt'

$ git commit -m "remove test.txt"
[master d17efd8] remove test.txt
1 file changed, 1 deletion(-)
 
$ delete mode 100644 test.txt
现在,文件就从版本库中被删除了。

另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:

$ git checkout -- test.txt

git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

8.远程仓库

第一种:添加远程库:

  1.mkdir learngit

  2.cd learngit

  3.git init

  4.添加文件

  5.git add .

  6.git commit -m "test"

  7.在github上创建仓库,复制地址

  8. git remote add origin git@github.com:michaelliao/learngit.git

  9.git push -u origin master

注意:

若出错:fatal: refusing to merge unrelated histories

解决:git pull origin master –allow-unrelated-histories

//github仓库中存在本地项目中不存在的文件,发生了冲图,所以应该先将github上的仓库全部pull下来,让两个仓库相关联。

最后依次用命令:

 git add .              
 git commit -m "commit2"                    
 git push origin master:master

第二种:从远程克隆仓库

  1.创建仓库,复制地址

  2.克隆:git clone  git@github.com:michaelliao/learngit.git

  3.添加文件

  4.git add .

  5.git commit -m "test"

  6.git push -u origin master

9.分支管理

a.创建与合并分支:

  1.创建分支:git branch dev

  2.切换到分支:git checkout dev

  创建+切换分支:git checkout -b dev

  3.查看当前分支:gir branch 

  4.将指定分支合并到当前分支,假如当前分支为:master:git merge dev

  5.删除dev分支:git branch -d dev

  强行删除,需要使用命令:git branch -D dev。

b.解决冲突:

  1. 用带参数的git log可以看到分支的合并情况:git log –graph –pretty=oneline –abbrev-commit
    c.bug分支:修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;
    当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场。

  2. 把当前工作现场“储藏”起来:git stash。现在,用git status查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地创建分支来修复bug。

  3. 工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:
    一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;另一种方式是用git stash pop,恢复的同时把stash内容也删了。工作区是干净的,刚才的工作现场存到哪去了?用git stash list命令看看。

c.多人协作:

  1.查看远程库的详细信息:git remote -v

  2.推送分支:git push origin master

  3.抓取分支:

本地新建的分支如果不推送到远程,对其他人就是不可见的;

从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;

在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;

建立本地分支和远程分支的关联,使用git branch –set-upstream branch-name origin/branch-name;

从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。

10.标签管理:

a.创建标签:

首先,切换到需要打标签的分支上:git checkout branch-name然后打标签:git tag tag-name。git tag查看所有标签。

如果忘了打标签,比如,现在已经是周五了,但应该在周一打的标签没有打,怎么办?

方法是找到历史提交的commit id,然后打上就可以了:

$git log --pretty=oneline --abbrev-commit

6a5819e merged bug fix 101
cc17032 fix bug 1017825a50 merge with no-ff
6224937 add merge
59bc1cb conflict fixed
400b400 & simple
75a857c AND simple
fec145a branch test
d17efd8 remove test.txt
...

比方说要对add merge这次提交打标签,它对应的commit id是6224937,敲入命令:

$ git tag v0.9 6224937

再用命令git tag查看标签.
git show <tagname>查看标签信息

创建带有说明的标签,用-a指定标签名,-m指定说明文字:
$ git tag -a v0.1 -m "version 0.1 released" 3628164

通过-s用私钥签名一个标签:
$ git tag -s v0.2 -m "signed version 0.2 released" fec145a

11.操作标签:

命令git push origin <tagname>可以推送一个本地标签;

命令git push origin --tags可以推送全部未推送过的本地标签;

命令git tag -d <tagname>可以删除一个本地标签;

命令git push origin :refs/tags/<tagname>可以删除一个远程标签。

12.配置别名:

$ git config --global alias.st status  //用st表示status

然后用git st就可以查看状态。 

13.忽略文件:

大部分项目中,有些文件,文件夹是我们不想提交的。为了防止一不小心提交,我们需要gitignore文件:

在项目根目录创建.gitignore文件,在文件中列出不需要提交的文件名,文件夹名,每个一行,.gitignore文件需要提交,就像普通文件一样。

通常会被ignore的文件有:

  1. log文件
  2. task runner builds
  3. node_modules等文件夹
  4. IDEs生成的文件
  5. 个人笔记

简介:

box-sizing 属性允许您以特定的方式定义匹配某个区域的特定元素。

语法:

box-sizing:content-box | border-box 默认值:content-box

取值:

  1. content-box,padding和border不被包含在定义的width和height之内。对象的实际宽度等于设置的width值和border、padding之和,即 ( Element width = width + border + padding )。此属性表现为标准模式下的盒模型。

  2. border-box,padding和border被包含在定义的width和height之内。对象的实际宽度就等于设置的width值,即使定义有border和padding也不会改变对象的实际宽度,即 ( Element width = width )。此属性表现为怪异模式下的盒模型。

示例:

  1. content-box:

    .test1{ box-sizing:content-box; width:200px; padding:10px; border:15px solid #eee; }

实际宽度为:200+(10+10)+(15+15), 内容宽度为:200

  1. border-box:

    .test2{ box-sizing:border-box; width:200px; padding:10px; border:15px solid #eee; }

实际宽度为:200, 内容宽度为:200-(10+10)-(15+15)

内核类型写法:

Webkit(Chrome/Safari)-webkit-box-sizing

Gecko(Firefox)-moz-box-sizing

Presto(Opera)-o-box-sizing

Trident(IE)IE8:-ms-box-sizing/IE9:box-sizing

注意:

由于CSS5标准还未完全订下来,所以各种内核的浏览器都有自己的标准,为了不使属性混淆,所以各家在各自标准前加了一个前缀,

如:

-moz- 主要是firefox火狐

-webikt- 主要是chrome谷歌

-o- 主要是用于苹果机上的浏览器

一. box-shadow(阴影效果)

使用:

box-shadow: 20px 10px 0 #000;
-moz-box-shadow: 20px 10px 0 #000;
-webkit-box-shadow: 20px 10px 0 #000;

支持:

FF3.5, Safari 4, Chrome 3

二. border-colors(为边框设置多种颜色)

使用:

border: 10px solid #000;
-moz-border-bottom-colors: #555 #666 #777 #888 #999 #aaa #bbb #ccc;
-moz-border-top-colors: #555 #666 #777 #888 #999 #aaa #bbb #ccc;
-moz-border-left-colors: #555 #666 #777 #888 #999 #aaa #bbb #ccc;
-moz-border-right-colors: #555 #666 #777 #888 #999 #aaa #bbb #ccc;

说明:

颜色值数量不固定, 且FF的私有写法不支持缩写: -moz-border-colors: #333 #444 #555;

支持:

FF3+

三. boder-image(图片边框)

使用:

 -moz-border-image: url(exam.png) 20 20 20 20 repeat;
 -webkit-border-image: url(exam.png) 20 20 20 20 repeat;

说明:

(1). 20 20 20 20 —边框的宽度, 分别对应top, right, bottom, left边框, 改变宽度可以实现不同的效果;
(2). 边框图片效果(目前仅实现了两种):
repeat — 边框图片会平铺, 类似于背景重复;
stretch — 边框图片会以拉伸的方式来铺满整个边框;
(3). 必须将元素的边框厚度设置为非0非auto值.

支持:

FF 3.5, Safari 4, Chrome 3

四. text-shadow(文本阴影)

使用:

text-shadow: [<颜色><水平偏移><纵向偏移><模糊半径>] || [<水平偏移><纵向偏移><模糊半径><颜色>];

说明:

(1) <颜色>和<模糊半径>是可选的, 当<颜色>未指定时, 将使用文本颜色; 当<模糊半径>未指定时, 半径值为0;
(2) shadow可以是逗号分隔的列表, 如:
text-shadow: 2px 2px 2px #ccc, 3px 3px 3px #ddd;
(3) 阴影效果会按照shadow list中指定的顺序应用到元素上;
(4) 这些阴影效果有可能相互重叠, 但不会叠加文本本身;
(5) 阴影可能会跑到容器的边界之外, 但不会影响容器的大小.

支持:

FF 3.5, Opera 10, Safari 4, Chrome 3

五. text-overflow(文本截断)

使用:

text-overflow: inherit | ellipsis | clip ;
-o-text-overflow: inherit | ellipsis | clip;

说明:

(1) 还有一个属性ellipsis-word, 但各浏览器均不支持.

支持:

IE6+, Safari4, Chrome3, Opera10

六. word-wrap(自动换行)

使用:

word-wrap: normal | break-word;

支持:

IE6+, FF 3.5, Safari 4, Chrome 3

七. border-radius(圆角边框)

使用:

 -moz-border-radius: 5px;
 -webkit-border-radius: 5px;

支持:

FF 3+, Safari 4, Chrome 3

八. opacity(不透明度)

使用:

opacity: 0.5;
filter: alpha(opacity=50); /* for IE6, 7 */
-ms-filter(opacity=50); /* for IE8 */

支持:

all

九. box-sizing(控制盒模型的组成模式)

使用:

box-sizing: content-box | border-box; // for opera
-moz-box-sizing: content-box | border-box;
-webkit-box-sizing: content-box | border-box;

说明:

  1. content-box:
    使用此值时, 盒模型的组成模式是, 元素宽度 = content + padding + border;
  2. border-box:
    使用此值时, 盒模型的组成模式是, 元素宽度 = content(即使设置了padding和border, 元素的宽度
    也不会变)。

支持:

FF3+, Opera 10, Safari 4, Chrome 3

String的描述

字符串是JavaScript中的一种基本的数据类型。
String 对象的length属性声明了该字符串中的字符数。
String 类定义了大量操作字符串的方法,例如从字符串中提取字符或子串,或者检索字符或子串。
String 对象用于处理文本(字符串)。

创建 String 对象的语法:

new String(s);
String(s);

参数

参数 s 是要存储在 String 对象中或转换成原始字符串的值。

返回值

当 String() 和运算符 new 一起作为构造函数使用时,它返回一个新创建的 String 对象,存放的是字符串 s 或 s 的字符串表示。
当不用 new 运算符调用 String() 时,它只把 s 转换成原始的字符串,并返回转换后的值。

JavaScript 中 slice 、substr 和 substring的区别:

  1. String.slice(start,end): 一个新的字符串。包括字符串 stringObject 从 start 开始(包括 start)到 end 结束(不包括 end)为止的所有字符.

  2. String.substring(start,end) 这个就有点特别了,它是先从start,end里找出一个较小的值. 然后从字符串的开始位置算起,截取较小值位置和较大值位置之间的字符串,截取出来的字符串的长度为较大值与较小值之间的差。
    一个新的字符串,该字符串值包含 stringObject 的一个子字符串,其内容是从 start 处到 stop-1 处的所有字符,其长度为 stop 减 start。

  3. String.substr(start,end) 这个就是我们常用的从指定的位置(start)截取指定长度(end)的字符串。
    一个新的字符串,包含从 stringObject 的 start(包括 start 所指的字符) 处开始的 lenght 个字符。如果没有指定 lenght,那么返回的字符串包含从 start
    到 stringObject 的结尾的字符。
    String 对象的方法 slice()、substring() 和 substr() (不建议使用)都可返回字符串的指定部分。slice() 比 substring() 要灵活一些,因为它允许使用负数作为参数。slice() 与 substr() 有所不同,因为它用两个字符的位置来指定子串,而 substr() 则用字符位置和长度来指定子串。

String对象中常用的方法:

1. charCodeAt方法返回一个整数,代表指定位置字符的Unicode编码。

用法:

strObj.charCodeAt(index)

说明:

index将被处理字符的从零开始计数的编号。有效值为0到字符串长度减1的数字。
如果指定位置没有字符,将返回NaN。

例如:

var str = "ABC";
str.charCodeAt(0);
结果:65

2. fromCharCode方法从一些Unicode字符串中返回一个字符串。

用法:

String.fromCharCode([code1[,code2...]])

说明:

code1,code2...是要转换为字符串的Unicode字符串序列。如果没有参数,结果为空字符串。

例如:

String.fromCharCode(65,66,112);
结果:ABp

3. charAt方法返回指定索引位置处的字符。如果超出有效范围的索引值返回空字符串。

用法:

strObj.charAt(index)

说明:

index想得到的字符的基于零的索引。有效值是0与字符串长度减一之间的值。

例如:

var str = "ABC";
str.charAt(1);
结果:B

4. slice方法返回字符串的片段。

用法:

strObj.slice(start[,end])

说明:

start下标从0开始的strObj指定部分其实索引。如果start为负,将它作为length+start处理,此处length为字符串的长度。
end小标从0开始的strObj指定部分结束索引。如果end为负,将它作为length+end处理,此处length为字符串的长度。

例如:

var str = "ABCDEF";
str.slice(2,4);
结果:CD

5. substring方法返回位于String对象中指定位置的子字符串。

用法:

strObj.substring(start,end)

说明:

start指明子字符串的起始位置,该索引从0开始起算。
end指明子字符串的结束位置,该索引从0开始起算。
substring方法使用start和end两者中的较小值作为子字符串的起始点。如果start或end为NaN或者为负数,那么将其替换为0。

例如:

var str = "ABCDEF";
str.substring(2,4); // 或 str.substring(4,2);
结果:CD

6. substr方法返回一个从指定位置开始的指定长度的子字符串。

用法:

strObj.substr(start[,length])

说明:

start所需的子字符串的起始位置。字符串中的第一个字符的索引为0。
length在返回的子字符串中应包括的字符个数。

例如:

var str = "ABCDEF";
str.substr(2,4);
结果:CDEF

7. indexOf方法返回String对象内第一次出现子字符串位置。如果没有找到子字符串,则返回-1。

用法:

strObj.indexOf(substr[,startIndex])

说明:

substr要在String对象中查找的子字符串。
startIndex该整数值指出在String对象内开始查找的索引。如果省略,则从字符串的开始处查找。

例如:

var str = "ABCDECDF";
str.indexOf("CD",1); // 由1位置从左向右查找 123...
结果:2

8. lastIndexOf方法返回String对象中字符串最后出现的位置。如果没有匹配到子字符串,则返回-1。

用法:

strObj.lastIndexOf(substr[,startindex])

说明:

substr要在String对象内查找的子字符串。
startindex该整数值指出在String对象内进行查找的开始索引位置。如果省略,则查找从字符串的末尾开始。

例如:

var str = "ABCDECDF";
str.lastIndexOf("CD",6); // 由6位置从右向左查找 ...456
结果:5

9. search方法返回与正则表达式查找内容匹配的第一个字符串的位置。

用法:

strObj.search(reExp)

说明:

reExp包含正则表达式模式和可用标志的正则表达式对象。

例如:

var str = "ABCDECDF";
str.search("CD"); // 或 str.search(/CD/i);
结果:2

10. concat方法返回字符串值,该值包含了两个或多个提供的字符串的连接。

用法:

str.concat([string1[,string2...]])

说明:

string1,string2要和所有其他指定的字符串进行连接的String对象或文字。

例如:

var str = "ABCDEF";
str.concat("ABCDEF","ABC");
结果:ABCDEFABCDEFABC

11. 将一个字符串分割为子字符串,然后将结果作为字符串数组返回。

用法:

strObj.split([separator[,limit]])

说明:

separator字符串或 正则表达式 对象,它标识了分隔字符串时使用的是一个还是多个字符。如果忽略该选项,返回包含整个字符串的单一元素数组。
limit该值用来限制返回数组中的元素个数。

例如:

var str = "AA BB CC DD EE FF";
alert(str.split(" ",3));
结果:AA,BB,CC

12. toLowerCase方法返回一个字符串,该字符串中的字母被转换成小写。

例如:

var str = "ABCabc";
str.toLowerCase();
结果:abcabc

13. toUpperCase方法返回一个字符串,该字符串中的所有字母都被转换为大写字母。

例如:

var str = "ABCabc";
str.toUpperCase();
结果:ABCABC

虽然js String对象已经提供像slice、replace、indexOf和substring等方法,但在实际项目应用中会对其进行扩展,以达到实用、方便目的。注释很详细,废话少说,代码如下:

String对象方法扩展:

字符串-格式化

String.prototype.format = function(){
var args = arguments;//获取函数传递参数数组,以便在replace回调函数内使用
var regex = /\{(\d+)\}/g;//匹配并捕获所有 形如:{数字} 字串
return this.replace(regex,function(m,i){//参数=匹配子串+第几次匹配+匹配字串位置+源字符串
return args[i];
});
}

字符串-去掉前后空白字符

String.prototype.trim = function(){
return this.replace(/(^\s*)|(\s*$)/g, "");
}

字符串-去掉前空白字符

String.prototype.ltrim = function(){
return this.replace(/(^\s*)/g, "");
}

字符串-去掉后空白字符

String.prototype.rtrim = function(){
return this.replace(/(\s*$)/g, "");
}

字符串-获取以ASCII编码字节数 英文占1字节 中文占2字节

String.prototype.lenASCII=function(){
return this.replace(/[^\x00-\xff]/g,'xx').length;//将所有非\x00-\xff字符换为xx两个字符,再计算字符串
}

字符串-获取以UNICODE编码字节数 一个字符均占2个字节

String.prototype.lenUNICODE=function(){
return this.length*2;
}
ps:若对js提供类型对象或自定义对象进行方法扩展,应利用原型prototype这个对象属性进行扩展,具体方式以下:

String.prototype.trim=function(){
//...代码略
};
String.prototype.ltrim=function(){
//...代码略
};