模板字符串
ES6新增了一种模板字符串,它会自动替换字符串中的变量:
var name = '小明';
var age = 20;
console.log(`你好, ${name}, 你今年${age}岁了!`);//你好, 小明, 你今年20岁了!
toUpperCase字符串全部改为大写
toLowerCase字符串全部变为小写
var s = 'Hello';
s.toUpperCase(); // 返回'HELLO'
substring返回指定索引区间的子串:
var s = 'hello, world'
s.substring(0, 5); // 从索引0开始到5(不包括5),返回'hello'
s.substring(7); // 从索引7开始到结束,返回'world'
JavaScript对象的所有属性都是字符串,不过属性对应的值可以是任意数据类型。
JavaScript的对象
var xiaoming = {
name: '小明',
birth: 1990,
school: 'No.1 Middle School',
height: 1.70,
weight: 65,
score: null
};
for … in循环,它可以把一个对象的所有属性依次循环出来:遍历的是属性名称
var o = {
name: 'Jack',
age: 20,
city: 'Beijing'
};
for (var key in o) {
console.log(key); // 'name', 'age', 'city'
}
由于Array也是对象,而它的每个元素的索引被视为对象的属性,因此,for … in循环可以直接循环出Array的索引:
var a = ['A', 'B', 'C'];
for (var i in a) {
console.log(i); // '0', '1', '2'
console.log(a[i]); // 'A', 'B', 'C'
}
注意,for … in对Array的循环得到的是String而不是Number。
JavaScript的对象有个小问题,就是键必须是字符串。但实际上Number或者其他数据类型作为键也是非常合理的。为了解决这个问题,最新的ES6规范引入了新的数据类型Map。
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael'); // 95
var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined
Javascript定义函数
第一种方式:
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
function指出这是一个函数定义;
abs是函数的名称;
(x)括号内列出函数的参数,多个参数以,分隔;
{ … }之间的代码是函数体,可以包含若干语句,甚至可以没有任何语句。
第二种方式:
var abs = function (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
};
注意第二种方式按照完整语法需要在函数体末尾加一个;,表示赋值语句结束。
arguments关键字,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。
箭头函数ES6标准新增了一种新的函数:Arrow Function(箭头函数)。详情参考箭头函数
x => x * x
相当于
function (x) {
return x * x;
}
generator(生成器)是ES6标准引入的新的数据类型。一个generator看上去像一个函数,但可以返回多次。
把任何JavaScript对象变成JSON,就是把这个对象序列化成一个JSON格式的字符串,这样才能够通过网络传递给其他计算机。
如果我们收到一个JSON格式的字符串,只需要把它反序列化成一个JavaScript对象,就可以在JavaScript中直接使用这个对象了。
序列化
'use strict';
var xiaoming = {
name: '小明',
age: 14,
gender: true,
height: 1.65,
grade: null,
'middle-school': '\"W3C\" Middle School',
skills: ['JavaScript', 'Java', 'Python', 'Lisp']
};
var s = JSON.stringify(xiaoming);
console.log(s);
{"name":"小明","age":14,"gender":true,"height":1.65,"grade":null,
"middle-school":"\"W3C\" Middle School","skills":["JavaScript","Java","Python","Lisp"]}
如果我们还想要精确控制如何序列化小明,可以给xiaoming定义一个toJSON()的方法,直接返回JSON应该序列化的数据:
var xiaoming = {
name: '小明',
age: 14,
gender: true,
height: 1.65,
grade: null,
'middle-school': '\"W3C\" Middle School',
skills: ['JavaScript', 'Java', 'Python', 'Lisp'],
toJSON: function () {
return { // 只输出name和age,并且改变了key:
'Name': this.name,
'Age': this.age
};
}
};
JSON.stringify(xiaoming); // '{"Name":"小明","Age":14}'
反序列化
拿到一个JSON格式的字符串,我们直接用JSON.parse()把它变成一个JavaScript对象:
JSON.parse('[1,2,3,true]'); // [1, 2, 3, true]
JSON.parse('{"name":"小明","age":14}'); // Object {name: '小明', age: 14}
JSON.parse('true'); // true
JSON.parse('123.45'); // 123.45
var obj = JSON.parse('{"name":"小明","age":14}', function (key, value) {
if (key === 'name') {
return value + '同学';
}
return value;
});
console.log(JSON.stringify(obj)); //{"name":"小明同学","age":14}
Javascript的面向对象编程
// 原型对象:
var Student = {
name: 'Robot',
height: 1.2,
run: function () {
console.log(this.name + ' is running...');
}
};
function createStudent(name) {
// 基于Student原型创建一个新对象:
var s = Object.create(Student);
// 初始化新对象:
s.name = name;
return s;
}
var xiaoming = createStudent('小明');
xiaoming.run(); // 小明 is running...
JavaScript的原型链和Java的Class区别就在,它没有“Class”的概念,所有对象都是实例,所谓继承关系不过是把一个对象的原型指向另一个对象而已。
构造函数
构造函数首字母应当大写,而普通函数首字母应当小写
function Student(name) {
this.name = name;
this.hello = function () {
alert('Hello, ' + this.name + '!');
}
}
var xiaoming = new Student('小明');
xiaoming.name; // '小明'
xiaoming.hello(); // Hello, 小明!
原型继承
JavaScript的原型继承实现方式就是:
定义新的构造函数,并在内部用call()调用希望“继承”的构造函数,并绑定this;
借助中间函数F实现原型链继承,最好通过封装的inherits函数完成;
继续在新的构造函数的原型上定义新方法。
class继承
新的关键字class从ES6开始正式被引入到JavaScript中。class的目的就是让定义类更简单。
操作DOM
<!-- HTML结构 -->
<div id="test-div">
<div class="c-red">
<p id="test-p">JavaScript</p>
<p>Java</p>
</div>
<div class="c-red c-green">
<p>Python</p>
<p>Ruby</p>
<p>Swift</p>
</div>
<div class="c-green">
<p>Scheme</p>
<p>Haskell</p>
</div>
</div>
// 选择<p>JavaScript</p>:
var js = document.getElementById('test-p');
// 选择<p>Python</p>,<p>Ruby</p>,<p>Swift</p>:
var arr = document.getElementsByClassName('c-red')[1].getElementsByTagName('p');
// 选择<p>Haskell</p>:
var haskell = document.getElementsByClassName('c-green')[1].lastElementChild;
更新DOM
!-- HTML结构 -->
<div id="test-div">
<p id="test-js">javascript</p>
<p>Java</p>
</div>
// 获取<p>javascript</p>节点:
var js = document.getElementById('test-js');
// 修改文本为JavaScript:
js.innerHTML='JavaScript';
// 修改CSS为: color: #ff0000, font-weight: bold
js.style.color='#ff0000';
js.style.fontWeight='bold';
操作表单
获取值
// <input type="text" id="email">
var input = document.getElementById('email');
input.value; // '用户输入的值'
设置值
// <input type="text" id="email">
var input = document.getElementById('email');
input.value = 'test@example.com'; // 文本框的内容已更新
提交表单
很多登录表单希望用户输入用户名和密码,但是,安全考虑,提交表单时不传输明文密码,而是密码的MD5。普通JavaScript开发人员会直接修改<input>
:
<!-- HTML -->
<form id="login-form" method="post" onsubmit="return checkForm()">
<input type="text" id="username" name="username">
<input type="password" id="password" name="password">
<button type="submit">Submit</button>
</form>
<script>
function checkForm() {
var pwd = document.getElementById('password');
// 把用户输入的明文变为MD5:
pwd.value = toMD5(pwd.value);
// 继续下一步:
return true;
}
</script>
这个做法看上去没啥问题,但用户输入了密码提交时,密码框的显示会突然从几个变成32个(因为MD5有32个字符)。
要想不改变用户的输入,可以利用<input type="hidden">
实现:
<!-- HTML -->
<form id="login-form" method="post" onsubmit="return checkForm()">
<input type="text" id="username" name="username">
<input type="password" id="input-password">
<input type="hidden" id="md5-password" name="password">
<button type="submit">Submit</button>
</form>
<script>
function checkForm() {
var input_pwd = document.getElementById('input-password');
var md5_pwd = document.getElementById('md5-password');
// 把用户输入的明文变为MD5:
md5_pwd.value = toMD5(input_pwd.value);
// 继续下一步:
return true;
}
</script>
在JavaScript中,浏览器的JavaScript执行引擎在执行JavaScript代码时,总是以单线程模式执行,也就是说,任何时候,JavaScript代码都不可能同时有多于1个线程在执行。执行多任务实际上都是异步调用。因为是异步操作,所以我们在JavaScript代码中就不知道什么时候操作结束,因此需要先设置一个回调函数,当文件读取完成后,JavaScript引擎将自动调用我们设置的回调函数。执行回调函数时,文件已经读取完毕,所以我们可以在回调函数内部安全地获得文件内容。
AJAX
Asynchronous JavaScript and XML,意思就是用JavaScript执行异步网络请求。
如果要让用户留在当前页面中,同时发出新的HTTP请求,就必须用JavaScript发送这个新请求,接收到数据后,再用JavaScript更新页面,这样一来,用户就感觉自己仍然停留在当前页面,但是数据却可以不断地更新。
用JavaScript写一个完整的AJAX代码并不复杂,但是需要注意:AJAX请求是异步执行的,也就是说,要通过回调函数获得响应。
在现代浏览器上写AJAX主要依靠XMLHttpRequest对象:
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('请求已发送,请等待响应...');
readyState是AJAX的状态
0 - (未初始化)还没有调用send()方法
1 - (载入)已调用send()方法,正在发送请求
2 - (载入完成)send()方法执行完成,
3 - (交互)正在解析响应内容
4 - (完成)响应内容解析完成,可以在客户端调用了
访问外域方式
jQuery
jQuery这么流行,肯定是因为它解决了一些很重要的问题。实际上,jQuery能帮我们干这些事情:
消除浏览器差异:你不需要自己写冗长的代码来针对不同的浏览器来绑定事件,编写AJAX等代码;
简洁的操作DOM的方法:写$(’#test’)肯定比document.getElementById(‘test’)来得简洁;
轻松实现动画、修改CSS等各种操作。
jQuery的理念“Write Less, Do More“,让你写更少的代码,完成更多的工作!
按ID查找
如果某个DOM节点有id属性,利用jQuery查找如下:
/ 查找<div id="abc">:
var div = $('#abc');
注意,#abc以#开头。返回的对象是jQuery对象。
什么是jQuery对象?jQuery对象类似数组,它的每个元素都是一个引用了DOM节点的对象。
通常情况下你不需要获取DOM对象,直接使用jQuery对象更加方便。如果你拿到了一个DOM对象,那可以简单地调用$(aDomObject)把它变成jQuery对象,这样就可以方便地使用jQuery的API了。
按tag查找
按tag查找只需要写上tag名称就可以了:
var ps = $('p'); // 返回所有<p>节点
ps.length; // 数一数页面有多少个<p>节点
按class查找
按class查找注意在class名称前加一个.
:
var a = $('.red'); // 所有节点包含`class="red"`都将返回
// 例如:
// <div class="red">...</div>
// <p class="green red">...</p>
var a = $('.red.green'); // 注意没有空格!
// 符合条件的节点:
// <div class="red green">...</div>
// <div class="blue green red">...</div>
还有属性 组合 多项选择器查找
更多精确查找方式详见精确查找
修改DOM
$('#test-ul li').text('JS');
// 如果不存在id为not-exist的节点:
$('#not-exist').text('Hello'); // 代码不报错,没有节点被设置为'Hello'
这意味着jQuery帮你免去了许多if语句。
css()方法将作用于DOM节点的style属性,具有最高优先级。如果要修改class属性,可以用jQuery提供的下列方法:
var div = $('#test-div');
div.hasClass('highlight'); // false, class是否包含highlight
div.addClass('highlight'); // 添加highlight这个class
div.removeClass('highlight'); // 删除highlight这个class
jQuery处理ajax
用JavaScript写AJAX前面已经介绍过了,主要问题就是不同浏览器需要写不同代码,并且状态和错误处理写起来很麻烦。
用jQuery的相关对象来处理AJAX,不但不需要考虑浏览器问题,代码也能大大简化。