var、let、const、解构、new和函数

117 阅读4分钟

1. var声明

es6以前只有使用var关键字声明变量,var有变量提升且可以重复声明

    var a = 11

声明了一个a的变量,变量值为11

    function foo(){
        var a = 11
        
        return a
    }
    
    foo()    //11

这里在foo函数中声明了一个a的变量,变量值为11,函数返回a变量


function foo(){
    var a = 11
    return function g(){
       var num = a+1
       return num
    }
}

let f = foo()
f()  //12

上面的例子中,g可以获取到foo函数中的a变量,并在每次调用g函数时都会访问到a变量,gfoo执行完之后,仍然可以调用a变量

作用域

不同于其他语言,javascript中var变量的作用域毕竟奇怪,如

function foo(num){
    if(num > 10){
        var a = num
    }
    return a
 }
 
 foo(11)  //11
 foo(9)   //undefined

在上面函数中,只有传参大于10才会声明a变量,但是传参小于10时,却返回undefined(变量存在,但是未赋值)。

在javascript中,var变量存在变量提升,即var变量会被放到函数或全局作用域的顶部,位于作用域中代码之前,变量提升让同一作用域中的代码不用考虑变量是否已经声明就可以直接使用,但是在实践中会有些奇怪的现象,例如:

    console.log(a)  //undefined
    var a = 11
    
    //---------等价于-------------
    var a;
    console.log(a)  //undefined
    a = 11

2.let和const 声明

es6中,新增了变量声明关键字letconst,它们都是块级作用域。 区块中出现了let const时,就会成为封闭作用域,在这个作用域中声明之前使用就会报错 所以它们都不存在变量提升并且不能重复声明。

console.log(a)  //ReferenceError

let a = 11

let a = 12  //Uncaught SyntaxError

const使用方式大致与let相同,都在声明所在的作用域中有效。不同在于const是保存一个只读常量,一旦声明就不可以更改。

但是const本质是变量所指向的内存地址所保存的数据不可更改。所以对于简单类型(数值、字符串、布尔值)来说是常量,但是如果是复杂类型(数组,对象)来说并不是。

let a = []
a.push('hello')  //成功
a= ['hello']  //失败报错

作用域

function foo(){
    let a = 11
}

function fooC(){
    const a = 11
 }

上面两个例子中,foo函数就是一个区块,区块中使用了let const,这时就形成了封闭作用域,在这个作用域中,不可以在变量未声明时使用变量

3.解构赋值

es6允许按照一定模式,从数组或对象中提取值,对变量进行赋值,这个步骤叫做解构

//以前赋值
let a = 1
let b = 2
let c = 3

es6可以允许写成

let [a,b,c] = [1,2,3]  //数组解构
let {a,b,c} = {a:1,b:2,c:3}  //对象解构

上面是从数组中取值,按照对应位置进行变量赋值

在解构赋值中,只要等号两边的模式相同,就可以将右边的值赋给左边。 但是当两边模式不等时就会解构失败,左边未进行赋值的变量会声明成功,但是不会有值。

let [a,b] = [1]  //a=1 b=undefined

解构函数允许指定默认值

let {name='juejin',age=12} = {name:'baidu',age:11}   //name=baidu age = 11
let {name='juejin',age=12} = {}  // name=juejin age = 12

4.new

new关键字是把被new的对象绑定到新对象的prototype

let superFoo = function (){
    let name = 'superFoo'
    this.age = 12
    this.setName = function(){}
}

superFoo.prototype.getName = function(){
    return this.name
}

let ins = new superFoo()

image.png

这个例子中,创建了一个函数superFoo,并且给函数的原型添加了getName方法,然后通过new创建了一个新的函数,这时函数superFoo就相当于构造函数

具体的,在函数前加上new操作符,这时函数就是构造函数

5、函数

函数的声明

常见函数是通过function关键字,其后是函数名与函数体组成

function foo(...arg){
    ...
}

用这种方式声明函数需要注意点,

  • 1.当前作用域会声明一个与函数名相同的变量名,变量指向这个函数
  • 2.这个函数会有变量提升的情况,如下例子
    foo()  //object
    
function foo(){
    console.log('object');
}

字面量函数

字面量函数就是声明一个变量,并将一个函数赋值给这个变量

let foo = function(){
...
}

这个例子中,声明了一个foo变量,并且将一个函数赋值给了这个变量,因为变量是let,所以不存在变量提升的情况

这个函数一般用于只使用一次,之后不会再用的情况

箭头函数

es6中新增的函数语法糖,是使用包含形参的括号,双箭头号=>与函数体组成

let test = (...args)=>{console.log(...args)}

注意点:

  • 没有this,或者说箭头函数的this是定义时的环境
  • 不可以new实例化
  • this不可变
  • 没有arguments对象
  • 没有prototype原型