标签:
来自:http://mzkmzk.github.io/blog/2015/10/05/amazeing-js/
本书的JS
<script>alert("执行js")</script>
var a = 1;//显式
a =1; //隐式
...
var scope = "全局变量";
function test(){
alert(scope); // undefiend
var scope = "局部变量";
alert(scope); // 局部变量
}
因为全局变量被局部变量覆盖了.虽然局部变量的scope还没赋值,但是已经在方法里”占”上位置了.
但如果把局部变量的var删了,就会先输出全局变量后输出局部变量,因为没有var在方法里给局部变量”占”位置;
var a =.333
var b = a * 5;
alert(b);
得出的结果是 1.66499999999999999
所以在js中判断浮点数是否相等 建议判断两者的差值是否小于一个足够的数(例如0.0000000000001)
js中没有字符类型变量 “”与’‘一致
var s ="abcdefg"
//b = "def"
b = s.slice(3, -1);
null == undefined //true
null === undefined //false
undefined 是没设值
null则是设定了为null值
//逗号运算符 取最右返回值
a = (b =5 , c = 7 , d =56) //a =56
a = void(b =5 , c = 7 , d =56) //a = undefined
typeof 用来获得 实例类型 :
typeof("123"); //string
instanceof 判断变量是否为某类的实例
var a = [4,5];
alert(a instanceof Array); //true
抛出异常
throw new Error("用户自定义异常"); //一般用于终止程序和返回错误提示是个不错的选择;
try{
}catch(e){
alert(e.message); // "用户自定义异常"
}
for in
//这回输出浏览器的所有属性,做浏览器兼容之前可以考虑看看.
for( prop_name in navigator){
document.wrti(prop_name + " : " + navigator[propname]);
}
跳出命名for
outer:
for(...){
for(...){
...
continue outer;
}
}
js 允许先调用函数 再定义函数
var show_name = function(name){
alert(name);
}
show_name("K"); //K
这样的好处是什么,如果直接定义function 它实际上也是创建了一个对象
var hello = function(){...};
hello instanceof Function //true;
hello instanceof Object //true;
alert(heelo) //输出函数源代码
在函数中使用this.变量 该变量就是函数的实例变量,而非局部变量,无论它在哪里.
函数可依附在类中.如没指定 则依附在winodw对象中
var hello =function(){...}
window.hello();
var p = {
wark: function(){...}
}
p.wark();
function Person(){
//局部变量 只能在函数里访问
var id ;
//实例属性 通过对象.访问
this.age ;
//类属性 通过Patient.name访问 与static类似
Person.name ;
}
function Student(){ };
var student =new Student();
//动态增加name属性
student.name = ‘K‘;
alert(sutdent.name) //K
Student.age =22 ;
alert(Student.age); //22 类属性也是可以动态添加的
直接调用
windows.alert();
//or
alert();
call()调用
作用:动态地传入一个函数引用
var each = function(array,fn){
for(var index in arrary){
//null表示以window为调用者fn函数
fn.call(null,index,arrary[index]);
}
}
each([4,20,3] , function(index ,ele){
alert("第 " + index "个元素是 : " + ele);
});
call()调用函数语法为:函数引用.call(调用者,参数1,参数2...)
直接调用函数语法为:调用者.函数(参数1,参数2 ...)
= 函数.call(调用者,参数1,参数2 ...)
apply()调用
apply和()call()基本相似,区别如下:
通过apply()动态地调用函数时,可以在括号中以arguments
来代表所有参数
var myfun = function (a , b){
alert(a + " " +b);
}
myfun.call(window ,12 ,23); //12 23;
myfun.apply(window ,[20 , 39]); //20 39
var example = function (num1 ,num2){
//直接调用arguments代表调用者(example,this代表example)时的传入的所有参数
myfun.apply(this,arguments);
}
example(20,40) //20 40
在函数A中可以定义函数B,但是函数B还是独立于函数A
function Person(name){
this.name = name;
this.info = function(){
alert(this.name);
}
}
var person =new Person(‘K‘);
person.info(); //K
var name = ‘K_window‘;
//由于window为调用者 ,this.name访问的是window.name
p.info.call(window); //K_window
来爽一发猫学狗叫?.
function Dog(name,bark){
this.name = name;
this.bark = bark;
this.info =function(){
alert(this.name + " " + this.bark);
}
}
function Cat(name){
this.name =name;
}
var dog = new Dog("K","汪汪!");
var cat = new Cat("K_2");
dog.info.call(cat); //K_2 undefined
和JAVA一样 都是值传递拉~.
基本类型
function change(arg){
arg =10 ;
alert(arg);
}
var x = 5;
alert(x); //5
change(x); //10
alert(x); //5
复合类型
function change(person){
person.age = 10;
alert(person.age);
person = null;
}
var person = {age : 5};
alert(person.age); //5
change(person); //10
alert(person.age); // 10
alert(person); // []object Object]
复合类型的传递为值传递,原person和参数person指向同一javascript对象,所以当改变age的时候,是在改变javascript对象的age,但是参数person赋值为null,原person并无改变.
function text(person){
alert( typeof parson);
}
text(); //undefined
所以对于弱类型,方法重载是无作用的,因为js会把空参数当做undefined传递进去;
同名函数,后面出现的会覆盖前面的,无论参数个数是多少.
javascript和Map有点类似,当key为对象,value为函数,该该函数就是对象的方法,当key为对象,value为基本类型,则该基本类型为对象的属性.(以上为便于理解,切勿细琢)所以访问属性时,可以obj.propName也可以obj[propName].
但有时候我们只能用obj[propName],因为.propName不能把propName当做变量处理,而是把他当成’propName’字符串
function Person(name){
this.name =name;
this.info = function(){
alert(K);
}
}
var person = new Person("K");
//遍历person属性
for (propName in person){
alert(p[propName]);//alet K info源代码 假如此处用p.propName则undefined,因为Person无‘propName‘变量.
}
在一个类(函数)中定义一个函数会导致
函数中若引用类的局部变量会产生闭包 导致局部变量一直存在
function Person(){
var local = "局部变量"
this.info = function(){
//产生闭包
alert(local);
}
}
var person = new Person();
person.ifno(); // 局部变量
解决方案:prototype
增加了prototype属性的类可视为继承了原先的类(伪继承)
function Person(){...}
var person = new Person();
//person.wark(); 程序报错wark不存在
Person.prototype.wark = function(){...}
person.wark(); //ok
在prototype之前实例化的类会具有wark方法吗? 有的,因为prototype这样并不会产生一个新的类,而是直接动态的往Person里加函数.
判断某方法是否继承了该对象
该对象.prototype[‘某方法‘] != undefined;
var test = new 该对象();
test.某方法 !=undefined ;
//(单身汪别说我不教你)
new关键字调用构造器创建对象
function Person(name){...}
var person_1 = new Person();
var person_2 = new Person(‘K‘); //js不存在方法重载,空参数undefined顶替
使用Object直接创建对象
var my_obj = new Object();
my_ojb.name = ‘K‘;
my_obj.handsome = function(){...}
function text(){...}
my_obj.text = text;//不要添加(),不然会认为是调用方法
JSON创建对象
ver person = {
name : ‘K‘,
school : [‘ChangAn‘,‘TianJin‘],
girl_friends :[
{
name : ‘Haski‘,
age : 11
},
{
name : ‘Samoyed‘,
age : ‘8‘
}
]
}
alert(person.girl_friends[0].name); //Haski
DOM操作其实JQuery已经做得很好了,这里简单补充一下原生JS的知识
HTML文档中只有一个根节点
根据节点关系
Node parentNode: 返回父节点
Node previousSibling: 返回前一个兄弟节点
Node nextSibling: 饭后后一个兄弟节点
Node[] childNodes 返回当前节点的所有节点
Node[] getElementsByTagName(‘标签名称‘): 返回当前节点具有制定标签的子节点
//注意ol标签的子标签IE8和其他浏览器不一样(其他浏览器会把ol下的li和其后面的空白分别当成2个节点,IE8则不会)
遍历window.screen,包含所以屏幕属性
for(var propName in window.screen){
alert(propName+":" +screent[propname]);
}
cofrim(‘标题’); 能弹出是否确认的提示框
定时器:setInterVal,clearInterval()
var timer;
var cur = new Date().getTime();
var setTime = function(){
document.getElementById("tm").innerHTML = new Date().toLocationString();
if(new Date().getTime- cur > 60 *1000){
clearInterval(timer);
}
}
//每1S执行一次,执行了60次就暂停
timer = window.setInterval("setTime()",1000);
navigator汉堡浏览器所有信息,遍历循环获取信息
for(var propName in window.navigator){
alert(propName + ":" + window.navigator[propName]);
}
HTML5新增geolocation属性
Geolocation提供的方法
上面的前两个方法的options参数是一个对象,可包含3个变量
例子:
var geoHandler = function(position){
var geoMsg = "用户地址位置是 : <br/>"
geoMsg += "timestamp属性为 :" + position.timestamp + "<br/>"//获取位置的时间
var cords =position.coords;
for(var prop in coords ){
geoMsg += prop + ": " + coords[prop] +"<br/>"//经纬度,移动速度等
}
document.writeln(geoMsg);
}
var errorHandler = function(error){
var errMsg = {
1: ‘用户拒绝了位置服务‘
2: ‘无法获取地址位置信息‘
3: ‘获取地理位置信息超时‘
};
alert(error[error.code]);
}
navigator.geolocation.getCurrentPosition(geoHandler
, errorHandler
, {
enableHighAccuracy:true,
maximuAge:1000
});
实现该功能主要通过performance对象
其中的(PerformanceTiming)timing属性包含加载时间相关的属性
另外(PerformanceNavigation)navigation,主要属性有
type :
TYPE_NAVIGATE(数值为0): 超链接/输入url
TYPE_RELOAD(1): 重新加载方式,diaoyonglocation.reload()等
TYPE_BACK_FORWARD(2): 通过浏览器的前进方式
TYPE_RESERVED(255): 未知方式
redirectCount: 重定向次数
img
,oframe
,body
img
,oframe
,body
p.info = function(){
alert(this.name);
}
document.getElementById("bt").onclick = p.info//this指向‘bt‘控件
document.getElementById("bt").onclick = new function (){ p.info();} //this总是指向p
注意表单设置id为x和name为y时候,相当于表单创建了x属性和y属性,所以id和name不能是关键字submit等
创建监听事件
objectTarget.addEventListener(“eventType”,handler,capture),第一个参数表示绑定的事件,如click、keypress之类的,第二个制定绑定的函数,第3个位boolean,true表示监听捕获阶段,false表示监听冒泡阶段
objectTarget.removeEventListener(“eventType”,handler,captureFlag): 删除绑定事件
捕获状态阶段的绑定事件先执行,事件冒泡状态阶段的绑定事件后执行. 捕获状态阶段从外往内触发,事件冒泡状态阶段从内往外触发.
绑定例子
var got_click = function (event){
for ( event_one in event){
alert(event_one + " : " + event[event_one]);
}
}
document.getElementByID("test").addEventListener("cilck",got_click,true);
阻止事件传播
event.stopPropagation();
取消事件的默认行为,如跳转页面等,但不会阻止事件传播.
event.preventDefault();
DOM提供了dispathEvent方法用于事件转发,该方法属于Node
target.dispathEvent(Event event),将event转发到target上
DOM的dispath()必须转发人工合成的Event事件
document.createEvent(String type),tpy参数用于指定事件类型,eg:普通事件Events,UI事件UIEvents,鼠标事件:MouseEvents
初始化事件
initEvent(具体参数...)
initUIEvent(具体参数...)
intMouseEvent(具体参数...)
//例子
<input id="bt1">
<input id="bt2">
...
var rd =function(evt){
alert("事件冒泡阶段: " + evt.currentTarget.value +"被点击了");
var e =document.createEvent("Evnets");
e.initEvent("click",true,false);//true表示是否支持冒泡,false表示是否有默认行为
document.getElementById("bn2").dispathEvent(e);
}
var go_click = function (evt){
alert("事件冒泡阶段: " + evt.currentTarget.value);
}
document.getElementById("bn1").addEventListener("click",rd,false);
document.getElementById("bn2").addEventListener("click",go_click,false);;
//点解按钮一结果
alert(事件冒泡阶段: 按钮一被点击了);
alert(事件冒泡阶段:按钮2);
点击按钮1,按钮执行了前面按钮一被点击了提示语句后,将点击事件转给了按钮2,按钮2执行自身的点击事件.
使用理由之一Cookie的局限性:
Web Storage分两种
Session Storage: 生命周期与用户Session一致(用户Session是指:用户从访问网址到离开网址/关闭浏览器)
Local Storage: 保存在用户的磁盘中,失效的方式为用户/程序显示删除.
Web Storage的方法有
Web Storage包含在window对象中
当value为对象时,建议用JSON存储
在html标签中修改
//表明该页使用index.manifest文件
<html manifest="index.manifest">
index.mainfest文件
CACHE MANIFEST
//第一行必须为上述字符
//指定版本号
#version 1
//本地缓存资源
CACHE
inedx.html
logo.jpg
//不缓存的资源
NETWORK
*
//前者表示在线状态使用的资源,后者代表离线状态使用的资源
FALLBACK
test.js offline.js
Tomcat为例,天津映射文件
<!--conf的web.xml根元素中增加MIME映射-->
<mine-mapping>
<extension>manifest</extension>
<mine-type>text/cache-mainfest</mime-type>
</mime-mapping>
启动应用后,页面可刷新(即使离线状态),并使用离线时候的资源
navigator.onLine属性: true表示在线
online/offline事件: 当在线/离线状态切换时,body上的online/offine事件会被触发,沿着document.body、document和window冒泡
window.addEventListener("offline",function(){
alert("离线状态")
},true);
if(navigator.onLine){
alert("在线");
}
js可通过applicationCache控制离线缓存.
status属性:
常用方法
void swapCache(): 更新缓存,只能在applicationCache的updateReady事件被触发时调用.
setInterval(function(){
applicationCache.update()
},2000);
applicationCache.onupdateready = function(){
if(confirm("已从远程服务器下载了需要的缓存,是否更新?")){
applicationCache.swapCache();
location.reload();
}
}
访问html页面过程
当用户再访问index.html时,前面1~5完全相同,接下来检测mainfest文件是否有改变.
worker中无法使用DOM、alert等与界面有关的操作.
使用理由:防止js阻塞主线程的js运行
WorkerAPI
写一段找出输入start和end之间素数的线程.
worker.js代码
onmessage =function(event){
var data =JSON.parse(event.data);
var start =data.start;
var end =data.end;
var result ="";
search:
for (var n =start; n <= end :n++){
if(n%i==0){
continue search;
}
result +=(n+",");
}
}
postMessage(result);
网页代码
<input name="start" ...>
<input name="end" ...>
<input type=button inclick="cal();" ...>
...
var car =function(){
var start = parseInt(document.getElementById("start").value);
var end = parseInt(document.getElementById("end").value);
//创建线程
var cal = new Worker("worker.js");
var data ={
"start" : srart,
"end" : end
};
//发送数据
cal.postMessage(JSON.stringify(data));
cal.onmessage = function (evnet){
alert(event);
}
}
并行的两条Worker不能互相通信,但Wroker可嵌套.
WebSocket: 服务器主动推送信息/客户端实时推送数据到服务器
window对象新增方法
onmessage: 调用方法:windows.onmessage =function(event){…}
event中的属性:
html想发送要做
html想接收要做
跨文档消息传递
//source.html
var targetWin = window.open("接收方url",‘_blank‘,‘windth=400,height=300‘);
targetWin.onload =function(){
targetWin.postMessage("传输消息","接收方域名");
}
window.onmessage =function(event){
//忽略其他域名发送的消息
if(event.orgin !="指定域名"){
return ;
}
alert(event.data);
}
//接收页面.html
window.onmessage = function(event){
//忽略其他域名发送的消息
if(event.orgin !="指定域名"){
return ;
}
alert("接收到消息拉!"+event.data);
event.source.postMessage("回传消息",event.origin);
}
结果:
alert(接收到消息拉!传输消息);
alert(回传消息);
注意!一定要判断发送方的域名!!!!!一定要判断发送方的域名!!!!!一定要判断发送方的域名!!!!!
以前方案:
WebSocket方法
WebSocket监听事件
WebSocket属性
readyState
1.1 CONNECTING(0): WebSocket正在尝试连接
1.2 OPEN(1): 已经连接
1.3 CLOSING(2): 正在关闭连接
1.4 CLOSED(3): 已经关闭连接
WebSocket与服务器通信步骤
实现客户端多人聊天,JAVA为例
客户端代码:
var web_socket =new WebSocket("ws://域名:端口");
web_socket.onopen =function(){
web_socket.onmessage =function(event){
document.getElementById(‘show‘).innerHTML += event.data +"</br>"
}
};
var sendMsg =function(val){
var inputElement = document.getElementByID(‘msg‘);
webSocket.send(inputElement.value);
inputElement.value="";
}
...
服务端代码
import java.io.*;
import java.net.*;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.regex.*;
import java.util.*;
import sun.misc.BASE64Encoder;
public class ChatServer
{
// 记录所有的客户端Soccket
public static List<Socket> clientSockets
= new ArrayList<Socket>();
public ChatServer()throws IOException
{
// 创建ServerSocket,准备接受客户端连接
ServerSocket ss = new ServerSocket(30000);
while(true)
{
// 接收到客户端连接
Socket socket = ss.accept();
// 将客户端Socket添加到clientSockets集合中
clientSockets.add(socket);
// 启动线程
new ServerThread(socket).start();
}
}
public static void main(String[] args)
throws Exception{
new ChatServer();
}
}
class ServerThread extends Thread
{
private Socket socket;
public ServerThread(Socket socket)
{
this.socket = socket;
}
public void run()
{
try
{
// 得到Socket对应的输入流
InputStream in = socket.getInputStream();
// 得到Socket对应的输出流
OutputStream out = socket.getOutputStream();
byte[] buff = new byte[1024];
String req = "";
// 读取数据,此时建立与WebSocket的"握手"。
int count = in.read(buff);
// 如果读取的数据长度大于0
if(count > 0)
{
// 将读取的数据转化为字符串
req = new String(buff , 0 , count);
System.out.println("握手请求:" + req);
// 获取WebSocket的key
String secKey = getSecWebSocketKey(req);
System.out.println("secKey = " + secKey);
String response = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: "
+ "websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "
+ getSecWebSocketAccept(secKey) + "\r\n\r\n";
System.out.println("secAccept = " + getSecWebSocketAccept(secKey));
out.write(response.getBytes());
}
int hasRead = 0;
// 不断读取WebSocket发送过来的数据
while((hasRead = in.read(buff)) > 0){
System.out.println("接收的字节数:" + hasRead);
/*
因为WebSocket发送过来的数据遵循了一定的协议格式,
其中第3个?第6个字节是数据掩码。
从第7个字节开始才是真正的有效数据。
因此程序使用第3个?第6个字节对后面的数据进行了处理
*/
for (int i = 0 ; i < hasRead - 6 ; i++ ){
buff[i + 6] = (byte) (buff[i % 4 + 2] ^ buff[i + 6]);
}
// 获得从浏览器发送过来的数据
String pushMsg = new String(buff
, 6 , hasRead - 6 , "UTF-8");
// 遍历Socket集合,依次向每个Socket发送数据
for (Iterator<Socket> it = ChatServer.clientSockets.iterator()
; it.hasNext() ;)
{
try
{
Socket s = it.next();
// 发送数据时,第一个字节必须与读到的第一个字节相同
byte[] pushHead = new byte[2];
pushHead[0] = buff[0];
// 发送数据时,第二个字节记录发送数据的长度
pushHead[1] = (byte) pushMsg.getBytes("UTF-8").length;
// 发送前两个字节
s.getOutputStream().write(pushHead);
// 发送有效数据
s.getOutputStream().write(pushMsg.getBytes("UTF-8"));
}
catch (SocketException ex)
{
// 如果捕捉到异常,表明该Socket已经关闭
// 将该Socket从Socket集合中删除
it.remove();
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
try
{
// 关闭Socket
socket.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
// 获取WebSocket请求的SecKey
private String getSecWebSocketKey(String req)
{
//构建正则表达式,获取Sec-WebSocket-Key: 后面的内容
Pattern p = Pattern.compile("^(Sec-WebSocket-Key:).+",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
Matcher m = p.matcher(req);
if (m.find())
{
// 提取Sec-WebSocket-Key
String foundstring = m.group();
return foundstring.split(":")[1].trim();
}
else
{
return null;
}
}
// 根据WebSocket请求的SecKey计算SecAccept
private String getSecWebSocketAccept(String key)
throws Exception
{
String guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
key += guid;
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(key.getBytes("ISO-8859-1") , 0 , key.length());
byte[] sha1Hash = md.digest();
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(sha1Hash);
}
}
标签:
原文地址:http://www.cnblogs.com/liujiale/p/5520923.html