ES6对比ES3\ES5

20180812

变量提升

  • 提升是浏览器解析JavaScript的结果。在执行JavaScript代码前,所有变量都会被“提升”,提升到函数作用域的顶部
function getClothing(isCold){
    if(isCold){
        var freezing = "Grab a jacket!";
    } else{
        var hot = "It's a shorts kind of day.";
        console.log(freezing)
    }
}

变量提升后相当于

function getClothing(isCold){
    var freezing,hot;
    ......
}

常量

  • ES3:无常量概念
  • ES5:给对象定义属性,绑定在window上,并设属性为只读 Object.defineProperty()
  • ES6:const定义
//ES5
Object.defineProperty(window, "PI5", {
    value: 3.1415926,
    writable: false,
})
console.log(window.PI5);

//ES6
const PI6 = 3.1415926;
console.log(PI6);

变量声明

  • var:要么为全局作用域,要么为本地作用域,也就是整个函数作用域。
  • let:作用域为块。变量可以重新赋值,但是不能在同一作用域内重新声明
  • const:作用域为块。变量必须赋初始值,但是不能在同一作用域内重新声明,也无法重新赋值
if(isCold){
    let freezing = 'Grab a jacket!';
} else{
    let hot = 'Its a shorts kind of day';
    console.log(freezing);  // not defined
}
  • 使用 let 和 const 声明的变量仅在它们所声明的块中可用.
  • 如果在代码块(用花括号 { } 表示)中使用 let 或 const 声明变量,那么该变量会陷入暂时性死区,直到该变量的声明被处理。这种行为会阻止变量被访问,除非它们被声明了。

箭头函数

  • 箭头函数与普通函数区别在于this的绑定
  • ES3\ES5:function a(){}
  • ES6:(parameters)=>{statements}; ()中参数,若只有一个参数,省略()。 {}中表达式直接作为返回值时省略。

——————————————————————–
数组遍历evens.map()
-ES3\ES5:使用evens.map(function(){})
-ES6:使用箭头函数

{
    //ES3\ES5
    var evens = [1, 2, 3, 4, 5];
    var odds = evens.map(function(v) {
        return v + 1
    });
    console.log(evens, odds);
}; 
{
    //ES6
    let evens = [1, 2, 3, 4, 5];
    let odds = evens.map(v => v + 1);  //箭头函数
    console.log(evens, odds);
}; 

——————————————————————–
this指向问题
普通函数:this的指向是该函数被调用的对象。
箭头函数:this指向的是定义时this的指向。

普通函数:
- this总是代表它的直接调用者(js的this是执行上下文),例如 obj.func ,那么func中的this就是obj;
- 在默认情况(非严格模式下,未使用 ‘use strict’),没找到直接调用者,则this指的是 window;
- 在严格模式下,没有直接调用者的函数中的this是undefined;
- 使用call,apply,bind(ES5新增)绑定的,this指的是 绑定的对象;
箭头函数:
- 箭头函数没有自己的this,它的this是继承而来;
- 默认指向在定义它时所处的对象(宿主对象),而不是执行时的对象。 定义它的时候,可能环境是window;
- 箭头函数可以方便地让我们在 setTimeout ,setInterval中方便的使用this;

{
    //ES3\ES5声明一个类,用函数作为类构造器. 
    var factory = function(){
        this.a = 'a';
        this.b = 'b';
        this.c = {
            a:'a+',
            b:function(){ //普通函数声明
                return this.a  //this的指向是该函数被调用的对象,b()由c调用
            }
        }
    }
};

使用 new factory().c.b() 访问c中b函数。b()由c调用,故b()函数体中this指向c。

{
    // ES6使用箭头函数,避免this指向不确定
    let factory=function(){  //构造函数中this指向factory的实例
        this.a = 'a';
        this.b = 'b';
        this.c = {
            a:'a+',
            b:()=>{ //箭头函数声明,箭头函数this指向是定义时this的指向。b在定义这个函数时this指向factory实例
                return this.a  
            }
        }
    }
}

使用new factory().c.b() 访问。因b使用箭头函数声明,故this指向:定义时this的指向(即指向factory实例)。

作用域

  • 函数名与执行函数
    • 函数名只是一个标识(指向函数的指针),而()才是执行函数
    • 当一个函数被调用完成之后,其执行上下文环境将被销毁,其中的变量也会被同时销毁
//ES5
const callbacks = []
for (var i = 0; i <= 2; i++) {  // var 变量提升
    callbacks[i] = function() {  //没有执行函数,函数内部不变,函数体内保存表达式而非值,形成闭包。
        return i * 2  //对变量的引用,而非对值的引用。 所以其「值」只有在执行时才能确定
    }
}

//内存回收机制:当一个函数被调用完成之后,其执行上下文环境将被销毁,其中的变量也会被同时销毁。垃圾回收callbacks[]。 
//暂不回收i(变量被引用着所以不会被回收)


//数据以表格的形式显示,接收一个强制的参数(必须是一个数组或者是一个对象)
//执行return i*2,表达式求值i=3
console.table([
    callbacks[0](),
    callbacks[1](),
    callbacks[2](),
  1. for中 callbacks[i]=function(){} 语句执行时 不能执行函数体(函数带()才是执行函数)。函数内部不变,函数体内保存表达式而非值,形成闭包
  2. callbacks[x]() 相当于执行return i * 2(此时 i==3)。
  3. for结束后,callbacks[i]使用完成,由内存回收机制回收;而i不被回收(变量被callbacksx引用着所以不会被回收)。

——————————————————————–
- 通过使用let声明的变量,保存当前块作用域的值。

const callbacks2 = []
//let声明的变量,块作用域。 每循环一次,生成一个新的作用域
for (let j = 0; j <= 2; j++) {  
    callbacks2[j] = function() {
        return j * 2  //该处闭包,取决于当前的块作用域,保存当前块作用域的值,供后面使用
    }
}

console.table([
    callbacks2[0](),
    callbacks2[1](),
    callbacks2[2](),
]);

——————————————————————–
- 作用域链
- 全局变量默认挂载在window对象下
- 当在函数中使用变量时,首先在本函数内部查找该变量,后找其父级函数,最后直到window
- 常见的window的属性和方法有: alert, location, document, parseInt, setTimeout, setInterval等, window的属性默认可以省略window前缀

  • 作用域隔离
    ES3\ES5:通过‘立即执行函数’。
//ES3\ES5
((function(){
    var foo = function(){
        return 1
    }
    console.log("foo()===1",foo()==1);

    ((function(){
        var foo = function(){ //与函数体外foo不冲突
            return 2
        }
        console.log("foo()===2",foo()==2)
    })());
    console.log("foo()===1",foo()==1);
})());

ES6:使用{}指定作用域,隔离作用域。

{
    function foo(){
        return 1
    }
    console.log("foo()===1",foo()==1);
    {
        function foo(){
            return 2
        }
        console.log("foo()===2",foo()==2);
    }
    console.log("foo()===1",foo()==1);
}

默认参数

基本使用
- ES3\ES5:x=x||1 判断是否为undefined
- ES6:function f(x,y=7,z=42){}

 {
    //ES3\ES5:默认参数写法
    function f(x,y){
        /*if(x===undefined){
            x=7;
        }
        if(y===undefined){
            y=42;
        }*/
        x = x || 7;
        y = y || 42;
        return x + y;
    }
    console.log(f(1,3));
};
{
    // ES6
    function f(x,y = 7,z = 42){
        return x + y + z;
    }
    console.log(f(1));
};

必选参数检查:通过函数checkParameter()抛出异常throw new Error();并通过try…catch捕获异常。

function checkParameter(){
    throw new Error('can\'t be empty');
}
function f(x = checkParameter(), y = 7, z = 42){
    return x + y + z;
}
try{
    f()
}catch(e){
    console.log(e)
}finally{

}

——————————————————————–
可变参数
ES3\ES5 将参数数组化:Array.prototype.slice.call(arguments)

//ES3\ES5
function f(x){
    var a = Array.prototype.slice.call(arguments);  //arguments伪数组,通过Array.prototype.slice.call()转化为数组
    var sum = 0;
    a.forEach(function(item){
        sum += item * 1;
    })
    return sum;
}
console.log(f(1,2,3));

ES6:function f(…a){}; …a扩展运算符,a为可变参数列表数组

//ES6 
function f(...a){  //...a扩展运算符,a为可变参数列表数组
    var sum=0;
    a.forEach(item=>{
        sum+=item*1  //转换为数字
    });
    return sum
}
console.log(f(2,3,4));

——————————————————————–
合并数组
ES3\ES5:.concat() 拼接数组
ES6:利用扩展运算符 var other=[1,2,…params];

{
    //ES5 合并数组
    var params=['hello',true,7];
    var other=[1,2].concat(params);
    console.log(other);
};{
    //ES6 利用扩展运算符合并数组
    var params=['hello',true,7];
    var other=[
        1,2,...params
    ];
    console.log(other);
}

对象代理

ES3\ES5:var Person = function(){}; 内部声明局部作用域,通过this.get = function(){}和this.set = function(key, value){}访问内部。

//ES3\ES5 数据保护
var Person = function() { //构造函数
    //内部声明,局部作用域。 若无this访问,则取不到data
    var data = {
        name: 'es3',
        sex: 'male',
        age: 15
    }
    this.get = function(key) {
        return data[key];
    }
    this.set = function(key, value) {
        if (key !== 'sex') {
            data[key] = value;
        }
    }
}
//声明一个实例
var person = new Person();
//读取:通过api方式
console.table({name: person.get('name'), sex: person.get('sex'), age: person.get('age')});
//修改
person.set('name', 'es3-cname');
console.table({name: person.get('name'), sex: person.get('sex'), age: person.get('age')});

person.set('sex', 'female'); //数据保护
console.table({name: person.get('name'), sex: person.get('sex'), age: person.get('age')
});

ES5 直接声明对象: Object.defineProperty(Person, ‘sex’, {writable: false,value: ‘male’}); 设置只能读不能写。

//ES5 直接声明对象,而不用构造函数
var Person = {
    name: 'es5',
    age: 15
};
//保护数据:设置只能读不能写
Object.defineProperty(Person, 'sex', {
    writable: false,
    value: 'male'
});
console.table({name: Person.name, sex: Person.sex, age: Person.age});

Person.name = 'es5-cname';
console.table({name: Person.name, sex: Person.sex, age: Person.age});

try {
    //不能为只读属性赋值
    Person.sex = 'female';
    console.table({name: Person.name, sex: Person.sex, age: Person.age});
} catch (e) {
    console.log(e);
} finally {}

ES6:let person = new Proxy(Person, {}); 以Proxy作为Person代理。person作为用户操作对象,保护Person。

//ES6
let Person = {
    name: 'es6',
    sex: 'male',
    age: 15
};
//Proxy作为Person代理。person作为用户操作对象,保护Person。
//target:Person;key:读取的属性
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});

//对代理对象person操作
try {
    person.sex = 'female';
} catch (e) {
    console.log(e);
} finally {}

猜你喜欢

转载自blog.csdn.net/qq_21980099/article/details/81607219
今日推荐