《JavaScript高级程序设计(第3版)》10-23章总结
《JavaScript高级程序设计(第3版)》10-23章总结
DOM(文档对象模型)是针对 HTML 和 XML 文档的一个 API(应用程序编程接口)。 DOM描绘了一个层次化的节点树,允许开发人员添加、移除和修改页面的某一部分。
console.log(Node.prototype) //打印出来看看就好,别记
console.log(Document.prototype)
console.log(Element.prototype)
console.log(Text.prototype)
console.log(Comment.prototype)
console.log(DocumentType.prototype)
console.log(DocumentFragment.prototype)
console.log(CDATASection.prototype)
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "client.js";
document.body.appendChild(script);
封装:
function loadScript(url){
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
document.body.appendChild(script);
}
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = "style.css";
var head = document.getElementsByTagName("head")[0];
head.appendChild(link);
封装:
function loadStyles(url){
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = url;
var head = document.getElementsByTagName("head")[0];
head.appendChild(link);
}
略
var divs = document.getElementsByTagName("div");
console.log(divs)
Selectors API Level 1 的核心是两个方法:querySelector()和 querySelectorAll()。
//取得 body 元素
var body = document.querySelector("body");
//取得 ID 为"myDiv"的元素
var myDiv = document.querySelector("#myDiv");
//取得类为"selected"的第一个元素
var selected = document.querySelector(".selected");
//取得类为"button"的第一个图像元素
var img = document.body.querySelector("img.button");
//取得某<div>中的所有<em>元素(类似于 getElementsByTagName("em"))
var ems = document.getElementById("myDiv").querySelectorAll("em");
//取得类为"selected"的所有元素
var selecteds = document.querySelectorAll(".selected");
//取得所有<p>元素中的所有<strong>元素
var strongs = document.querySelectorAll("p strong");
略
var i,
len,
child = element.firstElementChild;
while(child != element.lastElementChild){
processChild(child); //已知其是元素
child = child.nextElementSibling;
}
// 取得所有类中包含"username"和"current"的元素,类名的先后顺序无所谓
document.getElementsByClassName("username current")
var div = document.querySelector('.c-tips-container');
div.classList.add('current') // 添加class
var input = document.querySelector('#kw');
input.focus();
console.log(document.activeElement === input,document.hasFocus()) // true, false
并没有像书上所说document.hasFocus()返回true。console.log(document.readyState) // "complete"(可以判断文档是否加载完毕,返回值有complete和loading)
console.log(document.compatMode) // "CSS1Compat"(CSS1Compat表示标准模式,BackCompat表示混杂模式)
console.log(document.head) // <head>...</head>
console.log(document.charset) // "UTF-8"
//让元素可见
document.forms[0].scrollIntoView();
略
var myDiv = document.getElementById("su");
//设置背景颜色
myDiv.style.backgroundColor = "red";
//改变大小
myDiv.style.width = "100px";
myDiv.style.height = "200px";
//指定边框
myDiv.style.border = "1px solid black";
console.log(myDiv.style) // 略
console.log(myDiv.style.cssText) // 'background-color: red; width: 100px; height: 200px; border: 1px solid black;'
1、 DOM样式属性和方法 cssText: 访问style特性中的css代码 length: css属性数量 parentRule:cssRule对象 getPropertyCSSValue(propertyName): 返回属性值的CSSValue对象 //经我实验,已经删除该属性 getPropertyPriority(propertyName):设置了"!important"返回"import",否则返回空字符串。 getPropertyValue(propertyName):返回给定属性的字符串值。 item(index):返回给定位置的 CSS 属性的名称。 removeProperty(propertyName):从样式中删除给定属性。 setProperty(propertyName,value,priority):将给定属性设置为相应的值,并加上优先权标志("important"或者一个空字符串)。
var myDiv = document.getElementById("su");
myDiv.style.color = "red";
myDiv.style.cssText = "width: 25px !important; height: 100px; background-color: green";
console.log(myDiv.style.cssText) // height: 100px; background-color: green; width: 25px !important;(会把原来属性覆盖,不建议使用,例如前面的color)
console.log(myDiv.style.length) // 3
console.log(myDiv.style.parentRule) // null
console.log(myDiv.style.getPropertyPriority("width")) // "important"
console.log(myDiv.style.getPropertyValue("width")) // "25px"
console.log(myDiv.style.item(1)) // "background-color"
myDiv.style.removeProperty("height")
console.log(myDiv.style.cssText) // "background-color: green; width: 25px !important;" (height被删除了)
myDiv.style.setProperty("height","200px","important")
console.log(myDiv.style.cssText) // "background-color: green; width: 25px !important; height: 200px !important;"(height被添加了)
2、计算的样式 document.defaultView.getComputedStyle():要取得计算样式的元素和一个伪元素字符串(例如":after")
var myDiv = document.getElementById("su");
var computedStyle = document.defaultView.getComputedStyle(myDiv, null);
console.log(computedStyle.width) // "100px"(返回层叠后的最终样式)
console.log(myDiv.style.width) // “25px"(返回style中的样式)
function getStyleSheet(element){
return element.sheet || element.styleSheet;
}
//取得第一个<link/>元素引入的样式表
var link = document.getElementsByTagName("link")[0];
var sheet = getStyleSheet(link);
function insertRule(sheet, selectorText, cssText, position){
if (sheet.insertRule){
sheet.insertRule(selectorText + "{" + cssText + "}", position);
} else if (sheet.addRule){
sheet.addRule(selectorText, cssText, position);
}
}
//增加规则
insertRule(document.styleSheets[0], "body", "background-color: silver", 0);
function deleteRule(sheet, index){
if (sheet.deleteRule){
sheet.deleteRule(index);
} else if (sheet.removeRule){
sheet.removeRule(index);
}
}
//删除
deleteRule(document.styleSheets[0], 0);
1、偏移量 offsetHeight、offsetWidth、offsetLeft、offsetTop
var myDiv = document.getElementById("su");
console.log(myDiv.offsetHeight) // 44(元素垂直方向占据空间大小,包括左右10px边框)
console.log(myDiv.offsetWidth) // 128(元素水平方向占据空间大小,包括左右10px边框)
console.log(myDiv.offsetLeft) // 0
console.log(myDiv.offsetTop) // 0
2、客户区大小 元素的客户区大小(client dimension),指的是元素内容及其内边距所占据的空间大小
var myDiv = document.getElementById("su");
console.log(myDiv.clientWidth) // 108(元素垂直方向占据空间大小,包括边框)
console.log(myDiv.clientHeight) // 44(元素水平方向占据空间大小,包括边框)
获取浏览器视口
function getViewport(){
if (document.compatMode == "BackCompat"){
return {
width: document.body.clientWidth,
height: document.body.clientHeight
};
} else {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
};
}
}
getViewport() // {width: 1090, height: 920}
3、滚动大小 scrollHeight、scrollWidth、scrollLeft、scrollTop
var myDiv = document.getElementById("sull");
console.log(myDiv.scrollLeft) // 32
console.log(myDiv.scrollHeight) // 64
console.log(myDiv.scrollWidth) // 128
console.log(myDiv.scrollTop) // 37
myDiv.scrollTop =0; // 滚动条移动到顶部
4、确定元素大小 略
var div = document.getElementById("sull");
var iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT, null, false);
var node = iterator.nextNode();
while (node !== null) {
console.log(node.tagName); //输出标签名
node = iterator.nextNode();
}
// 输出 SPAN INPUT
只遍历其中的li元素
var div = document.getElementById("form");
var filter = function(node){
return node.tagName.toLowerCase() == "li" ?
NodeFilter.FILTER_ACCEPT :
NodeFilter.FILTER_SKIP;
};
var iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT,
filter, false);
var node = iterator.nextNode();
while (node !== null) {
console.log(node.tagName); //输出标签名
node = iterator.nextNode();
}
// 输出 LI LI LI LI
var div = document.getElementById("form");
var filter = function(node){
return node.tagName.toLowerCase() == "li"?
NodeFilter.FILTER_ACCEPT :
NodeFilter.FILTER_SKIP;
};
var iterator= document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT,
filter, false);
var node = iterator.nextNode();
while (node !== null) {
console.log(node.tagName); //输出标签名
node = iterator.nextNode();
}
// LI LI LI LI
var div = document.getElementById("head");
var walker = document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT, null, false);
walker.firstChild(); //第一个子元素
walker.nextSibling(); //下一个兄弟元素
var node = walker.firstChild(); //第一个子元素
while (node !== null) {
console.log(node.tagName);
node = walker.nextSibling();
}
略
IE 的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。从里面往外面冒泡,记忆IE处理事情总是冒冒失失的。直至传播到 document 对象
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body onclick="handleClick('2')" style="height: 100%; width: 100%; background-color: green">
<div style="height: 100px; width: 100px; background-color: yellow" onclick="handleClick('1')">
<div style="height: 50px; width: 50px; background-color: red" onclick="handleClick('0')"></div>
</div>
</body>
<script>
function handleClick(type){
console.log(type)
}
</script>
</html>
点击红色方块输出 0 1 2
在事件捕获过程中,document 对象首先接收到 click 事件,然后事件沿 DOM 树依次向下,一直传播到事件的实际目标,即
先捕获(用于拦截事件),再冒泡
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body onclick="handleClick('2')" style="height: 100%; width: 100%; background-color: green">
<div style="height: 100px; width: 100px; background-color: yellow" onclick="handleClick('1')">
<div style="height: 50px; width: 50px; background-color: red" onclick="handleClick('0')"></div>
</div>
</body>
<script>
function handleClick(type){
console.log(type)
}
</script>
</html>
事件处理程序的名字以"on"开头,因此click 事件的事件处理程序就是 onclick,load 事件的事件处理程序就是 onload。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<input type="button" value="Click Me" onclick="showMessage()" />
<input type="button" value="Click Me" onclick="console.log('Hello world!');" />
</body>
<script type="text/javascript">
function showMessage(){
console.log("Hello world!");
}
</script>
</html>
// 点击都输出 "hello world!"
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<input type="button" value="Click Me" id="btn"/>
</body>
<script type="text/javascript">
function showMessage(){
console.log(this.id);
}
var btn = document.getElementById('btn');
btn.onclick = showMessage;
</script>
</html>
// 点击输出 "btn"
btn.onclick = null; //删除事件处理程序
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<input type="button" value="Click Me" id="btn"/>
</body>
<script type="text/javascript">
function showMessage(){
console.log(this.id);
}
var btn = document.getElementById('btn');
btn.addEventListener("click",showMessage,false) //
</script>
</html>
// 点击输出 "btn"
都接受 3 个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是 true,表示在捕获阶段调用事件处理程序;如果是 false,表示在冒泡阶段调用事件处理程序。当然一般传false。 btn.removeEventListener("click",showMessage,false) // 移除监听 注意: 匿名函数无法移除监听
var btn = document.getElementById("myBtn");
btn.addEventListener("click", function(){
console.log(this.id);
}, false);
//这里省略了其他代码
btn.removeEventListener("click", function(){ //没有用!
console.log(this.id);
}, false);
经我测试ie8以下addEventListener不起作用。不过一般都不用兼容ie8了吧。
IE总是特立独行,在此就略过了。
在触发 DOM 上的某个事件时,会产生一个事件对象 event,这个对象中包含着所有与事件有关的信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。
兼容 DOM 的浏览器会将一个 event 对象传入到事件处理程序中。无论指定事件处理程序时使用什么方法(DOM0 级或 DOM2 级),都会传入 event 对象。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<input type="button" value="Click Me" id="btn"/>
</body>
<script type="text/javascript">
function show(){
console.log(this.id);
}
var btn = document.getElementById("btn");
btn.onclick = function(event){
console.log(event.type); //"click"
};
btn.addEventListener("click", function(event){
console.log(event.type); //"click"
}, false);
</script>
</html>
在事件处理程序内部,对象 this 始终等于 currentTarget 的值,而 target 则只包含事件的实际目标。如果直接将事件处理程序指定给了目标元素,则 this、currentTarget 和 target 包含相同的值。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<input type="button" value="Click Me" id="btn"/>
</body>
<script type="text/javascript">
function show(){
console.log(this.id);
}
var btn = document.getElementById("btn");
btn.onclick = function(event){
console.log(event.currentTarget === this); //true
console.log(event.target === this); //true
};
</script>
</html>
如果把处理程序存于父节点中例如body上,则event.currentTarget和tartget不一样
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<input type="button" value="Click Me" id="btn"/>
</body>
<script type="text/javascript">
var btn = document.getElementById("btn");
document.body.onclick = function(event){
console.log(event.currentTarget === document.body); //true
console.log(this === document.body); //true
console.log(event.target === document.getElementById("btn")); //true
};
</script>
</html>
阻止默认事件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<a href="http://baidu.com" id="myLink">点我去百度</a>
</body>
<script type="text/javascript">
var link = document.getElementById("myLink");
link.onclick = function(event){
event.preventDefault(); // 成功阻止了跳转
};
</script>
</html>
阻止冒泡
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<input value="点击" id="btn" type="button"/>
</body>
<script type="text/javascript">
var btn = document.getElementById("btn");
btn.onclick = function(event){
event.stopPropagation();
console.log("取消冒泡")
};
document.body.onclick = function (){
console.log('来不到这里了')
}
</script>
</html>
判断事件的阶段
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<input value="点击" id="btn" type="button"/>
</body>
<script type="text/javascript">
var btn = document.getElementById("btn");
btn.onclick = function(event){
console.log(event.eventPhase); //2
};
document.body.addEventListener("click", function(event){
console.log(event.eventPhase); //1
}, true);
document.body.addEventListener("click", function(event){
console.log(event.eventPhase); //3
}, false);
document.body.onclick = function(event){
console.log(event.eventPhase); //3
};
</script>
</html>
事件委托
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<ul onclick="handler(event)">
<li id="1">1</li>
<li id="2">2</li>
<li id="3">3</li>
<li id="4">4</li>
<li id="5">5</li>
<li id="6">6</li>
</ul>
</body>
<script type="text/javascript">
function handler(event){
var target = event.target // 这里保存着点击元素的信息,例如可以访问id,这样可以减少事件的绑定
console.log(target.id)
}
</script>
</html>
btn.onclick = null; //移除事件处理程序
模拟点击事件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<input value="点击" id="btn" type="button"/>
</body>
<script type="text/javascript">
var fn = function(){
console.log('button was clicked'); // 此函数通过事件的方式被调用
}
var btn = document.getElementById('btn');
btn.addEventListener('click', fn);
// 点击事件 MouseEvent
var mouseClick = document.createEvent('MouseEvent');
mouseClick.initMouseEvent('click', false, false, null);
// 执行
btn.dispatchEvent(mouseClick); // 'click'
</script>
</html>
action:接受请求的 URL;等价于 HTML 中的 action 特性。 elements:表单中所有控件的集合(HTMLCollection)。 length:表单中控件的数量。 method:要发送的 HTTP 请求类型,通常是"get"或"post";等价于 HTML 的 method 特性。 name:表单的名称;等价于 HTML 的 name 特性。 reset():将所有表单域重置为默认值。 submit():提交表单。 target:用于发送请求和接收响应的窗口名称;等价于 HTML 的 target 特性。
var form = document.getElementById("form");
console.log(document.forms[0] == form) // true
console.log(document.forms['form'] == form) // true
可以通过document.forms索引或name来获取特定表单
<!-- 通用提交按钮 -->
<input type="submit" value="Submit Form">
<!-- 自定义提交按钮 -->
<button type="submit">Submit Form</button>
禁止表单提交
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<form method="get" name='form' action="https://www.baidu.com" id="form"><input type="text" name="name"/><button type="submit">提交</button></form>
</body>
<script type="text/javascript">
var form = document.getElementById('form')
form.onsubmit = function(event){
event.preventDefault() // 禁止默认事件或者,return false
//return false
}
</script>
</html>
手动提交表单
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<form method="get" name='form' action="https://www.baidu.com" id="form"><input type="text" name="name"/><button type="submit">提交</button></form>
</body>
<script type="text/javascript">
var form = document.getElementById('form')
form.onsubmit = function(event){
alert('进来了') //没有alert不会触发onsubmit事件
}
form.submit()
</script>
</html>
<!-- 通用重置按钮 -->
<input type="reset" value="Reset Form">
<!-- 自定义重置按钮 -->
<button type="reset">Reset Form</button>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<form method="get" name='form' action="https://www.baidu.com" id="form"><input type="text" name="name"/><button type="submit">提交</button></form>
</body>
<script type="text/javascript">
var form = document.getElementById("form");
form.onreset = function(){
alert('重置了') //弹出alert
}
//重置表单
form.reset();
</script>
</html>
会触发onreset函数!
console.log(form.elements['name']) //输出 <input type="text" name="name"/>
console.log(form.elements['name'].value) // 输出你输入的值
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<textarea rows="25" cols="25" id="textarea"></textarea>
</body>
<script type="text/javascript">
function getSelectedText(textbox){
return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd); // 获取选中的字
}
var textarea = document.getElementById('textarea');
textarea.onselect = function(){
console.log(getSelectedText(textarea)) // 输出选中的字
}
</script>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<textarea rows="25" cols="25" id="textarea"></textarea>
</body>
<script type="text/javascript">
var textarea = document.getElementById('textarea');
textarea.onkeypress = function(event){
console.log(/[\d.]/.test(String.fromCharCode(event.keyCode)))
if(!/\d/.test(String.fromCharCode(event.keyCode))){
event.preventDefault()
}
}
</script>
</html>
过滤非数字字符
var textbox1 = document.getElementById("txtTel1");
textbox1.focus()
增加类型和必填检测
<input type="email" name="username" required>
数值范围
<input type="number" min="0" max="100" step="5" name="count">
输入模式
<input type="text" pattern="\d+" name="count">
检测有效性:使用 checkValidity() 对表单内某个元素使用
if (document.forms[0].elements[0].checkValidity()){
//字段有效,继续
} else {
//字段无效
}
对整个表单使用
if(document.forms[0].checkValidity()){
//表单有效,继续
} else {
//表单无效
}
例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<form onsubmit="handleSumbit(event)" name="form" id="form">
<input type="text" pattern="\d+" name="count">
<input type="email" name="email">
<button type="submit">提交</button>
</form>
</body>
<script type="text/javascript">
function handleSumbit(event){
event.preventDefault()
console.log(document.forms['form'].elements['count'].checkValidity())
console.log(document.forms['form'].checkValidity())
}
</script>
</html>
输入数字或者不输入点击时两个都返回true 禁用验证
<form method="post" action="signup.php" novalidate>
<!--这里插入表单元素-->
</form>
var selectedOption = selectbox.options[selectbox.selectedIndex];
文本selectedOption.text 值selectedOption.value 设置选项为true selectbox.options[0].selected = true;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<select id="selectbox">
<option value="1">one</option>
<option value="2">two</option>
<option value="3">three</option>
</select>
</body>
<script type="text/javascript">
var selectbox = document.getElementById('selectbox');
selectbox.options[0].selected = true;
var selectedOption = selectbox.options[selectbox.selectedIndex];
console.log(selectedOption.text,selectedOption.value) // "one" "1"
selectbox.options[1].selected = true;
var selectedOption = selectbox.options[selectbox.selectedIndex];
console.log(selectedOption.text,selectedOption.value) // "two" "2"
</script>
</html>
单选时js代码重新选中时,会导致原来的默认被取消,不需要手动取消。 多选时,需要遍历输出每一项
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<select id="selectbox" multiple>
<option value="1">one</option>
<option value="2">two</option>
<option value="3">three</option>
</select>
</body>
<script type="text/javascript">
var selectbox1 = document.getElementById('selectbox');
selectbox1.options[0].selected = true;
selectbox1.options[1].selected = true;
function getSelectedOptions(selectbox){
var result = new Array();
var option = null;
for (var i=0, len=selectbox.options.length; i < len; i++){
option = selectbox.options[i];
if (option.selected){
result.push(option);
}
}
return result;
}
console.log(getSelectedOptions(selectbox1))
</script>
</html>
var newOption = document.createElement("option");
newOption.appendChild(document.createTextNode("Option text"));
newOption.setAttribute("value", "Option value");
selectbox.appendChild(newOption);
var newOption = new Option("Option text", "Option value");
selectbox.add(newOption, undefined); //最佳方案
selectbox.removeChild(selectbox.options[0]);
selectbox.remove(0); //移除第一个选项
selectbox.options[0] = null; //移除第一个选项
选项复制到另一个选中框
var selectbox1 = document.getElementById("selLocations1");
var selectbox2 = document.getElementById("selLocations2");
selectbox2.appendChild(selectbox1.options[0]);
var optionToMove = selectbox.options[1];
selectbox.insertBefore(optionToMove, selectbox.options[optionToMove.index+2]); //+2才向后移动一个位置
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<form id="form">
<input type="text" name="input"/>
<select id="selectbox" multiple name="select">
<option value="1">one</option>
<option value="2">two</option>
<option value="3">three</option>
</select>
<input type="radio" name="sex" value="1" checked="checked">男
<input type="radio" name="sex" value="2">女
<input type="checkbox" name="vote">同意
<button type="submit">提交</button>
</form>
</body>
<script type="text/javascript">
function serialize(form) {
var parts = [],
field = null,
i,
len,
j,
optLen,
option,
optValue;
for (i = 0, len = form.elements.length; i < len; i++) {
field = form.elements[i];
switch (field.type) {
case "select-one":
case "select-multiple":
if (field.name.length) {
for (j = 0, optLen = field.options.length; j < optLen; j++) {
option = field.options[j];
if (option.selected) {
optValue = "";
if (option.hasAttribute) {
optValue = (option.hasAttribute("value") ?
option.value : option.text);
} else {
optValue = (option.attributes["value"].specified ?
option.value : option.text);
}
parts.push(encodeURIComponent(field.name) + "=" +
encodeURIComponent(optValue));
}
}
}
break;
case undefined: //字段集
case "file": //文件输入
case "submit": //提交按钮
case "reset": //重置按钮
case "button": //自定义按钮
break;
case "radio": //单选按钮
case "checkbox": //复选框
if (!field.checked) {
break;
}
/* 执行默认操作 */
default:
//不包含没有名字的表单字段
if (field.name.length) {
parts.push(encodeURIComponent(field.name) + "=" +
encodeURIComponent(field.value));
}
}
}
return parts.join("&");
}
var form1 = document.getElementById('form')
form1.onsubmit = function(event){
event.preventDefault();
console.log(serialize(form1)) // 'input=fdfdd&select=3&sex=2&vote=on'(序列化了)
}
</script>
</html>
JSON语法可以表示以下类型的值: 简单值、对象、数组。
JSON表示数值5: 5 JSON表示字符串的方式:‘lzw’
{
"name": "Nicholas",
"age": 29,
"school": {
"name": "Merrimack College",
"location": "North Andover, MA"
}
}
[
{
"title": "Professional JavaScript",
"authors": [
"Nicholas C. Zakas"
],
edition: 3,
year: 2011
},
{
"title": "Professional JavaScript",
"authors": [
"Nicholas C. Zakas"
],
edition: 2,
year: 2009
}
]
var book = {
title: "Professional JavaScript",
authors: [
"Nicholas C. Zakas"
],
edition: 3,
year: 2011
};
var jsonText = JSON.stringify(book);
console.log(jsonText) // {"title":"Professional JavaScript","authors":["Nicholas C. Zakas"],"edition":3,"year":2011}
var bookCopy = JSON.parse(jsonText);
console.log(bookCopy) // {title: "Professional JavaScript", authors: Array(1), edition: 3, year: 2011}
可用于深拷贝对象 值为undefined的属性会被忽略
var book = {
title: "Professional JavaScript",
authors: [
"Nicholas C. Zakas"
],
edition: 3,
year: 2011,
price: undefined,
storage: null
};
var jsonText = JSON.stringify(book);
console.log(jsonText) // {"title":"Professional JavaScript","authors":["Nicholas C. Zakas"],"edition":3,"year":2011,"storage":null}(undefined属性值消失了)
1、过滤结果
var book = {
"title": "Professional JavaScript",
"authors": [
"Nicholas C. Zakas"
],
edition: 3,
year: 2011
};
var jsonText = JSON.stringify(book, ["title", "edition"]);
console.log(jsonText) // {"title":"Professional JavaScript","edition":3}(只输出数组里含有的属性)
第二个参数为函数时
var book = {
"title": "Professional JavaScript",
"authors": [
"Nicholas C. Zakas"
],
edition: 3,
year: 2011
};
var jsonText = JSON.stringify(book, function(key, value){
switch(key){
case "authors":
return value.join(",")
case "year":
return 5000;
case "edition":
return undefined;
default:
return value;
}
});
console.log(jsonText) // {"title":"Professional JavaScript","authors":"Nicholas C. Zakas","year":5000} (undefined依然会被忽略)
toJson方法
var book = {
"title": "Professional JavaScript",
"authors": [
"Nicholas C. Zakas"
],
edition: 3,
year: 2011,
toJSON: function(){
return this.title;
}
};
var jsonText = JSON.stringify(book);
console.log(jsonText) // "Professional JavaScript"
JOSON.parse()
var book = {
"title": "Professional JavaScript",
"authors": [
"Nicholas C. Zakas"
],
edition: 3,
year: 2011,
releaseDate: new Date(2011, 11, 1)
};
var jsonText = JSON.stringify(book);
var bookCopy = JSON.parse(jsonText, function(key, value){
if (key == "releaseDate"){
return new Date(value);
} else {
return value;
}
});
console.log(jsonText) // {"title":"Professional JavaScript","authors":["Nicholas C. Zakas"],"edition":3,"year":2011,"releaseDate":"2011-11-30T16:00:00.000Z"}
console.log(bookCopy) // {title: "Professional JavaScript", authors: Array(1), edition: 3, year: 2011, releaseDate: Thu Dec 01 2011 00:00:00 GMT+0800 (中国标准时间)}
function createXHR(){
if (typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest();
} else if (typeof ActiveXObject != "undefined"){
if (typeof arguments.callee.activeXString != "string"){
var versions = [ "MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
"MSXML2.XMLHttp"],
i, len;
for (i=0,len=versions.length; i < len; i++){
try {
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (ex){
//跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error("No XHR object available.");
}
}
var xhr = createXHR();
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
console.log(xhr.responseText);
} else {
console.log("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get", "example.txt", true);
xhr.send(null);
在使用 XHR 对象时,要调用的第一个方法是 open(),它接受 3 个参数:要发送的请求的类型("get"、"post"等)、请求的 URL 和表示是否异步发送请求的布尔值。 要发送特定的请求,必须像下面这样调用 send()方法:
xhr.open("get", "example.txt", false);
xhr.send(null);
由于这次请求是同步的,JavaScript 代码会等到服务器响应之后再继续执行。 XHR 对象的属性 responseText:作为响应主体被返回的文本。 responseXML:如果响应的内容类型是"text/xml"或"application/xml",这个属性中将保 存包含着响应数据的 XML DOM 文档。 status:响应的 HTTP 状态。 statusText:HTTP 状态的说明。 XHR 对象的 readyState 属性 0:未初始化。尚未调用 open()方法。 1:启动。已经调用 open()方法,但尚未调用 send()方法。 2:发送。已经调用 send()方法,但尚未接收到响应。 3:接收。已经接收到部分响应数据。 4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了。
xhr.abort();//停止请求
Accept:浏览器能够处理的内容类型。 Accept-Charset:浏览器能够显示的字符集。 Accept-Encoding:浏览器能够处理的压缩编码。 Accept-Language:浏览器当前设置的语言。 Connection:浏览器与服务器之间连接的类型。 Cookie:当前页面设置的任何 Cookie。 Host:发出请求的页面所在的域 。 Referer:发出请求的页面的 URI。注意,HTTP 规范将这个头部字段拼写错了,而为保证与规 范一致,也只能将错就错了。(这个英文单词的正确拼法应该是 referrer。) User-Agent:浏览器的用户代理字符串。
xhr.setRequestHeader("MyHeader", "MyValue"); //自定义头部
添加参数
function addURLParam(url, name, value) {
url += (url.indexOf("?") == -1 ? "?" : "&");
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}
var url = "example.php";
//添加参数
url = addURLParam(url, "name", "Nicholas");
url = addURLParam(url, "book", "Professional JavaScript");
//初始化请求
xhr.open("get", url, false);
function submitData(){
var xhr = createXHR();
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("post", "postexample.php", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var form = document.getElementById("user-info");
xhr.send(serialize(form));
}
var data = new FormData();
data.append("name", "Nicholas"); //添加数据
var form = document.getElementById("user-info");
xhr.send(new FormData(form)); // 发送数据
xhr.onprogress = function(event){
var divStatus = document.getElementById("status");
if (event.lengthComputable){
divStatus.innerHTML = "Received " + event.position + " of " +
event.totalSize +" bytes";
}
};
function createCORSRequest(method, url){
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr){
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined"){
xhr = new XDomainRequest();
xhr.open(method, url); } else {
xhr = null;
}
return xhr;
}
var request = createCORSRequest("get", "https://www.somewhere-else.com/page/");
if (request){
request.onload = function(){
//对 request.responseText 进行处理
};
request.send();
}
图像ping
var img = new Image();
img.onload = img.onerror = function(){
alert("Done!");
};
img.src = "http://www.example.com/test?name=Nicholas"; // 浏览器服务器单向通信
JSONP
function handleResponse(response){
alert("You’re at IP address " + response.ip + ", which is in " +
response.city + ", " + response.region_name);
}
var script = document.createElement("script");
script.src = "http://freegeoip.net/json/?callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);
console.log(Object.prototype.toString.call([])); //"[object Array]"
console.log(Object.prototype.toString.call('')); // "[object String]"
console.log(Object.prototype.toString.call(/l/)); // "[object RegExp]"
区分原生JSON对象
var isNativeJSON = window.JSON && Object.prototype.toString.call(JSON) == "[object JSON]";
function Person(name, age, job){
if (this instanceof Person){
this.name = name;
this.age = age;
this.job = job;
} else {
return new Person(name, age, job);
}
}
var person1 = Person("Nicholas", 29, "Software Engineer");
console.log(window.name); //""(防止误操作导致往全局添加属性)
console.log(person1.name); //"Nicholas"
作用域安全带来的问题:
function Polygon(sides){
if (this instanceof Polygon) {
this.sides = sides;
this.getArea = function(){
return 0;
};
} else {
return new Polygon(sides);
}
}
function Rectangle(width, height){
Polygon.call(this, 2);
this.width = width;
this.height = height;
this.getArea = function(){
return this.width * this.height;
};
}
Rectangle.prototype = new Polygon(); // 去除该句就没有sides属性,因为this 对象并非 Polygon 的实例
var rect = new Rectangle(5, 1);
console.log(rect.sides); //2
方法一:调用的时候重写,重写后在调用,仅在第一次执行if语句
function createXHR(){
if (typeof XMLHttpRequest != "undefined"){
createXHR = function(){
return new XMLHttpRequest();
};
} else if (typeof ActiveXObject != "undefined"){
createXHR = function(){
if (typeof arguments.callee.activeXString != "string"){
var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
"MSXML2.XMLHttp"],
i, len;
for (i=0,len=versions.length; i < len; i++){
try {
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (ex){
//skip
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
};
} else {
createXHR = function(){
throw new Error("No XHR object available.");
};
}
return createXHR();
}
方法二: 自执行函数返回适当函数
var createXHR = (function(){
if (typeof XMLHttpRequest != "undefined"){
return function(){
return new XMLHttpRequest();
};
} else if (typeof ActiveXObject != "undefined"){
return function(){
if (typeof arguments.callee.activeXString != "string"){
var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
"MSXML2.XMLHttp"],
i, len;
for (i=0,len=versions.length; i < len; i++){
try {
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (ex){
//skip
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
};
} else {
return function(){
throw new Error("No XHR object available.");
};
}
})();
与函数绑定紧密相关的主题是函数柯里化(function currying),它用于创建已经设置好了一个或多个参数的函数。
function add(num1, num2){
return num1 + num2;
}
function curriedAdd(num2){
return add(5, num2); // 指定了第一个参数
}
console.log(add(2, 3)); //5
console.log(curriedAdd(3)); //8
function curry(fn){
var args = Array.prototype.slice.call(arguments, 1);
console.log(args) // [5, 12]
return function(){ // 第二次执行这里,即调用curriedAdd时
var innerArgs = Array.prototype.slice.call(arguments);
console.log(innerArgs); // [3]
var finalArgs = args.concat(innerArgs);
console.log(finalArgs) // [5, 12, 3]
return fn.apply(null, finalArgs);
};
}
function add(num1, num2){
return num1 + num2;
}
var curriedAdd = curry(add, 5, 12);
console.log(curriedAdd(3)); //20
var person = { name: "Nicholas" };
Object.preventExtensions(person);
person.age = 29;
console.log(person.age); //undefined(不可拓展了)
console.log(Object.isExtensible(person)); //false(判断是否可以拓展)
严格模式下
"use strict"
var person = { name: "Nicholas" };
Object.preventExtensions(person);
person.age = 29; // 报错Uncaught TypeError: Cannot add property age, object is not extensible
console.log(person.age);
密封对象不可扩展,而且已有成员的[[Configurable]]特性将被设置为 false。这就意味着不能删除属性和方法,因为不能使用 Object.defineProperty()把数据属性修改为访问器属性,或者相反。但是可以修改。
var person = { name: "Nicholas" };
Object.seal(person);
person.age = 29;
console.log(person.age); //undefined(无法添加)
delete person.name;
console.log(person.name); //"Nicholas"(无法删除)
console.log(Object.isExtensible(person)); //false(不可拓展)
console.log(Object.isSealed(person)); //true(已经密封)
person.name = 'lzw';
console.log(person) // {name: "lzw"}
最严格的防篡改级别是冻结对象(frozen object)。冻结的对象既不可扩展,又是密封的,而且对象数据属性的[[Writable]]特性会被设置为 false。如果定义[[Set]]函数,访问器属性仍然是可写的。
var person = { name: "Nicholas" };
Object.freeze(person);
person.age = 29;
console.log(person.age); //undefined
delete person.name;
console.log(person.name); //"Nicholas"
person.name = "Greg";
console.log(person.name); //"Nicholas"(不能重写了)
console.log(Object.isExtensible(person)); //false
console.log(Object.isSealed(person)); //true
console.log(Object.isFrozen(person)); //true
基本形式:
var processor = {
timeoutId: null,
//实际进行处理的方法
performProcessing: function(){
//实际执行的代码
},
//初始处理调用的方法
process: function(){
clearTimeout(this.timeoutId);
var that = this;
this.timeoutId = setTimeout(function(){
that.performProcessing();
}, 100);
}
};
//尝试开始执行
processor.process();
使用throttle函数简化:接收两个参数要执行的函数以及在哪个作用域中执行
function throttle(method, context) {
clearTimeout(method.tId);
method.tId= setTimeout(function(){
method.call(context);
}, 100);
}
如果没有给出第二个参数,那么就在全局作用域内执行该方法。
观察者模式由两类对象组成:主体和观察者。主体负责发布事件,同时观察者通过订阅这些事件来观察该主体。该模式的一个关键概念是主体并不知道观察者的任何事情,也就是说它可以独自存在并正常运作即使观察者不存在。
function EventTarget(){
this.handlers = {};
}
EventTarget.prototype = {
constructor: EventTarget, // 保持构造函数的正确指向
addHandler: function(type, handler){
if (typeof this.handlers[type] == "undefined"){
this.handlers[type] = [];
}
this.handlers[type].push(handler); // 把每类事件对应的需要执行的函数全部存在数组中
},
fire: function(event){
if (!event.target){
event.target = this;
}
if (this.handlers[event.type] instanceof Array){
var handlers = this.handlers[event.type]; // 获取存储起来的数组,该数组里面存放着需要执行的一堆函数
for (var i=0, len=handlers.length; i < len; i++){
handlers[i](event); // 把存储起来的函数全部遍历执行一遍
}
}
},
removeHandler: function(type, handler){
if (this.handlers[type] instanceof Array){
var handlers = this.handlers[type];
for (var i=0, len=handlers.length; i < len; i++){
if (handlers[i] === handler){
break;
}
}
handlers.splice(i, 1);// 删除其中某一个函数
}
}
};
cookies、sessionStorage、localStorage clear(): 删除所有值;Firefox 中没有实现 。 getItem(name):根据指定的名字 name 获取对应的值。 key(index):获得 index 位置处的值的名字。 removeItem(name):删除由 name 指定的名值对儿。 setItem(name, value):为指定的 name 设置一个对应的值。