ES5中常量声明要通过Object.defineProperty函数来实现,要将常量绑定在某个控件上
// 声明一个常量属性,绑定在window上,命名PI2,值为3.1415926, 不可写
Object.defineProperty(window, "PI2", {
value: 3.1415926,
writable: false,
})
ES6中,直接通过const关键字来定义常量
const PI = 3.1415
console.log(PI)
ES5中:for循环定义的var i 为全局变量
const callbacks = []
for (var i = 0; i <= 2; i++) {
callbacks[i] = function() {
return i * 2
}
}
console.table([
callbacks[0](),
callbacks[1](),
callbacks[2](),
])
输出结果为 6 6 6
console.log(i)输出是3
for循环中的var是一个全局变量,闭包调用方法时,因为i=3,利用i*2计算出的值也就全是6
ES6中:for循环定义的let j 为局部变量,作用域为 块{}
const callbacks2 = []
for (let j = 0; j <= 2; j++) {
callbacks2[j] = function() {
return j * 2
}
}
console.table([
callbacks2[0](),
callbacks2[1](),
callbacks2[2](),
])
输出结果为 0 2 4
console.log(j) 报错,j未定义
这里for循环中的 j 的作用域为 块作用域(即{}),每循环一次,进入一次{},变量j会保存一次
闭包调用时,会调用它的执行过程中的 j 的当时值
ES5及之前,没有块作用域的概念,如果想要声明一个只能在固定区域内使用的函数,只能通过将逻辑全部包装在一个立即执行函数中的方式:
(function() {
const foo = function() {
return 1
}
console.log("foo()===1", foo() === 1)// true
// 开辟新的作用域
;((function() {
const foo = function() {
return 2
}
console.log("foo()===2", foo() === 2)// true
})())
})()
此时foo函数只能在各自的function块内调用,程序不会报错,因为两个const foo函数是在不同的作用域内
ES6中:{}及代表一个块作用域
{
function foo() {
return 1
}
console.log("foo()===1", foo() === 1)// true
// 开辟新的作用域
{
function foo() {
return 2
}
console.log("foo()===2", foo() === 2)// true
}
console.log("foo()===1", foo() === 1)// true
}
语法类似于Java中的Lambda表达式,箭头函数中的this是指向定义时的this
ES3,ES5
{
// ES3,ES5
var factory = function() {
this.a = 'a';
this.b = 'b';
this.c = {
a: 'a+',
b: function() {
return this.a // 这里this发生变化,指向调用此function的对象
}
}
}
console.log(new factory().c.b());// c调用的b(),所以this指向的是c
}
此时控制台输出b方法的值为 "a+",因为function中的this指向的是调用它的对象
ES6中
{
var factory = function() {
this.a = 'a';
this.b = 'b';
this.c = {
a: 'a+',
b: () => {
return this.a
// b 在定义这个箭头函数时,this指向factory,所以箭头函数中的this也指向factory
}
}
}
console.log(new factory().c.b());
}
此时控制台输出b方法的值为a,箭头函数中的this是指向定义时的this
ES6中的默认参数写法和C++相同
ES5\ES3 默认参数的写法,需要自己进行判断是否使用默认参数
{
// ES5\ES3 默认参数的写法,需要自己进行判断是否使用默认参数
function f(x, y, z) {
if (y === undefined) {
y = 7;
}
if (z === undefined) {
z = 42
}
return x + y + z
}
console.log(f(1, 3));
}
ES6 可变参数
{
// ES6 可变参数
function checkParameter() {
throw new Error('can\'t be empty')
}
// 可以通过默认参数赋函数的方式,对传值是否为空进行检验
function f(x = checkParameter(), y = 7, z = 42) {
return x + y + z
}
try {
f() // 触发checkParameter
} catch (e) {
console.log(e);
} finally {}
}
ES6中对可变参数的获取也变得简单,只需要使用扩展运算符(…)
ES3,ES5 可变参数
{
// ES3,ES5 可变参数
function f() {
var a = Array.prototype.slice.call(arguments);// 这里arguments就是传入的参数
var sum = 0;
a.forEach(function(item) {
sum += item * 1;
})
return sum
}
console.log(f(1, 2, 3, 6));
}
ES6 可变参数
{
// ES6 可变参数
function f(...a) { // 只需要申明扩展运算符(...),语义即为可变
var sum = 0;
a.forEach(item => {
sum += item * 1
});
return sum
}
console.log(f(1, 2, 3, 6));
}
扩展运算符的其它用法
{
// ES6 利用扩展运算符合并数组
var params = ['hello', true, 7];
var other = [
1, 2, ...params
];
console.log(other);
}
等价于
{
// ES5 合并数组
var params = ['hello', true, 7];
var other = [1, 2].concat(params);
console.log(other);
}
对象代理用来解决没有私有变量的问题,对于一个变量只希望它在对象内部被使用。
ES3数据保护
{
// ES3数据保护
var Person = function() {
var data = { // 通过类初始函数声明一个隐私的数据
name: 'es3',
sex: 'male',
age: 15
}
// 声明getter、setter方法使外部对它操作
this.get = function(key) {
return data[key]
}
this.set = function(key, value) {
if (key !== 'sex') { // 'sex'属性设置为只读
data[key] = value
}
}
}
}
ES5中可以采用声明常量绑定的方式
{
// ES5中可以采用声明常量绑定的方式
var Person = {
name: 'es5',
age: 15
};
// 声明属性,绑定在Person对象上,属性名为'sex',值为'male',不可写
Object.defineProperty(Person, 'sex', {
writable: false,
value: 'male'
});
}
ES6中使用对象代理的方式
{
// ES6中使用对象代理的方式
let Person = {
name: 'es6',
sex: 'male',
age: 15
};
// 赋值一个代理类将原对象保护起来,代理对象为Person
let person = new Proxy(Person, {
get(target, key) {
return target[key]
},
set(target,key,value){
if(key!=='sex'){
target[key]=value;
}
}
});
console.table({
name:person.name,
sex:person.sex,
age:person.age
});
try {
person.sex='female';
} catch (e) {
console.log(e);
} finally {
}
}