主要参考 廖雪峰的 JavaScript 教程
- number
- boolean
- string
- array
- object
- NaN : 计算错误返回,所有与 NaN 相关的计算返回 NaN
- undefined
- null
注:
- 转换类型使用
NumberBooleanString,例如Number('123') - 使用
parseInt()|parseFloat()转换任意类型到number - 转换到
string使用String()|obj.toString() number对象到string使用(123).toString()- 判断
Array使用Array.isArray(arr) - 判断
null使用myvar == null|isNaN() - 判断全局变量的存在
typeof window.myVar === 'undefined' - 判断函数内部变量是否存在使用
typeof myVar === 'undefined'
使用 call 指定函数使用的 this, 若不指定 this 指向 window
- call :
fun.call(thisArg[, arg1[, arg2[, ...]]]) - apply :
fun.apply(thisArg, [argsArray])
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
var apple = Foos('apple', 30)
var now = new Date()
now; // Tue Dec 22 2015 10:26:08 GMT+0800 (CST)
now.getFullYear() //205
.getMonth()
.getDate() // 24号
.getDay // 3 获取星期,从 1 开始
.getHours()
.getMinutes()
.getSeconds()
.geMilliseconds() // 875 毫秒数
.getTime() // 时间戳var d = new Date(2015, 5, 19, 20, 15, 30, 123)
// 2015.6.19 20:15:30:123 月份从 0 开始
var timestamp = Date.parse('2015-06-24T19:49:22.875+08:00')
var dateObj = new Date(timestamp)
var d= new Date()
d.toLocaleString()
d.toUTCString()
时间戳
nowTimestamp = Data.now() | new Date().getTime()
var re1 = /ABC\-001/
var re2 = new RegExp('ABC\\-001')
var re = /xxx/
// 检测是否符合
re.test(str) // return -> boolean 判断是否符合条件
// 切割字符串
str.split(/\s+/) // 'a b c' -> ['a', 'b', 'c']
// 分组
var re = /(\d)\d(\d)/
re.exec("123") // return -> ["123", "1", "3"]
re.exec("abc') // return -> null
var re = /\d{3}/g // 使用 /g
var s = '123a456')
re.exec(s) // return -> ["123"]
re.lastIndex // 3 下一次搜索的起点
re.exec(s) // return -> ["456"]
re.lastIndex // 4
re.exec(s) // return -> null
re.lastIndex // 0
类似: /m 匹配多行 /i 忽略大小写
// to json
obj = {hello:"world", age:12}
JSON.stringify(obj)
// return -> {"hello":"world", "age":12}
JSON.stringify(obj, (value, key) => { //do some thing
return value;})
注: 传入的函数参数顺序为 value / key
var obj = {hello:"world",
age:12,
toJSON: function () {
return {
hello: this.hello
}
}}
// 使用 箭头函数不行 不知为何
JSON.stringify(obj,['needvar1', 'needvar2'])
JSON.parse('[1, 2, 3, true]'); // [1, 2, 3, true]
// 处理 序列
JSON.parse('[1, 2, 3, true]', (v, k) => typeof v === 'number' ? v+1: v)
// k, v 在接收到 1,2,3, true 之后还会接受到整个处理后的数组 [2, 3, 4, true] 导致一些奇异的行为 ?
JavaScript不区分类和实例的概念,而是通过原型prototype来实现面向对象编程
xiaoming.__proto__ = Student;
// 把小明的原型指向 Student 类似于 xiaoming 继承于 Student
Object.create(parent) 方法可以传入一个原型对象,并创建一个基于该原型的新对象,但是新对象只有 parent 的方法,没有 parent 的属性
当我们用obj.xxx访问一个对象的属性时,JavaScript引擎先在当前对象上查找该属性,如果没有找到,就到其原型对象上找,如果还没有找到,就一直上溯到Object.prototype对象,最后,如果还没有找到,就只能返回undefined
var arr = []
// arr -> Array.prototype -> Object.prototype -> null
var func = () => 1
// func -> Function.prototype -> Object.prototype -> null
function Student(name) {
this.name = name;
this.getName = () => "hello " + this.name
}
xm = new Student('xm')
xm.getName() // return -> 'hello xm'
// xm ----> Student.prototype ----> Object.prototype ----> null
xh = new Student('xh')
此时 xh / xm 都保存有一份 getName 的代码,虽然函数是一样的
可以将 Student 的 getName 绑定 到 Student 的 prototype 上,这样 xm / xh 之类的可以共用一份方法节省内存
function Student(name) {
this.name = name;
}
Student.prototype.getName = () => 'hello ' + this.name
一种更好的实现
function Student(props) {
this.name = props.name || '匿名'; // 默认值为'匿名'
this.grade = props.grade || 1; // 默认值为1
}
Student.prototype.hello = function () {
alert('Hello, ' + this.name + '!');
};
function createStudent(props) {
return new Student(props || {})
}
表示屏幕的信息
- width : 屏幕宽度,以像素为单位
- height : 屏幕高度,以像素为单位
- colorDepth : 放回颜色位数,如8、 16、 24
表示浏览器的信息
- navigator.appName:浏览器名称;
- navigator.appVersion:浏览器版本;
- navigator.language:浏览器设置的语言;
- navigator.platform:操作系统类型;
- navigator.userAgent:浏览器设定的User-Agent字符串
表示全局作用域,同时表示浏览器窗口
- innerWidth
- innerHeight
表示浏览器窗口的内部宽度和高度。内部宽高是指除去菜单栏、工具栏、边框等占位元素后,用于显示网页的净宽高
- outerWidth
- outerHeight
获取浏览器窗口的整个宽高
表示当前 url 信息
-
href : 当前完整 url 信息, 可通过赋值造成
url跳转http://www.example.com:8080/path/index.html?a=1&b=2#TOP, -
protocol : 'http:'
-
host : 'www.example.com'
-
port : 8080
-
pathname : '/path/index.html'
-
search : '?a=1&b=2'
-
hash : 'TOP'
-
location.reload() 刷新当前页
-
location.assign('new path') 调整到新的路径下
表示当前页面,document 对象就是整个 DOM 树的根节点
- title : 当前窗口标题
- cookie : 获取当前页面
cookie - getElementById()
- getElementByTagName()
- getElementByClassName()
服务器在设置Cookie时可以使用httpOnly,设定了httpOnly的Cookie将不能被JavaScript读取
表示浏览历史
- back()
- foward()
目前大量使用AJAX和页面交互,简单粗暴地调用history.back()可能会让用户感到非常愤怒
- document.getElementById()
- document.getElementByTagName()
- document.getElementByClassName()
使用 CSS 选择器
- document.querySelector('#id')
- document.querySelectorAll('div > p')
获取一个元素的所有子节点
- parent.children
不仅可直接修改文本,而且可以通过 HTML 直接修改 DOM 节点
注:此时不会对文本内容转义,需要注意是否可能会被 XSS 攻击
ele.innerHTML = 'ABC <p>hello</p> DEF'
修改的文本中若有 HTML 属性,会自动转义
innerText 不返回回隐藏元素的文本
textContent 返回所有文本
ele.innerText = 'hello<p>xyz</p>'
ele.textContent = 'hello<p>xyz</p>'
// hello<p>xyz</p>
ele.style 返回所有的 CSS 属性,命名改为驼峰式
- ele.createElement('style')
- ele.setAttribute('type', 'text/css')
- parent.appendChild(ele) : 在
parent的最后插入 - parent.insertBefore(newele, refele) : 在
refele前插入newele
- parent.removeChild(childEle)
对 text、password、hidden以及select 可以直接设置 value
ele.value = 'value'
对 radio 需要检查或者设置 checked
使用 form.submit() 不推荐
var form = document.querySelector('#form')
// do something
form.submit()
<form id="test-form" onsubmit="return checkForm()">
<input type="text" name="test">
<button type="submit">Submit</button>
</form>
<script>
function checkForm() {
var form = document.querySelector('#form')
// do something
return true // false 不提交
}
</script>
没有name属性的<input>的数据不会被提交
function success(text) {
var textarea = document.getElementById('test-response-text');
textarea.value = text;
}
function fail(code) {
var textarea = document.getElementById('test-response-text');
textarea.value = 'Error code: ' + code;
}
var request = new XMLHttpRequest(); // 新建XMLHttpRequest对象
request.onreadystatechange = function () { // 状态发生变化时,函数被回调
if (request.readyState === 4) { // 成功完成
// 判断响应结果:
if (request.status === 200) {
// 成功,通过responseText拿到响应的文本:
return success(request.responseText);
} else {
// 失败,根据响应码判断失败原因:
return fail(request.status);
}
} else {
// HTTP请求还在继续...
}
}
// 发送请求:
request.open('GET', '/api/categories');
request.send();
alert('请求已发送,请等待响应...');
默认情况下,JavaScript在发送AJAX请求时,URL的域名必须和当前页面完全一致。绕过可以使用 JSONP 或 CORS
这种方式跨域实际上是利用了浏览器允许跨域引用JavaScript资源.它有个限制,只能用GET请求,并且要求返回JavaScript。
以163的股票查询URL为例,对于URL:http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice,你将得到如下返回:
refreshPrice({"0000001":{"code": "0000001", ... });
因此我们需要首先在页面中准备好回调函数:
function refreshPrice(data) {
var p = document.getElementById('test-jsonp');
p.innerHTML = '当前价格:' +
data['0000001'].name +': ' +
data['0000001'].price + ';' +
data['1399001'].name + ': ' +
data['1399001'].price;
}
最后用getPrice()函数触发:
function getPrice() {
var
js = document.createElement('script'),
head = document.getElementsByTagName('head')[0];
js.src = 'http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice';
head.appendChild(js);
}
Cross-Origin Resource Sharing,是HTML5规范定义的如何跨域访问资源。
Origin表示本域,也就是浏览器当前页面的域。当JavaScript向外域(如sina.com)发起请求后,浏览器收到响应后,首先检查Access-Control-Allow-Origin是否包含本域,如果是,则此次跨域请求成功,如果不是,则请求失败,JavaScript将无法获取到响应的任何数据。
只要响应头Access-Control-Allow-Origin为http://my.com,或者是*,本次请求就可以成功
上面这种跨域请求,称之为“简单请求”。简单请求包括GET、HEAD和POST(POST的Content-Type类型
仅限application/x-www-form-urlencoded、multipart/form-data和text/plain),并且不能出现任何自定义头(例如,X-Custom: 12345),通常能满足90%的需求
对于PUT、DELETE以及其他类型如application/json的POST请求,在发送AJAX请求之前,浏览器会先发送一个OPTIONS请求(称为preflighted请求)到这个URL上,询问目标服务器是否接受:
OPTIONS /path/to/resource HTTP/1.1
Host: bar.com
Origin: http://my.com
Access-Control-Request-Method: POST
服务器必须响应并明确指出允许的Method:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://my.com
Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS
Access-Control-Max-Age: 86400
浏览器确认服务器响应的Access-Control-Allow-Methods头确实包含将要发送的AJAX请求的Method,才会继续发送AJAX,否则,抛出一个错误。
由于以POST、PUT方式传送JSON格式的数据在REST中很常见,所以要跨域正确处理POST和PUT请求,服务器端必须正确响应OPTIONS请求
function test(resolve, reject) {
setTimeOut(() => resolve(result), 1000)
setTimeOut(() => reject(reason), 1000)
}
new Promise(test).then(function (result) {
console.log('成功:' + result);
}).catch(function (reason) {
console.log('失败:' + reason);
});
我们需要从两个不同的URL分别获得用户的个人信息和好友列表,这两个任务是可以并行执行的,用Promise.all()实现如下:
var p1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 600, 'P2');
});
// 同时执行p1和p2,并在它们都完成后执行then:
Promise.all([p1, p2]).then(function (results) {
console.log(results); // 获得一个Array: ['P1', 'P2']
});
多个异步任务是为了容错。比如,同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可。这种情况下,用Promise.race()实现:
var p1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
console.log(result); // 'P1'
});
$('css 选择器')
最常见的查找是在某个节点的所有子节点中查找,使用find()方法,它本身又接收一个任意的选择器
- 无参数时获取当前节点的父节点
- 接受
CSS选择器时从当前的父节点开始向上查找,直到找到某个符合条件的节点并返回
同级节点使用 next() 和 prev() 来获取
- 传入
CSS选择器
var langs = $('ul.lang li'); // 拿到JavaScript, Python, Swift, Scheme和Haskell
var a = langs.filter('.dy'); // 拿到JavaScript, Python, Scheme
- 传入过滤函数
var langs = $('ul.lang li'); // 拿到JavaScript, Python, Swift, Scheme和Haskell
langs.filter(function () {
return this.innerHTML.indexOf('S') === 0; // 返回S开头的节点
}); // 拿到Swift, Scheme
eles.map(function () {// do something})
// 获取
ele.html()
ele.text()
//设置
ele.html('new html')
ele.text('new text')
此操作会作用在 JQuery 对象包含的所有 DOM 节点下
// 获取
ele.css('name')
// 设置
$('ele').css('name', 'value') // name 支持 CSS 命名和驼峰
$('#test-css li.dy>span').css('background-color', '#ffd351').css('color', 'red');
ele.css('name', '') // 清除 CSS 属性
var div = $('div')
div.hasClass('highlight'); // false, class是否包含highlight
div.addClass('highlight'); // 添加highlight这个class
div.removeClass('highlight'); // 删除highlight这个class
隐藏或者显示 JQuery 对象
ele.width()
ele.height()
//设置
ele.width(200)
ele.height('300px')
// 获取
ele.attr('type')
// 设置
ele.attr('type', 'button')
// 移除
ele.removeAttr('type')
prop()
prop()方法和attr()类似,但是HTML5规定有一种属性在DOM节点中可以没有值,只有出现与不出现两种,例如:
<input id="test-radio" type="radio" name="test" checked value="1">
等价于:
<input id="test-radio" type="radio" name="test" checked="checked" value="1">
attr()和prop()对于属性checked处理有所不同:
var radio = $('#test-radio');
radio.attr('checked'); // 'checked'
radio.prop('checked'); // true
prop()返回值更合理一些。不过,用is()方法判断更好:
var radio = $('#test-radio');
radio.is(':checked'); // true
类似的属性还有selected,处理时最好用is(':selected')
// 获取
ele.var()
// 设置
ele.var('hello')
可以传入原始的DOM对象,jQuery对象和函数对象
传入函数时,要求返回一个字符串、DOM对象或者jQuery对象。
若 append()的对象已经存在,则会移动这些对象
同级节点可以用after()或者before()方法
var js = $('#test-div>ul>li:first-child');
js.after('<li><span>Lua</span></li>');
ele.remove()
ele.on('click', () => alert('hello'))
// 或者
ele.click(() => alert('hello'))
可绑定的事件列表
鼠标事件
click: 鼠标单击时触发;
dblclick:鼠标双击时触发;
mouseenter:鼠标进入时触发;
mouseleave:鼠标移出时触发;
mousemove:鼠标在DOM内部移动时触发;
hover:鼠标进入和退出时触发两个函数,相当于mouseenter加上mouseleave。
键盘事件
键盘事件仅作用在当前焦点的DOM上,通常是<input>和<textarea>。
keydown:键盘按下时触发;
keyup:键盘松开时触发;
keypress:按一次键后触发。
其他事件
focus:当DOM获得焦点时触发;
blur:当DOM失去焦点时触发;
change:当<input>、<select>或<textarea>的内容改变时触发;
submit:当<form>提交时触发;
ready:当页面被载入并且DOM树完成初始化后触发
ready仅作用于document对象。由于ready事件在DOM完成初始化后触发,且只触发一次,所以非常适合用来写其他的初始化代码
有些事件,如mousemove和keypress,我们需要获取鼠标位置和按键的值,否则监听这些事件就没什么意义了。所有事件都会传入Event对象作为参数,可以从Event对象上获取到更多的信息
一个已被绑定的事件可以解除绑定,通过off('click', function)实现:
function hello() {
alert('hello!');
}
a.click(hello); // 绑定事件
// 10秒钟后解除绑定:
setTimeout(function () {
a.off('click', hello);
}, 10000);
一个需要注意的问题是,事件的触发总是由用户操作引发的
// 手动触发
ele.change()
ele.click()
// 为 ele.tirgger('click')的简写
ele.show(3000); // 3秒内消失
ele.hide(3000); // 3秒内展示
ele.toggle(3000); / 根据当前状态决定是 show() 还是 hide()
ele.slideUp()
ele.slideDown()
ele.slideToggle()
ele.fadeIn('slow')
ele.fadeOut('slow')
ele.fadeToggle('slow')
var div = $('#test-animate');
div.animate({
opacity: 0.25,
width: '256px',
height: '256px'
}, 3000); // 在3秒钟内CSS过渡到设定值
animate()还可以再传入一个函数,当动画结束时,该函数将被调用:
var div = $('#test-animate');
div.animate({
opacity: 0.25,
width: '256px',
height: '256px'
}, 3000, function () {
console.log('动画已结束');
// 恢复至初始状态:
$(this).css('opacity', '1.0').css('width', '128px').css('height', '128px');
});
jQuery在全局对象jQuery(也就是$)绑定了ajax()函数。ajax(url, settings)函数需要接收一个URL和一个可选的settings对象,常用的选项如下:
async:是否异步执行AJAX请求,默认为true,千万不要指定为false;
method:发送的Method,缺省为'GET',可指定为'POST'、'PUT'等;
contentType:发送POST请求的格式,默认值为'application/x-www-form-urlencoded; charset=UTF-8',也可以指定为text/plain、application/json;
data:发送的数据,可以是字符串、数组或object。如果是GET请求,data将被转换成query附加到URL上,如果是POST请求,根据contentType把data序列化成合适的格式;
headers:发送的额外的HTTP头,必须是一个object;
dataType:接收的数据格式,可以指定为'html'、'xml'、'json'、'text'等,缺省情况下根据响应的Content-Type猜测。
var jqxhr = $.ajax('/api/categories', {
dataType: 'json'
}).done(function (data) {
ajaxLog('成功, 收到的数据: ' + JSON.stringify(data));
}).fail(function (xhr, status) {
ajaxLog('失败: ' + xhr.status + ', 原因: ' + status);
}).always(function () {
ajaxLog('请求完成: 无论成功或失败都会调用');
});
$.get(url, paramsObj)
$.post(url, paramsObj) // 默认 content-type 为 application/x-www-form-urlencoded
var jqxhr = $.getJSON('/path/to/resource', {
name: 'Bob Lee',
check: 1
}).done(function (data) {
// data已经被解析为JSON对象了
});
jQuery的AJAX完全封装的是JavaScript的AJAX操作,所以它的安全限制和前面讲的用JavaScript写AJAX完全一样。
如果需要使用JSONP,可以在ajax()中设置jsonp: 'callback',让jQuery实现JSONP跨域加载数据
给jQuery对象绑定一个新方法是通过扩展$.fn对象实现的
$.fn.highlight1 = function () {
// this已绑定为当前jQuery对象:
this.css('backgroundColor', '#fffceb').css('color', '#d85030');
return this;
}