HTML5-WebSocket API 学习

  1. 1. 服务器端 编写serverfile.js文件,建立http服务器和socket连接:
  2. 2. 浏览器端 编写 webSocket.html ,建立与服务器的连接:
  3. 3. 浏览器对WebSocket的支持性

使用nodejs的socket.io和现代浏览器的WebSocket来建立一个聊天室。

服务器端 编写serverfile.js文件,建立http服务器和socket连接:

[javascript]
var http = require(‘http’);
var io = require(‘socket.io’);

// 创建一个服务器
var server = http.createServer(function(request, response){
response.writeHead(200, {‘Content-type’: ‘text/html’});
response.end(‘小赖的WebSocket服务器启动啦!’);
});
// 监听端口
server.listen(9999);

// 创建一个WebSocket
var socket = io.listen(server).set(‘log’, 1);

// 监听连接
server.on(‘connection’, function(client) {
// 监听信息
client.on(‘message’, function(data){
console.log(‘收到客户端发来信息:’, data);
var curTime = new Date().getTime();
client.emit(‘服务器返回信息:’, data + ‘->’ + curTime);

     client.on('disconnect', function(){
         console.log('连接已断开');
     });
 });

});
[/javascript]

创建http服务器,运行http服务器成功:

浏览器端 编写 webSocket.html ,建立与服务器的连接:

[html]
<!DOCTYPE html>
<html>
<head>
<title>WebSocket API</title>
<meta charset="utf-8">
<script src="<span style="text-decoration: underline;">http://localhost:9999/socket.io/socket.io.js</span>"></script&gt;
</head>
<body>
<div id="log">显示log信息…</div>
<input id="msg" type="text" placeholder="请输入信息" />
<button id="send-btn">发送!</button>

<script>
var myWebSocket = {};
myWebSocket.socketio = {
mysocket: null,
initialize: function(){
// 建立连接
myWebSocket.socketio.mysocket = io.connect(‘<span style="text-decoration: underline;">http://localhost:9999</span&gt;’);
// 监听连接
myWebSocket.socketio.mysocket.on(‘connect’, function(){
myWebSocket.socketio.log(‘成功连接到服务器\n’);
});
// 监听信息
myWebSocket.socketio.mysocket.on(‘message’, function(data){
myWebSocket.socketio.log(‘服务器返回数据:’ + data + ‘\n’);
});
// 监听断开连接
myWebSocket.socketio.mysocket.on(‘disconnect’, function(){
myWebSocket.socketio.log(‘已断开连接\n’);
})

         // 点击发送按钮
         document.querySelector('#send-btn').onclick = function(){
             // 发送信息到服务器
             var msg = document.querySelector('#msg').value;
             myWebSocket.socketio.sendMessageToServer(msg);
             document.querySelector('#msg').value = '';
         };
     },
     sendMessageToServer: function(data){
         myWebSocket.socketio.mysocket.secd(data);
         myWebSocket.socketio.log('已发送信息到服务器:' + data +'\n');
     },
     log: function(msg) {
         document.querySelector('#log').innerHTML += msg;
     }
 }

 myWebSocket.socketio.initialize();
 &lt;/script&gt;

</body>
</html>
[/html]

然后在浏览器打开这个网页,终端显示:

这样客户端和服务器就可以通信啦!

输入信息后,点击发送,终端显示:

浏览器则显示:

然后关闭服务器的话,则显示「已断开连接」:

实现广播功能,即一个客户端发送消息,所以和服务器建立了连接的其他客户端都能看到这个消息:
修改serverfile.js文件,注意有『修改』字眼的部分:

[javascript]
var http = require(‘http’);
var io = require(‘<span style="text-decoration: underline;">socket.io</span>’);

// 创建一个服务器
var server = http.createServer(function(request, response){
response.writeHead(200, {‘Content-type’: ‘text/html’});
response.end(‘小赖的WebSocket服务器启动啦!’);
});
// 监听端口
server.listen(9999);

// 创建一个WebSocket

var socket = io.listen(server).set(‘log’, 1);

// 监听连接
socket.on(‘connection’, function(client) {
// 修改:监听信息
client.on(‘customMessage’, function(data){
console.log(‘收到客户端发来信息:’, data);
var curTime = new Date().getTime();

     // 修改:使用广播方法
     client.broadcast.emit('服务器返回customMessage信息:', data + '广播-&gt;' + curTime);

     client.on('disconnect', function(){
         console.log('连接已断开');
     });
 });

});
[/javascript]

修改webSocket.html文件,注意有『修改』字眼的部分:

[html]
<!DOCTYPE html>
<html>
<head>
<title>WebSocket API</title>
<meta charset="utf-8">
<script src="<span style="text-decoration: underline;">http://localhost:9999/socket.io/socket.io.js</span>"></script&gt;
</head>
<body>
<div id="log">显示log信息…</div>
<input id="msg" type="text" placeholder="请输入信息" />
<button id="send-btn">发送!</button>

<script>
var myWebSocket = {};
myWebSocket.socketio = {
mysocket: null,
initialize: function(){
// 建立连接
myWebSocket.socketio.mysocket = io.connect(‘<span style="text-decoration: underline;">http://localhost:9999</span&gt;’);
// 监听连接
myWebSocket.socketio.mysocket.on(‘connect’, function(){
myWebSocket.socketio.log(‘成功连接到服务器<br />’);
});
//修改: 监听customMessage信息
myWebSocket.socketio.mysocket.on(‘broadcastMessage’, function(data){
myWebSocket.socketio.log(‘收到广播信息:’ + data + ‘<br />’);
});
// 监听断开连接
myWebSocket.socketio.mysocket.on(‘disconnect’, function(){
myWebSocket.socketio.log(‘已断开连接\n’);
})

         // 点击发送按钮
         document.querySelector('#send-btn').onclick = function(){
             // 发送信息到服务器
             var msg = document.querySelector('#msg').value;
             myWebSocket.socketio.sendMessageToServer(msg);
             document.querySelector('#msg').value = '';
         };
     },
     sendMessageToServer: function(data){
         // 修改
         myWebSocket.socketio.mysocket.emit('customMessage', data);
         myWebSocket.socketio.log('已发送信息到服务器:' + data +'&lt;br /&gt;');
     },
     log: function(msg) {
         document.querySelector('#log').innerHTML += msg;
     }
 }

 myWebSocket.socketio.initialize();
 &lt;/script&gt;

</body>
</html>
[/html]

然后用多个页面打开webSocket.html,在第一个页面输入消息:

点击发送,其他页面立即收到了消息:

在第二个页面输入信息:

在其他页面收到广播:


哇!WebSocket够强大,可以实现客户端和服务端的通信,而node的socket.io更是封装了它的一系列方法,实现一个web端通信就轻而易举了,但!是!HTML5的这个新特性,你敢用嘛?!

浏览器对WebSocket的支持性

在caniuse.com查询可知,WebSocket在IE10+和其他现代浏览器才支持,低版本的IE不支持WebSocket - -!

不过好消息是,socket.io对不支持WebSocket的浏览器启用了其他策略,使得socket.io甚至能在IE6下运行!

学好node后再回来拓展这个小小聊天室呗^_^
参考资料
参考资料
参考资料

HTML5-file API 学习

为实现图片上传前预览并限制图片大小,貌似只能通过flash和HTML5的API来解决了吧?

今天学习了HTML5的file API,将预览和限制大小的功能应用到了项目里。

练习代码先贴到这,方便自己查阅,日后比较空闲时再回来好好研究那些API的机制吧:)

[html]

<p>请选择图片(可多选):</p>
<input id="file_input" type="file" multiple style="display:none;" onchange="handleFiles(this.files)">
<button id="select-btn">请选择图片</button>
<div id="dropbox" style="width:300px;height:200px;background:#eee;">
或拖动图片到此处
</div>
<ol id="preview-img-list">

</ol>
<button id="send-btn">发送!</button>

[/html]

[javascript]

// 获取文件
var file_input = document.getElementById(‘file_input’);
var select_btn = document.getElementById(‘select-btn’);
var preview_img_list = document.getElementById(‘preview-img-list’);
var dropbox = document.getElementById(‘dropbox’);
var send_btn = document.getElementById(‘send-btn’);

// 选择文件
select_btn.onclick = function(){
file_input.click();
};

send_btn.onclick = function(){
sendFiles();
};

// 监听文件改变
file_input.addEventListener(‘change’, handleFiles, false);
// 监听拖拽事件
dropbox.addEventListener(‘dragenter’, dragenter, false);
dropbox.addEventListener(‘dragover’, dragover, false);
dropbox.addEventListener(‘drop’, drop, false);

// 接受并预览图片
function handleFiles(files){
var len = files.length;
var imageType = /image.*/;
window.URL = window.URL || window.webkitURL;
if (len) {
preview_img_list.innerHTML = ‘’;
for (var i = 0; i < len; i++) {
if( ! files[i].type.match(imageType)) {
// 不是图片 跳过
continue;
}

var li = document.createElement(‘li’);
var img = document.createElement(‘img’);
var p = document.createElement(‘p’);

p.innerHTML = ‘name: ‘ + files[i].name + " <br />size: " + files[i].size + ‘ Bytes’ + "<br/>type: " + files[i].type;

// 将file对象存在当前图片中,用于后续创建上传任务
img.file = files[i];
// 添加一个类,方便选择
img.classList.add(‘obj’);
/方法一:使用URL对象预览图片/
// 使用window.URL.createObjectURL创建 blob URL
img.src = img.src = window.URL.createObjectURL(files[i]);
img.onload = function(e) {
// 使用window.URL.revokeObjectURL释放URL对象,因为图片加载完成后不再需要这个对象
window.URL.revokeObjectURL(this.src);
}
/方法一结束/

/方法二:使用FileReader对象预览图片 /
// var reader = new FileReader();
// reader.onload = (function(aImg) {
// return function(e) {
// aImg.src = e.target.result;
// };
// })(img);
// reader.readAsDataURL(files[i]);
/方法二结束 /

li.appendChild(img);
preview_img_list.appendChild(li);

};
}
}

// 创建上传任务
function sendFiles() {
var imgs = document.querySelectorAll(‘.obj’);
var len = imgs.length;
for (var i = 0; i < len; i++) {
// 第二个参数用于读取图片数据
new FileUpLoad(imgs[i], imgs[i].file);
};
}

function FileUpLoad(img, file) {
var reader = new FileReader();
// 创建一个 throbber 用于显示进度信息
this.ctrl = createThrobber(img);
// 创建一个XMLHttpRequest对象用来上传数据
var xhr = new XMLHttpRequest();
this.xhr = xhr;

var self = this;
// 监听数据上传,更新throbber
this.xhr.upload.addEventListener(‘progress’, function(e){
if (e.lengthComputable) {
var percentage = Math.round((e.loaded * 100) / e.total);
self.ctrl.update(percentage);
}
}, false);
// 上传完成,更新进度到100%,移除throbber 因为不再需要
xhr.upload.addEventListener(‘load’, function(e) {
self.ctrl.update(100);
var canvas = self.ctrl.ctx.canvas;
canvas.parentNode.removeChild(canvas);
}, false);
// 使用POST方式发送数据
xhr.open("POST", "http://demos.hacks.mozilla.org/paul/demos/resources/webservices/devnull.php&quot;);
// 使用一个通用的MIME类型
xhr.overrideMimeType(‘text/plain; charset=x-user-defined-binary’);
reader.onload = function(evt) {
// 以二进制形式发送
xhr.sendAsBinary(evt.target.result);
};
// 将文件转化为二进制字符串形式
reader.readAsBinaryString(file);
}

&nbsp;

function dragenter(e) {
e.stopPropagation();
e.preventDefault();
}
function dragover(e) {
e.stopPropagation();
e.preventDefault();
}
function drop(e) {
e.stopPropagation();
e.preventDefault();

var dt = e.dataTransfer;
var files = dt.files;

handleFiles(files);
}

[/javascript]

 

这个File API 使得浏览器支持预览、图片大小/类型限制、拖拽上传、多图上传。

 

图片预加载和判断图片是否加载完成

使用Image()对象预加载图片:

var imgsSrcArray = [src1, src2, src3, src4, src5];
需要预加载这些图片,以便点击上一张或下一张按钮的时候,能显示对应的图片。
使用JS自带的 Image对象 实现图片预加载:
[javascript]
var images= [];
var len = imgsSrcArray.length;
for(var i = 0; i < len; i++) {
var img = new Image();
img.src = imgsScrArray[i];
images.push(img)
}
[/javascript]

这样就实现了将多个图片进行了预加载,缓存到了images数组里。

使用img.onload,当图片加载完成时执行操作:

[javascript]
img.onload = function(){
// console.log(‘图片加载完成’)
};
[/javascript]

判断图片是否已经加载完成则:需要判断 img.complete属性是否为true:

if (img.complete) {
// 执行操作
}

优化刚刚的预加载函数,封装一个预加载非固定数目图片的函数

[javascript]
var images = [];
function preloadImgs() {
// 利用arguments参数判断需要加载的图片数目
var len = preloadImgs.arguments.length;
for (var i=0; i<len; i++) {
images[i] = new Image();
images[i].src = preloadImgs.arguments[i];
}
}
[/javascript]

// 或传入数组
[javascript]
var images = [];
function preloadImgs(srcArray) {
// 利用arguments参数判断需要加载的图片数目
var len = preloadImgs.arguments.length;
for (var i=0; i<len; i++) {
images[i] = new Image();
images[i].src = srcArray[i];
}
}
[/javascript]

阅读全文

坎坷大学路

今天晚上UC俱乐部开了个分享会,难得停下来倾听别人的成长,几分感触。
WT 分享了ACM竞赛的经验,现在保送到新加坡国立大学硕博连读5年,真是艳羡,不能望其项背。
SZ 分享了Android的开发的体会,而我则给大家介绍了『前端』这个新词汇。

说长也不长,说短亦不短,转眼现在已经大三。
好像一直在瞎忙,忙得忘记停下来回头看看自己遇到了哪些坎,忘记停下来总结总结自己的教训。

这篇文,就算是给自己一个安慰吧。

# 教训

> 教训1:大学生谓之『大』,异于『小』学生,异于『中』学生。
大学生该有『大』的风范,该有高等教育背景下的专业素养,比如:你应该用你的专业视觉去剖析社会现象,而非做盲目从众的五毛党。

> 教训2:大学生谓之『学生』,同于『小』学生,同于『中』学生。大学生的本质仍在于『学习』,可以用不同的学习方式来帮助自己成长,但不能离其宗-你得不断在学习。

按《原本大学》的说法,大学之道,在明明德,在亲民,在止于至善。知止而后有定,定而后能静,静而后能安,安而后能虑,虑而后能得。这『大学』不一定指代我们在读的『大学』,但作为一个成年人,就该有这方面的担当吧。
按胡适先生的说话,我们要有独立之思想,自由之精神。
唉,作为一个自私又功利的个体大学生,我其实没有没有那么高尚,我对自己大学的定义是:
认识自己,认识朋友,认识世界。
这真是一个无比艰难的过程。
# 经验

> 经验1:认识自己在于你如何给自己定位,是想做A,还是做B。
我不比别人聪明,这个智商是硬伤,那就该结合自身,发挥特长,将这仅有的一丁点智商用到极致。
靠几分努力,加几分坚持,慢慢发现你总能打败那些毫不上进的人。而面对那些不能望其项背的牛人,你则必须非常努力,才有可能迎头赶上。

> 经验2:兴趣还真是个最好的老师。
人生短暂仅有几十年,怎么个过法,我可不想听天由命。毕业后,三分之一的时间在职场,三分之一的时间在家庭,还三分之一的时间在————-做梦。我假定我原来很悲哀,只有后面三分之二是快乐的(够自卑了吧)。但如果,我能在职场上做一份感兴趣的工作,那么就可以提高这个快乐值啊,好像人生又会多个三分之一。有兴趣还不够,你还得坚持。

> 经验3:预则立,不预则废。
一直缠绕我的无非就是拖延症了,有时候事一多,情绪上就会闹例假,啥都不想干。
但在死亡Deadline降临之时,我就必须咬紧牙关应付任务。这时候诸葛亮地想一想,这事早点做认真做其实可以做得更好一些。
真是事前猪一样啊。
事多不代表会做的不好(尽管这可能是残酷的结果),你必须根据权重来执行任务,才不会累坏身体搞坏心情。
> 经验4:静心才能成事,多思才能致远。
能安静做一件事情,其实就是在享受一种奢侈。要学会制造、享受这种奢侈。
多思就有多个可能多个方案,不给自己设限,才能给自己留下更多空间。

>经验4:不重要的东西不代表可以不学习。
鬼知道你学的这点皮毛哪一天就真正用上了呢?
这体现在当我以一个比较Open的心态去学习的时候,发现了一个真理:
『The more you know, the more you know you don’s know.』
而恰恰遇上这种未知的可能时,你得逼自己一把去尝试学会新的知识或者工具。
『When you don’t know how to do it, just do it as if you know how to do it.』

唉,机会失去太多。
但,仍有很多可能。

今天终于可以静下来,给自己灌鸡汤打鸡血,满血复活好好干。

你要相信,牛人的高度不是企及。
是你从一开始就放弃了自己。
你知道吗,那些牛人嘲笑你的不是你的水平菜,而是你的态度低。
凭大多数人的努力程度之低,根本轮不到你拼天赋。
你必须非常努力,才能在别人眼里看上去毫不费力。

要不试试?想想如果你一不小心在一个领域坚持了十年,可能你会发现:
1. 那群智商有余但定力不足的人们,玩了几年就坚持不下去了;
2. 前一波的前辈们不是退休了,就是挂了( - - 我真缺德)。
3. 你一不小心坚持了下来,哎呀妈啊,你智商都没用上就实现屌丝逆袭了,这得多励志啊 XD 。』

嗨,小赖,你要知道:
不设限,不止步,不屈服。

Cookies学习笔记

Cookie 的格式是:

[javascript]
name=<value>[; expires=<date>][; domain=<domain>][; path=<path>][; secure]
//名称=<值>[; expires=<日期>][; domain=<域>][; path=<路径>][; 安全]
[/javascript]

// 设置cookie

[javascript]
document.cookie="key=escape(value)";
[/javascript]

//escape()函数进行编码,它能将一些特殊符号使用十六进制表示,例如空格将会编码为“20%”,从而可以存储于cookie值中,而且使用此 种方案还可以避免中文乱码的出现。在取值的时候需要unescape(value)对value再进行转码即可。

// 设置多个cookie
设置多个cookie需要多次使用这样的方法。正确的设置方法是:

[javascript]
document.cookie="key=escape(value)";
document.cookie="key1=escape(value1)"
// 而不是
document.cookie="key=escape(value);key1=escape(value1)";
[/javascript]
// 获取cookie,注意第二个开始key值前面有空格:

[javascript]
function getCookie(key){
var aCookie = document.cookie.split(";");
for (var i=0; i < aCookie.length; i++){
var aCrumb = aCookie[i].split("=");
if (key === aCrumb[0].replace(/^\s|\s$/,"")){
return unescape(aCrumb[1]);
}
}
}
[/javascript]
// 设置cookie的存活时间:

[javascript]
var liveDate = new Date();
liveDate.setTime(liveDate.getTime() + 32460601000); //设置cookie的name的存活时间为3天。
document.cookie="name=test;expires=" + liveDate.toGMTString();
[/javascript]
// 删除cookie,设置expires一个过期的时间即可

[javascript]
var liveDate = new Date();
liveDate.setTime(liveDate.getTime() - 10000);
document.cookie = "name=test;expires=" + date.toGMTString();
[/javascript]
// 拓展cookie的作用域到根目录:

[javascript]
document.cookie="key=escape(value);path=/";
[/javascript]
// 设置cookie的访问域

[javascript]
document.cookie="name=value;domain=cookieDomain";
//以Laispace为例,要实现跨主机访问,可以写为:
document.cookie="name=value;domain=.laispace.com"; //所有Laispace.com下的主机都可以访问该cookie
[/javascript]
// 设置cookie的访问权限
设置了该属性,只有使用https协议才能够访问到
注意点:
如果设置cookie时带path属性,那么在删除的时候一定要加上path属性,否则删除的是当前目录下设置的cookie值。

Javascript 闭包的学习

名词定义:包裹一些局部变量的一个函数叫做一个闭包。闭包是个函数,而它「记住了周围发生了什么」。表现为由「一个函数」体中定义了「另个函数」
实现原理:嵌套函数可以访问外部作用域中声明的变量。
组成结构:函数以及构建这个函数的环境。
使用价值:将函数与其所操作的某些数据(环境)关连起来
使用缺点:闭包会影响性能!闭包会使得函数中的变量都被保存在内存中,内存消耗很大。

  • 用途1,将数据与多个函数相关联:
    [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(); // 将字号调整到12px
    //size14(); // 将字号调整到14px
    //size16(); // 将字号调整到16px
    [/javascript]

  • 用途2,模拟私有方法:
    私有方法不仅仅有利于限制对代码的访问:还提供了管理全局命名空间的强大能力,避免非核心的方法弄乱了代码的公共接口部分。
    [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;
    

    }
    }
    })();

    alert(Counter.value()); / 提示 0 /
    Counter.increment();
    Counter.increment();
    alert(Counter.value()); / 提示 2 /
    Counter.decrement();
    alert(Counter.value()); / 提示 1 /
    [/javascript]

这种方法跟创建一个对象,并分别定义对象的三个方法相似吧?
实验结果显示,这两种方式是相同的,不过小赖觉得,以下这种更为直观一点吧:
[javascript]
// 创建一个环境为三个函数共享,减少了污染
var Counter = {
privateCounter : 0,

increment: function() {
this.privateCounter +=1;
},

 decrement: function() {
   this.privateCounter -=1;
 },

 value: function() {
   return this.privateCounter;
 }

}

alert(Counter.value()); / 提示 0 /
Counter.increment();
Counter.increment();
alert(Counter.value()); / 提示 2 /
Counter.decrement();
alert(Counter.value()); / 提示 1 /
[/javascript]

使用闭包的话,三个方法共享一个环境,而使用对象来创建明明空间,实则是通过this指向这个对象,来保证共享一个环境,也是避免了污染,有异曲同工之妙吧。

参考:
1. 闭包
2. 闭包
3. secrets_of_javascript_closures

Javascript 最佳实践

  1. 1. 编码技巧
  2. 2. 新鲜概念

// @author lxl:使用高质量JS代码对提高性能肯定是非常有帮助的,小赖对常见的好方法总结在这里,不断更新。
// @update 2013/10/04
-
使用压缩后的文件(如lxl.min.js),并开启http gzip压缩工具
-
尽量将script标签放在前,可以尝试用异步加载的方法加载js文件
-
尽量保证js代码和HTML结构的分离,不要内嵌代码到HTML中,以统一维护和缓存处理

-

  • 避免全局变量的污染

1. 使用命名空间
2. 匿名函数封装立即执行
3. 始终使用var来声明变量

  • 使用var声明(显式)的全局变量是不能被删除的
  • 未用var声明(隐式)的全局变量是可以被删除的
  • 隐式全局变量并非真正的全局变量,但却是全局对象的属性,因为属性是可以通过delete操作符删除的,而变量则不行

  • for循环中将长度缓存到变量中。

1
避免重复计算HTMLCollections的长度(操作DOM一般都是比较昂贵的,缓存长度后效率竟然是是IE7下不缓存的190倍!)
  • for循环中建议使用降序来遍历
1
向下数到0通常更快,因为和0作比较要比和数组长度或非0的东西作比较更有效率
  • for-in循环只在遍历对象属性的时候才使用,其他情况建议使用for循环就够了
1
for-in 循环枚举出的顺序是不能保证的,且若数组对象已被自定义的功能增强,就可能发生逻辑错误
  • 避免隐式类型转换,使用===或!==总是最严谨的!
1
这总能避免一些意想不到的类型转换问题,不是么?
  • 使用hasOwnProperty()方法过滤从原型链继承的属性,如:
1
2
3
4
5
for (var i in man) {
if (man.hasOwnProperty(i)) { // 过滤
console.log(i, ":", man[i]);
}
}
  • 使用单var语句声明变量
1
2
3
4
变量的声明会被被JS引擎提至函数顶部预解析(hoisting),不如直接使用单var统 一声明所有将会用到的变量,方便查询又易于管理,如:
var a = 1,
b = 2,
c = 3;
  • 避免改变或增加原型对象的方法
1
2
3
4
5
6
7
随意改变或增加原型会增加维护成本,当以后使用一个方法却发现这个方法被重定义时,就会带来问题。
除非团队认可这种做法并意识到原型已添加了方法,知道怎么使用时:
if( typeof Object.prototype.myMethod !== "function"){
Object.prototype.myMethod = function(){
// 实现新增方法
}
}
  • 避免使用eval语句
1
2
3
4
5
6
7
8
9
10
eval是魔鬼,除非知道它执行的代码本身会有什么问题。
eval里的代码被恶意篡改的话,就会带来严重的安全问题。
若绝对需要使用eval,实则可以
1.new Function()替代,因为它有局部函数作用域,其中的var变量不会变成全局 的,可以避免一些问题.
2.将eval语句封装到即时的匿名函数中,与1有相同效果。
注意,setIntervalsetTimeout中传递字符串跟eval()是一样的,要注意避免直接 传递字符串:
setTimeout(myFunc, 1000); // 正确
setTimeout(function () { // 正确
myFunc(1, 2, 3);
}, 1000);
  • parseInt() 数制转换,不要忽略第二个参数指定基数
1
EC3中以字母o开头的字符串被当做八进制处理,而在EC5中已经改变,为了避免意外,应 该总是指定基数参数,尽管默认是10
  • 团队里使用同一套缩进方案,tab或space缩进
1
比起纠结于具体的规范,团队里总是执行同一套方案更有价值!
  • 总是使用花括号{},尽管只有一行代码
1
2
花括号开始的位置,是同一行还是换行,这也是团队规范的问题了:统一就好,不必 纠结。
为了避免下一条谈到js引擎自动补全分好的问题,建议花括号开始于同一行,可终端JS分 号的自动补全。
  • 总是使用分号结束代码
1
因为JS引擎自动补全分号的机制,不小心的换行可能会中断代码逻辑,如return语句块 换到了下一行。
  • 命名规范,多种,选择一套喜欢的呗
    1. 构造函数首字母大写,如Person(){}
    2. 构造函数驼峰命名分割单词,如MyFunc(){}
    3. 变量名用下划线分割单词,如 my_name,这可以喝ECMAScript默认属性和方法的Camel标记法相区分
    4. 常量用全大写和下划线书写,如 MAX_WIDTH
    5. 全局变量名全部大写,如GLOBAL,并使用它来定义明明空间,如GLOBAL.name = “xiaolai”;GLOBAL.myMethod = function(){};
    6. 私有属性或方法用下划线前缀来表示,如 _index
    -

编码技巧

  • 访问全局对象
1
2
3
4
全局对象一般直接通过window属性来访问,但特殊情况下(如定义了名为window的局部 变量覆盖了全局的window)可使用匿名函数内的this来获得全局对象:
var global = (function(){
return this;
})();

新鲜概念

  • HTMLCollections对象
1
2
3
4
5
6
7
document.getElementsByName();
document.getElementsByClassName();
document.getElementsByTagName();
document.images; // 页面上所有的图片元素
document.links; // 所有a标签
document.forms; // 所有表单
document.forms[0].elements; // 页面上第一个表单中的所有域

Javascript 异步加载

异步编程,即非阻塞地执行代码,其实可以用来加载一些附属功能的代码,比如分享按钮代码、GA分析代码等。
建议将script标签放置在就是为了不让JS代码阻塞DOM的渲染,不会在JS执行期间,网页一片空白卡顿的糟糕体验。
今天学习到GA的异步加载代码:
[javascript]
(function() {
var ga = document.createElement(‘script’); ga.type = ‘text/javascript’; ga.async = true;
ga.src = (‘https:’ == document.location.protocol ? ‘https://ssl‘ : ‘http://www‘) + ‘.google-analytics.com/ga.js’;
var s = document.getElementsByTagName(‘script’)[0]; s.parentNode.insertBefore(ga, s);
})();
[/javascript]
动态生成script标签并利用HTML5才新增的async属性设置为异步(可不写,但最好加上),加上用匿名函数封装,避免了内部变量泄露到外部污染全局。
这份代码可以兼容不支持HTML5中async属性的浏览器,而如果只考虑现代浏览器的话,其实可以偷懒,直接给要异步加载的script一个async属性即可实现上述异步加载的效果了:

用MySQLdb包连接数据库

  1. 1. !/usr/bin/python
  2. 2. -- coding: utf-8 --

捣鼓捣鼓,跨过好多坑终于在Mac上配置好了开发环境,开始学Python啦!
今天学习的是Python连接数据库,安装了python-mysql包后,使用它自带的一些方法就可以连接了:
[python]

!/usr/bin/python

-- coding: utf-8 --

import sys
import MySQLdb

db = None

try:

# 连接数据库
db=MySQLdb.connect(host=&quot;localhost&quot;,
                 user=&quot;root&quot;,passwd=&quot;&quot;,
                 db=&quot;wegroup&quot;,
                 charset = &quot;utf8&quot;,
                 unix_socket=&quot;/Applications/XAMPP/xamppfiles/var/mysql/mysql.sock&quot;)
                 # unix_socket 
cursor = db.cursor()

# 执行一个查询
cursor.execute(&quot;SELECT VERSION()&quot;)
data = cursor.fetchone()
# 显示数据库的版本
print &quot;Database version: %s&quot; % data

# 创建表user(id,name) 并插入数据
cursor.execute(&quot;CREATE TABLE IF NOT EXISTS user(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(30))&quot;)
cursor.execute(&quot;INSERT INTO user(name) VALUES('user1')&quot;)
cursor.execute(&quot;INSERT INTO user(name) VALUES('user2')&quot;)
# commit 后数据才会真正添加到数据表中!
db.commit()

# 更新数据
cursor.execute(&quot;UPDATE user SET name = %s WHERE id = %s&quot;,(&quot;xiaolai&quot; , 2));

# 获取数据并遍历
cursor.execute(&quot;SELECT * FROM user&quot;);
# 获取描述信息
desc = cursor.description
print &quot;描述信息:&quot;, desc
# 打印表头
print &quot;%s %s&quot; % (desc[0][0],desc[1][0])

# 获取结果数
count = cursor.rowcount
for i in range(count):
    row = cursor.fetchone()
    # 每一个都是一个元组
    print row[0], row[1]

finally:

# 记得要关闭!
if db:
    db.close()

[/python]

Mac OS 下MySQL配置与乱码解决

用惯了windows下xampp,打开Apache打开mysql就可以有一个本地服务器做测试了,在mac上发现:

1.xampp上的MySQL开启后,在终端输入『mysql』无反应,故在MySQL官网重装了个,终端就可以操作MySQL了;

2.MySQL默认端口是3306,两个MySQL是无法同时打开的,于是修改xampp中mysql的端口为3307(只要不冲突)就可以了:

3.初学Python,用Python连接数据库,却发现无法连接xampp中mysql的数据库,这就纳闷了,显示错误:

OperationalError: (2002, “Can’t connect to local MySQL server through socket ‘/tmp/mysql.sock’ (2)”)


修改了端口还不行么?查了好久了资料都没搞懂,stackoverflow上有类似的问题,真是个神奇的地方啊,修改xampp的配置文件:

让它能找到正确的socket,重新连接数据库,成功!

PS:除此之外,还可以在连接数据库时指定一个unix_socket使程序招到正确的sock:

[python]
conn=MySQLdb.connect(host="localhost",
user="root",passwd="",
db="wegroup",
unix_socket="/Applications/XAMPP/xamppfiles/var/mysql/mysql.sock")

                 # unix_socket 

[/python]

 

4.因mac默认编码不是utf-8,用python操纵mysql输出数据库的中文信息显示乱码

解决办法:
在配置文件的[client]后添加default-character-set=utf8;
在[mysqld]后添加:
default-storage-engine=INNODB
character-set-server=utf8
collation-server=utf8_general_ci;
终端mysql直接查询是不出现问题了,Python文件头也声明了utf-8编码,还是没用,只好直接在MySQLdb.connect 参数中指定编码为utf8:

[python]
conn=MySQLdb.connect(host="localhost",
user="root",passwd="",
db="wegroup",
charset = "utf8",
unix_socket="/Applications/XAMPP/xamppfiles/var/mysql/mysql.sock")

                 # unix_socket 

[/python]

如此一来,输出中文乱码的问题就解决啦: