ES6 ---- 函数

650 阅读7分钟

这是我参与更文挑战的第17天,活动详情查看: 更文挑战

默认值

概念 在ES6中函数的参数支持使用默认值,当在调用函数时如果没有给函数传递实参则形参会使用默认值

语法

function test(x = 1, y = 2) {
    console.log(x, y)
}
        
test() // 1,2
test(null1) // null 1
test(15, 16) // 15, 16
test(undefined20) // 1, 20 可以使用但不推荐

注意

  1. 函数中的任意形参都可以包含默认值

  2. 传递null并不会使得形参使用默认值, 参数的值将会变成null

  3. 传递undefined会使得形参使用默认值

  4. 推荐传递了实参前的参数不要使用默认值

  5. 设置默认值形参后面的所有形参会被函数的length属性忽略

var a = function (a,b,c,d ) {}
a.length // 4

var a1 = function (a,b,c,d = 2 ) {}
a1.length // 3  忽略 d 只有abc

var a1 = function (a,b = 0,c,d ) {}
a1.length // 1 忽略b之后所有形参 a

函数的任何一个形参一旦被设置默认值,函数在声明初始化时。所有的参数都将变为独立作用域的参数

function a(x, x, y ) { }  // 正确,形参可以重复的定义
function a(x, x, y = 2 ) { }  // 错误,所有形参变成了拥有独立作用域的变量。不可以有同名参数
 
 // 观察下面代码
let x = 5        

function a(y = x) { 
// 正确, 设置了默认值后 y 作用域当前函数作用域内变量。但是赋值给y的x变量作用域函数外部
    let x = 1
    console.log(y,x)
}
// 函数的默认值是惰性求值,并不是在声明函数时就已经传递了默认值。而是在每次调用时才会调用默认值
a() //等价于 a(x) 5 1 

x = 200
a() //等价于 a(x) 200 100,函数每次调用时才会将默认值赋值给形参

函数默认值惰性赋值特性可以实现函数的特定参数不可以为空

function throwErrorOfUndefined(funcName, funcArg) {
             throw new Error('函数:'+ funcName+"缺少必传参数'"+funcArg+"'")
}
// 因为是惰性,所以函数在声明时throwErrorOfUndefined不会立即执行
function test (a = throwErrorOfUndefined('test','a')) {

}

test(123// 因为没有使用默认值,所以默认值也不会被调用

test() // 当你不传参时,函数才会调用默认值

作用域就是一个变量的有效范围,在ES6之前js只有函数作用域全局作用域。ES6引入了块级作用域,在ES6中创建块级作用域最简单方法时使用大括号"{}" (在ES6中代表块)配合拥有块级作用域的变量let const就可以实现

 {
      // 大括号代表一个代码块,有自己独立的块级作用域
      let a = 7
      console.log(a) // 7
      var b = 1
      console.log(b) // 1
}

console.log(b) // 1
console.log(a) // a is not defined

// 块 使用ES5实现方法 有两种
//  方法一利用函数作用域
(function(a) { console.log(a) })(9)
console.log(a)
// 方法二 使用try catch实现块级作用域
try {
     throw 7catch (a) {
     console.log(a)
}

console.log(a)

ES6函数拥有name,当前函数的函数名

function aaa () {
    console.log(this)
}
console.log(aaa.name) // "aaa"

let demo = function () {
    
}
console.log(demo.name) // ES5 "" ES6 "demo"

严格模式(use strict)

概念让js代码在严格的条件下执行。非严格模式下的代码很多是不符合逻辑的,严格模式可以让我们的代码更规范(提高编译效率,消除语法不严谨不合理)。也为js的升级做好铺垫。

语法声明严格模式 将"use strict" 字面量声明在文档的头部 函数的外部 函数的内部(ES6不允许)

"use strict" //正确 写在外部
function a(x, y ) { 
    "use strict" // 正确,ES5允许将 "use strict"写到函数内部
}

function a(x, y = 5) { // 错误 ES6 语法中不允许将 "use strict"写到函数内部
    "use strict"
}

// 为什么在ES6中  "use strict" 不能写在函数内部
// 我们看下面的代码,因为在ES6中函数的默认值是惰性赋值的,
// 在函数的声明时8进制数077 不会立即赋值  "use strict" 没有办法检测到这里的问题
function a( y = 077) {
    "use strict"
     return y
}
// 当调用该函数时 8进制先赋值再执行 "use strict" 不符合开发需求的
// ES6为了避免这些问题规定 "use strict" 不能写在 es6的函数内部
a()

注意 严格模式规范

// 不能使用未声明的变量
a = 7 // Error
// 不能删除对象的属性,不能删除不允许删除的属性
var x = 7
delete x // Error
delete Object.prototype //Error
// 不允许变量重命名
var a = 1
var a = 2 // Error
function (x,x) {} // Error
//不允许使用八进制
var num = 070 // Error
// 不允许使用转义符
var ascii = \010 // Error
// 不允许修改只读属性 不允许对只有get方法的属性进行复制
const person = {};
Object.defineProperty(object1, 'name', {
  value: "小明",
  writable: false // 是否允许修改该属性 false不允许 true允许
});

person.name = "小刚" // Error

const person {
    name: '小王',
    get age() {return 18}
}
person.age = 12 // Error
// 不允许声明变量名为关键字的变量
var eval = 1 // Error
var arguments = 2 // Error
var let = 3 // Error
var static = 4 // Error
var public = 5 // Error
var private = 5.1 // Error
var protected = 5.2 // Error
var package = 6 // Error
var interface = 7 // Error
var implements = 8 // Error
var yield = 9 // Error

// eval 作用域独立
eval("var a =10086") 
console.log(a)// undefined

// 不允许this 指向全局对象
"use strict"

function aaa () {
    console.log(this)
}
aaa() // undefined

案例 Object.defineProperty的使用

// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
let obj = {
    name: '小于',
    age: 40,
    address: 'bj',
    hobby: ['抽烟', '喝酒', '烫头']
}

Object.defineProperty(obj, 'hobby', {
    enumerable: false,
    writable: true
})


for (key in obj) {
    console.log(key)
}

obj.hobby = ['睡觉']

console.log(obj)

箭头函数

概念 在ES6中允许使用 => 形式声明一个函数

语法

function a (x,y) {
   return x + y + 1
}
// 上面的函数就等等价于下面的箭头函数
let a = (x, y) => x + y + 1

注意

  1. 箭头函数不能直接设置函数名,只能将箭头函数以赋值的形式传递给变量

  2. 若箭头函数 => 符号后没有跟大括号则箭头函数会将 => 后面的代码自动return (注意没有大括号的箭头函数只使用于函数内部只有一行js表达式函数), 如果箭头函数包含大括号, 则默认return功能会被取消

let a = (x, y) => x + y
 
let a = (x, y) => {
     let result = x + y + 1
     // 因为当前箭头函数包含大括号,导致自动return功能被取消
     // 这时必须使用return 返回特定的值
     return result 
}
// 如果箭头函数使用默认return功能返回一个对象,必须用()将对象包含
let a = (name, age) => ({name: name, age: age})
  1. 若箭头函数有且仅有一个参数,则参数的()可以被省略
let func = (age) => age >= 18
// 等价于
let func = age => age >= 18

4.箭头函数自身没有this。函数内部的this指向这段代码当前的作用域。

下面的代码中在setTimeout中使用箭头函数,箭头函数内部的this指向的是声明这段代码的作用域对象而不是window对象

 function Cat(name) {
    this.name = name
    this.sayHello = function () {
        console.log('Meow !')
       // 如果是普通函数 setTimeout中的this应该指向window
       // 而箭头函数指向当前代码的作用域
        setTimeout(() => console.log('你好,我叫' + this.name), 500)
    }
}

 let cat = new Cat('旺财')

 cat.sayHello()
 
 // 对象的方法不要使用箭头函数
 let cat1 = {
    name'阿橘',
    sayHello() => {
        // 因为对象是全局声明的,他的作用域就是全局
        // 这里的this就是全局对象
        console.log(this)
    }
}

cat1.sayHello() // window
  1. 箭头函数不能作为构造函数配合new 关键字使用。箭头函数本身就没有实例

  2. 箭头函数没有arguments对象

function test (x,y)  {
    // 伪数组,包含了当前函数的所有实参
    console.log(arguments// Arguments[1,2,8,0,4,5,9,7,callee]
}

test(1,2,8,0,4,5,9,7)

let test = (x,y) => {
  
    console.log(arguments// Error!箭头函数没有arguments
}

test(1,2,8,0,4,5,9,7)
  1. 箭头函数不能作为Generator函数 优势
  2. 简化 js 回调函数
for (let i = 0; i < 5; i++) {
    setTimeout(() => console.log(i), 100)
}
$.ajax({
    url"test.html",
    contextdocument.body,
    success() => $(this).addClass("done")
});

[12345].forEach(item => console.log(item));
  1. 简化柯里化函数 函数一次只能接受一个参数
function getPerson(name, age, address) {
    return {
        name: name,
        age: age,
        address: address
   }
}

getPerson('小明',18'gz')

function getPerson(name) {
    return function (age) {
        return function (address) {
            return {
                    name: name,
                    age: age,
                    address: address
                }
         }
     }
}

// ES6 箭头函数简化柯里化函数
let getPerson = name => age => address => ({
    name: name,
    age: age,
    address: address
})
getPerson('小明')(18)('gz')