- 数组操作
//index of
var arr = [10, 20, '30', 'xyz'];
arr.indexOf(10); // 元素10的索引为0
arr.indexOf(20); // 元素20的索引为1
arr.indexOf(30); // 元素30没有找到,返回-1
arr.indexOf('30'); // 元素'30'的索引为2
//slice
var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
arr.slice(0, 3); // 从索引0开始,到索引3结束,但不包括索引3: ['A', 'B', 'C']
arr.slice(3); // 从索引3开始到结束: ['D', 'E', 'F', 'G']
//push和pop 在数组最后增添元素
var arr = [1, 2];
arr.push('A', 'B'); // 返回Array新的长度: 4
arr; // [1, 2, 'A', 'B']
arr.pop(); // pop()返回'B'
arr; // [1, 2, 'A']
arr.pop(); arr.pop(); arr.pop(); // 连续pop 3次
arr; // []
arr.pop(); // 空数组继续pop不会报错,而是返回undefined
arr; // []
//shift和unshift 在数组前面增添元素
var arr = [1, 2];
arr.unshift('A', 'B'); // 返回Array新的长度: 4
arr; // ['A', 'B', 1, 2]
arr.shift(); // 'A'
arr; // ['B', 1, 2]
arr.shift(); arr.shift(); arr.shift(); // 连续shift 3次
arr; // []
arr.shift(); // 空数组继续shift不会报错,而是返回undefined
arr; // []
//sort 排序
var arr = ['B', 'C', 'A'];
arr.sort();
arr; // ['A', 'B', 'C']
//reverse元素反正
var arr = ['one', 'two', 'three'];
arr.reverse();
arr; // ['three', 'two', 'one']
//splice 从某处删除n个元素,再添加新元素
var arr = ['Microsoft', 'Apple', 'Yahoo', 'AOL', 'Excite', 'Oracle'];
// 从索引2开始删除3个元素,然后再添加两个元素:
arr.splice(2, 3, 'Google', 'Facebook'); // 返回删除的元素 ['Yahoo', 'AOL', 'Excite']
arr; // ['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']
// 只删除,不添加:
arr.splice(2, 2); // ['Google', 'Facebook']
arr; // ['Microsoft', 'Apple', 'Oracle']
// 只添加,不删除:
arr.splice(2, 0, 'Google', 'Facebook'); // 返回[],因为没有删除任何元素
arr; // ['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']
//concat 连接数组
var arr = ['A', 'B', 'C'];
var added = arr.concat([1, 2, 3]);
added; // ['A', 'B', 'C', 1, 2, 3]
arr; // ['A', 'B', 'C']
//join 将数组所有元素用指定字符连接
var arr = ['A', 'B', 'C', 1, 2, 3];
arr.join('-'); // 'A-B-C-1-2-3'
- Map和Set
//map
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
//set
var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3
s.add(4);
s; // Set {1, 2, 3, 4}
s.add(4);
s; // 仍然是 Set {1, 2, 3, 4}
- iterable
for...of...
var a = ['A', 'B', 'C'];
var s = new Set(['A', 'B', 'C']);
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
for (var x of a) { // 遍历Array
console.log(x);
}
for (var x of s) { // 遍历Set
console.log(x);
}
for (var x of m) { // 遍历Map
console.log(x[0] + '=' + x[1]);
}
for...each...
//set
var s = new Set(['A', 'B', 'C']);
s.forEach(function (element, sameElement, set) {
console.log(element);
});
//Map
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
m.forEach(function (value, key, map) {
console.log(value);
});
//Array
var a = ['A', 'B', 'C'];
a.forEach(function (element) {
console.log(element);
});
- apply和call
apply()把参数打包成Array再传入;
call()把参数按顺序传入。
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // 25
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空
Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5
- 高阶函数
//map 和 reduce
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(String); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']
var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x + y;
}); // 25
var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x * 10 + y;
}); // 13579
//filter 过滤掉array的某些元素 返回结果为true的元素才能留下
var arr = [1, 2, 4, 5, 6, 9, 10, 15];
var r = arr.filter(function (x) {
return x % 2 !== 0;
});
r; // [1, 5, 9, 15]
//filter可以有多个元素
var arr = ['A', 'B', 'C'];
var r = arr.filter(function (element, index, self) {
console.log(element); // 依次打印'A', 'B', 'C'
console.log(index); // 依次打印0, 1, 2
console.log(self); // self就是变量arr
return true;
});
//sort()方法会直接对Array进行修改,它返回的结果仍是当前Array
var a1 = ['B', 'A', 'C'];
var a2 = a1.sort();
a1; // ['A', 'B', 'C']
a2; // ['A', 'B', 'C']
a1 === a2; // true, a1和a2是同一对象
//Array的高阶函数
//every
var arr = ['Apple', 'pear', 'orange'];
console.log(arr.every(function (s) {
return s.length > 0;
})); // true, 因为每个元素都满足s.length>0
console.log(arr.every(function (s) {
return s.toLowerCase() === s;
})); // false, 因为不是每个元素都全部是小写
//find
var arr = ['Apple', 'pear', 'orange'];
console.log(arr.find(function (s) {
return s.toLowerCase() === s;
})); // 'pear', 因为pear全部是小写
console.log(arr.find(function (s) {
return s.toUpperCase() === s;
})); // undefined, 因为没有全部是大写的元素
//findIndex
var arr = ['Apple', 'pear', 'orange'];
console.log(arr.findIndex(function (s) {
return s.toLowerCase() === s;
})); // 1, 因为'pear'的索引是1
console.log(arr.findIndex(function (s) {
return s.toUpperCase() === s;
})); // -1
//foreach forEach()和map()类似,它也把每个元素依次作用于传入的函数,但不会返回新的数组。forEach()常用于遍历数组
var arr = ['Apple', 'pear', 'orange'];
arr.forEach(console.log); // 依次打印每个元素
- 闭包
function count(){
var arr=[]
for(var i=1;i <= 3;i ++){
arr.push(function(){
return i*i;
});
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
//输出结果
f1(); // 16
f2(); // 16
f3(); // 16
原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了4,因此最终结果为16。
返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
解决方法:
function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push((function (n) {
return function () {
return n * n;
}
})(i));
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
f1(); // 1
f2(); // 4
f3(); // 9
创建匿名函数并立即执行的语法
function (x) { return x * x } (3);
闭包就是携带状态的函数,并且它的状态可以完全对外隐藏起来。
js创建计数器:
'use strict';
function create_counter(initial) {
var x = initial || 0;
return {
inc: function () {
x += 1;
return x;
}
}
}
var c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3
var c2 = create_counter(10);
c2.inc(); // 11
c2.inc(); // 12
c2.inc(); // 13
- 面向对象
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 || {})
}
var xiaoming = createStudent({
name: '小明'
});
xiaoming.grade; // 1
- 原型继承
function inherits(Child, Parent) {
var F = function () {};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
}
function Student(props) {
this.name = props.name || 'Unnamed';
}
Student.prototype.hello = function () {
alert('Hello, ' + this.name + '!');
}
function PrimaryStudent(props) {
Student.call(this, props);
this.grade = props.grade || 1;
}
// 实现原型继承链:
inherits(PrimaryStudent, Student);
// 绑定其他方法到PrimaryStudent原型:
PrimaryStudent.prototype.getGrade = function () {
return this.grade;
};
- class继承
class Student {
constructor(name) {
this.name = name;
}
hello() {
alert('Hello, ' + this.name + '!');
}
}
class PrimaryStudent extends Student {
constructor(name, grade) {
super(name); // 记得用super调用父类的构造方法!
this.grade = grade;
}
myGrade() {
alert('I am at grade ' + this.grade);
}
}
- AJAX
AJAX不是JavaScript的规范,它只是一个哥们“发明”的缩写:Asynchronous JavaScript and XML,意思就是用JavaScript执行异步网络请求。
如果仔细观察一个Form的提交,你就会发现,一旦用户点击“Submit”按钮,表单开始提交,浏览器就会刷新页面,然后在新页面里告诉你操作是成功了还是失败了。如果不幸由于网络太慢或者其他原因,就会得到一个404页面。
这就是Web的运作原理:一次HTTP请求对应一个页面。
如果要让用户留在当前页面中,同时发出新的HTTP请求,就必须用JavaScript发送这个新请求,接收到数据后,再用JavaScript更新页面,这样一来,用户就感觉自己仍然停留在当前页面,但是数据却可以不断地更新。
最早大规模使用AJAX的就是Gmail,Gmail的页面在首次加载后,剩下的所有数据都依赖于AJAX来更新。
用JavaScript写一个完整的AJAX代码并不复杂,但是需要注意:AJAX请求是异步执行的,也就是说,要通过回调函数获得响应。
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('请求已发送,请等待响应...');