var name = '小明';
var age = 20;
var message = `你好, ${name}, 你今年${age}岁了!`;
alert(message);
toUpperCase()
把一个字符串全部变为大写
toLowerCase()
把一个字符串全部变为小写
indexOf()
会搜索指定字符串出现的位置:没有找到的话返回-1
substring(start,数量)
返回指定索引区间的子串: 不写数量的话默认到结束
请注意,
直接给数组赋length会改变原数组大小
如果通过索引赋值时,索引超过了范围,同意会改变原数组大小,所以访问索引时要确保索引不会越界。
indexOf()
搜索一个指定的元素的位置:
slice(start,数量)
截取数组
的部分元素返回一个新的数组
:不写数量的话默认到结束 注意:可通过slice()来复制数组
push()
向数组
的末尾添加若干元素
unshift()
向数组
的开头添加若干元素
pop()
把数组
的最后一个元素删除掉
shift()
把数组
的第一个元素删掉
sort()
可以对当前数组进行排序
reverse()
反转整个数组
的元素
splice(start,数量,添加的字符串)
可以从指定的索引开始删除若干元素,然后再从该位置添加若干元素
concat()
方法把两个数组连接起来,并返回一个新的Array
join(',') 把数组元素按照逗号拼接为字符串,
返回连接后的字符串:可以不加参数直接拼接
访问对象属性属于 对象名.属性名 或 对象名[属性名]
delete 对象名.属性名 删除对象属性
对象名.hasOwnProperty(‘属性名’ ) 检查对象是否含有此属性
Map是一组键值对的结构,具有极快的查找速度。
初始化Map需要一个二维数组,或者直接初始化一个空Map
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
var m = new Map()
Map具有以下方法:
m.set('Adam', 67); //添加新的key-value
m.has('Adam'); //检查是否存在key
m.get('Adam'); //获取对应key的值
m.delete('Adam'); //删除key
Set是一组key的集合,但不存储value,key不重复。
初始化Set需要一个一维数组,或者直接初始化一个空Set
var s = new Set([1,2,3]);
var s = new Set()
Set具有以下方法:
s.add(4); //增加key
s.delete(3); //删除key
遍历
Array
可以采用下标循环,遍历Map
和Set
就无法使用下标。为了统一集合类型,ES6标准引入了新的
iterable
类型,Array
、Map
和Set
都属于iterable
类型。
iterable
类型的集合可以通过新的for ... of
循环来遍历
var a = ['A', 'B', 'C'];
var a = new Map();
var a = new Set();
for (var x of a) {
console.log(x);
}
最佳的遍历方式通过forEach()方法
数组:
var a = ['A','B','C'];
a.forEach(function (element, index, array) {
// element: 指向当前元素的值
// index: 指向当前索引
// array: 指向Array对象本身
console.log(element + ', index = ' + index);
});
Map:类似
ar s = new Set(['A', 'B', 'C']);
s.forEach(function (element, sameElement, set) {
console.log(element);
});
Set:类似
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
m.forEach(function (value, key, map) {
console.log(value);
});
function abs(x) {
if(x<0){
return -x;
}else{
return x;
}
}
var abs = function (x) {
return x;
};
1.
arguments参数
函数内部有免费赠送的关键字
arguments
,利用arguments
,你可以获得调用者传入的所有参数。
arguments
类似Array,
实际上arguments
最常用于判断传入参数的个数。你可能会看到这样的写法:
// 接收2~3个参数,b是可选参数,如果只传2个参数,b默认为null:
function foo(a, b, c) {
if (arguments.length === 2) {
// 实际拿到的参数是a和b,c为undefined
c = b; // 把b赋给c
b = null; // b变为默认值
}
}
2.rest参数
函数调用时,为了获得额外的参数,通过rest返回额外参数Array
rest参数只能写在最后,前面用
...
标识
function foo(a, b, ...rest) {
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}
foo(1,2,3,4,5) //rest:[3,4,5]
如果一个变量在函数体内部申明,则该变量的作用域为整个函数体,在函数体外不可引用该变量:
如果两个不同的函数申明同一个变量,不同函数内部的同名变量互相独立,互不影响:
JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部:
注意:JavaScript引擎自动提升了变量y
的声明,但不会提升变量y
的赋值。
'use strict';
function foo() { function foo() {
var x = 'Hello, ' + y; var y;
console.log(x); 相当于 var x = 'Hello, ' + y;
var y = 'Bob'; y = 'Bob';
} console.log(x);
}
foo(); //返回 Hello,undefined
- 不在任何函数内定义的变量就具有全局作用域。
- 实际上,JavaScript默认有一个全局对象
window
,全局作用域的变量实际上被绑定到window
的一个属性:- 由于函数定义有两种方式,以变量方式
var foo = function () {}
定义的函数实际上也是一个全局变量,因此顶层函数也会绑定到window
对象:可以通过window.foo()调用
全局变量会绑定到window
上,不同的JavaScript文件如果使用了相同的全局变量,或者定义了相同名字的顶层函数,都会造成命名冲突,并且很难被发现。
减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中。
// 唯一的全局变量MYAPP:
var MYAPP = {};
// 其他变量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;
// 其他函数:
MYAPP.foo = function () {
return 'foo';
};
用 let关键字
替代var
可以申明一个块级作用域的变量:
function foo() {
var sum = 0;
for (let i=0; i<100; i++) {
sum += i;
}
// SyntaxError:
i += 1;
}
13.常量
const关键字
来定义常量,也拥有块级作用域
const PI = 3.14;
PI = 3; // 某些浏览器不报错,但是无效果!
同时对多个变量赋值:
var [x, y, z] = ['hello', 'JavaScript', 'ES6'];
解构赋值还可以忽略某些元素:
let [, , z] = ['hello', 'JavaScript', 'ES6']; // 忽略前两个元素,只对z赋值第三个元素
z; // 'ES6'
如果需要从一个对象中取出若干属性,也可以使用解构赋值,便于快速获取对象的指定属性
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school'
};
var {name, age, passport} = person;
// name = 小明, age = 20, passport = G-12345678
解构赋值在很多时候可以大大简化代码。例如,交换两个变量x
和y
的值,可以这么写,不再需要临时变量:
var x=1, y=2;
[x, y] = [y, x]
快速获取当前页面的域名和路径:
var {hostname:domain, pathname:path} = location;
如果一个函数接收一个对象作为参数,那么,可以使用解构直接把对象的属性绑定到变量中。例如,下面的函数可以快速创建一个Date
对象:
function buildDate({year, month, day, hour=0, minute=0, second=0}) {
return new Date(year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second);
}
它的方便之处在于传入的对象只需要year
、month
和day
这三个属性:
buildDate({ year: 2017, month: 1, day: 1 });
// Sun Jan 01 2017 00:00:00 GMT+0800 (CST)
也可以传入hour
、minute
和second
属性:
buildDate({ year: 2017, month: 1, day: 1, hour: 20, minute: 15 });
// Sun Jan 01 2017 20:15:00 GMT+0800 (CST)
绑定到对象上的函数称为方法
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
};
var fn = xiaoming.age; // 先拿到xiaoming的age函数
fn(); // NaN
var fn = xiaoming.age(); //正确
这是不行的!要保证this
指向正确,必须用obj.xxx()
的形式调用!
注意:在函数内部定义的函数,this
指向window!
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var that = this; // 在方法内部一开始就捕获this
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - that.birth; // 用that而不是this
}
return getAgeFromBirth();
}
};
xiaoming.age(); // 25
解决办法:用一个that
变量首先捕获this
指定函数的this
指向哪个对象,可以用函数本身的apply
方法
它接收两个参数,第一个参数就是需要绑定的this
变量,第二个参数是Array
,表示函数本身的参数。
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
getAge.apply(xiaoming, []); //不用apply的话,this就会指向window报错
另一个与apply()
类似的方法是call()
,唯一区别是:
apply()
把参数打包成Array
再传入;
call()
把参数按顺序传入。
对普通函数调用,我们通常把this
绑定为null
。
利用apply()
,我们还可以动态改变函数的行为。
var count = 0;
var oldParseInt = parseInt; // 保存原函数
window.parseInt = function () {
count += 1;
return oldParseInt.apply(null, arguments); // 调用原函数
};
parseInt('10');
parseInt('20');
parseInt('30');
console.log('count = ' + count); // 3
一个函数接收另一个函数作为参数,这种函数就称之为高阶函数。
map( f(x) ) 方法 :把f(x)作用在Array的每一个元素并把结果生成一个新的Array”
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var arr2 = arr.map(String);
console.log(arr2); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']
reduce( f(x,y) ) 方法把一个函数作用在这个Array
的[x1, x2, x3...]
上,这个函数必须接收两个参数,reduce()
把结果继续和序列的下一个元素做累积计算,其效果就是:
[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)
用reduce
实现一个数组的求和
var arr = [1, 3, 5, 7, 9];
var arr2 = arr.reduce(function (x, y) {
return x + y;
});
console.log(arr2); // 25
filter也是一个常用的操作,它用于把
Array
的某些元素过滤掉,然后返回剩下的元素。filter
()
把传入的函数依次作用于每个元素,然后根据返回值是true
还是false
决定保留还是丢弃该元素。
例如,在一个
数组
中,删掉偶数,只保留奇数,可以这么写:var arr = [1, 2, 4, 5, 6, 9, 10, 15]; var r = arr.filter(function (x) { return x % 2 !== 0; }); console.log(r); // [1, 5, 9, 15]
filter()
有多个参数。通常我们仅使用第一个参数,表示Array
的某个元素。回调函数还可以接收另外两个参数,表示元素的位置和数组本身:var r = arr.filter(function (element, index, self) { });
利用
filter
,可以巧妙地去除Array
的重复元素:var arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange']; var r = arr.filter(function (element, index, self) { return self.indexOf(element) === index; });
通常规定,对于两个元素x
和y
,如果认为x < y
,则返回-1
,如果认为x == y
,则返回0
,如果认为x > y
,则返回1
sort()
方法也是一个高阶函数,可以接收一个比较函数来实现自定义的排序。var arr = [1,3,20,10,4] arr.sort(function (x, y) { if (x < y) { return -1; } if (x > y) { return 1; } return 0; }); console.log(arr); // [1, 3, 4, 10, 20]
注意:
sort()
方法会直接对Array
进行修改,它返回的结果仍是当前Array
every()
方法可以判断数组的所有元素是否满足测试条件。
var arr = ['Apple', 'pear', 'orange'];
console.log(arr.every(function (s) {
return s.length > 0;
})); // true, 因为每个元素都满足s.length>0
find()
方法用于查找符合条件的第一个元素,如果找到了,返回这个元素,否则,返回undefined
:
var arr = ['Apple', 'pear', 'orange'];
console.log(arr.find(function (s) {
return s.toUpperCase() === s;
})); // undefined, 因为没有全部是大写的元素
findIndex()
查找符合条件的第一个元素,如果找到了,返回这个元素的索引,如果没有找到,返回-1
:
var arr = ['Apple', 'pear', 'orange'];
console.log(arr.findIndex(function (s) {
return s.toUpperCase() === s;
})); // -1,没有全是大写的字符串
forEach()
常用于遍历数组,不会返回新的数组,因此传入的函数不需要返回值:
var arr = ['Apple', 'pear', 'orange'];
var arr2 = [];
arr.forEach(x=>{
arr2.push()
}); // 依次打印每个元素
返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。