函数的扩展

1、函数参数的默认值

es6 之前不能直接为函数的参数指定默认值,只能采用变通方法

function fun (x, y) {
    y = y || ‘world‘
    console.log( x ,y)
}

fun (‘hello‘)   // hello world
fun (‘hello‘, ‘china‘)  // hello china
fun (‘hello‘, ‘‘)  // hello world

以上代码的缺陷在于,当参数 y 所赋值的类型为 false时,该赋值不起作用,就像 y 赋值为空字符,结果被改成了 ‘world‘

为了避免这个问题,通常需要先判断一下参数y是否被赋值,如果没有,再等于默认值

if (typeof y === ‘undefined‘) {
  y = ‘World‘;
}

es6 允许为函数的参数设置默认值,直接写在参数定义的后面

function test(x, y = ‘world‘){
    console.log(‘默认值‘,x,y);
  }
  test(‘hello‘);   // 默认值 hello world
  test(‘hello‘,‘kill‘);  // 默认值 hello kill

这里需要注意以下 4点

(1)、参数变量是默认声明的,所以不能用let或const再次声明

function foo(x = 5) {
  let x = 1;
}
foo ()   // Uncaught SyntaxError: Identifier ‘x‘ has already been declared

(2)、使用参数默认值时,函数不能有同名参数

// 不报错
function foo(x, x, y) {
  // ...
}

// 报错
function foo(x, x, y = 1) {
  // ...
}
// SyntaxError: Duplicate parameter name not allowed in this context

(3)、参数默认值不是传值的,而是每次都重新计算默认值表达式的值。也就是说,参数默认值是惰性求值的

let x=‘test‘;
function test2(x,y=x){
   console.log(x,y);   // x = test or x = kill
}
 test2(‘kill‘);   // kill kill

(4)、如果传入undefined,将触发该参数等于默认值,null则没有这个效果

function foo(x = 5, y = 6) {
  console.log(x, y);
}

foo(undefined, null)   // 5 null

2、rest 参数

rest 参数(形式为 ...arg),用于获取函数多余的参数,存放到数组中

function test3(...arg){
    for(let v of arg){
      console.log(‘rest‘,v);
    }
  }
  test3(1,2,3,4,‘a‘);

// rest 1
// rest 2
// rest 3
// rest 4
// rest a

再来看一个给类数组对象排序的例子

// es5
function sortNumbers() {
  return Array.prototype.slice.call(arguments).sort();
}

// es6
const sortNumbers = (...numbers) => numbers.sort();

rest 参数中的变量代表一个数组,所以数组特有的方法都可以用于这个变量。下面是一个利用 rest 参数改写数组push方法的例子

function push(array, ...items) {
  items.forEach(function(item) {
    array.push(item);
    console.log(item);
  });
}

var a = [];
push(a, 1, 2, 3)  // 1 2 3

注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错

// 报错
function f(a, ...b, c) {
  // ...
}

函数的length属性,不包括 rest 参数

(function(a) {}).length  // 1
(function(...a) {}).length  // 0
(function(a, ...b) {}).length  // 1

3、箭头函数

es6 允许使用“箭头”(=>)定义函数

let arrow = v => v*2

// 等同于
function arrow (v) {
    return v*2
}

let arrow2 = () => 5
// 等同于
function arrow2 () {
    return 5
}

如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回

var sum = (num1, num2) => { return num1 + num2; }

由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号

var getTempItem = id => ({ id: id, name: "Temp" })

箭头函数可以与变量解构结合使用

const full = ({ first, last }) => first + ‘ ‘ + last;

// 等同于
function full(person) {
  return person.first + ‘ ‘ + person.last;
}

箭头函数有几个使用注意点。

(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象

(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误

(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替

(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数

上面四点中,第一点尤其值得注意。this对象的指向是可变的,但是在箭头函数中,它是固定的

function foo() {
  setTimeout(() => {
    console.log(‘id:‘, this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 });   // id: 42

箭头函数可以让setTimeout里面的this,绑定定义时所在的作用域,而不是指向运行时所在的作用域。下面是另一个例子

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  // 箭头函数
  setInterval(() => this.s1++, 1000);
  // 普通函数
  setInterval(function () {
    this.s2++;
  }, 1000);
}

var timer = new Timer();

setTimeout(() => console.log(‘s1: ‘, timer.s1), 3100);   // s1:  3
setTimeout(() => console.log(‘s2: ‘, timer.s2), 3100);   // s2:  0

上面代码中,Timer函数内部设置了两个定时器,分别使用了箭头函数和普通函数。前者的this绑定定义时所在的作用域(即Timer函数),后者的this指向运行时所在的作用域(即全局对象)。所以,3100毫秒之后,timer.s1被更新了3次,而timer.s2一次都没更新

时间: 2024-07-31 14:30:45

函数的扩展的相关文章

关于C gets,fgets,gets_s函数一些扩展

自己写的,第一位观众席肯定是留给自己的. 前言废话: 工作之后总是忘不了当初学C时的感觉,那种调试,改错,成功后喜悦.虽简单到麻木,但是那是真的有点喜欢. 估计同老剧本很像,没钱时,放弃了自己喜欢的,有钱时,又想回去找Ta.估计也想是我那朋友"网视悠悠"说的"人生的矛盾" 之一吧.随着自己学习的深入,从最初的M$的.Net开发,逐渐走向C开发.也解决了最初的语言问题.因为我本身就不是 一个纯粹的程序员.我以前学的是数学.一直瞧不起搞编程的.这么简单的活.就是在玩堆积

Javascript使用函数apply扩展环境对象

Javascript使用函数apply扩展环境对象 通过实例对象作为参数传入调用构造函数对象的apply方法,以使实例对象作为环境对象在作为一个普通函数的构造函数中执行,构造函数的属性会覆盖到实例对象上,从而实现实例对象的属性扩展. 1.函数对象的apply和call传入参数     var tag = "global";      function say(){          for(var args = "", i = 0; i < arguments

编译器对C++ 11变参模板(Variadic Template)的函数包扩展实现的差异

编译器对C++ 11变参模板(Variadic Template)的函数包扩展实现的差异 题目挺绕口的.C++ 11的好东西不算太多,但变参模板(Variadic Template)肯定是其中耀眼的一颗明星,在C++设计新思维中,你可以看到很多模版的代码为了支持不确定的参数个数,而要重载1个参数到N个模板参数的N个函数.虽然种代码一般也是用会用宏和脚步辅助生成.但我想也没有人愿意看到几千行这种单调的函数.通过这个东东,模板的威力可以爆发. 目前的最新的编译器基本都已经支持Variadic Tem

ES6 - Note3:数组、对象与函数的扩展

一.数组的扩展,ES6在数组扩展了一些API,以实现更多的功能 1.Array.from:可以将类数组和可遍历的数据结构转换成真正的数组,如下所示 var a = { '0':1,'1':1,length:2 }; var arr = Array.from(a); console.log(arr) Array [ 1, 1 ] ---------------ES5的实现----------- var arr = [].slice.call(a); console.log(arr) Array [

第七课:数值以及函数的扩展和修复

1.数值扩展和修复 toFixed(num) 方法可把 Number 四舍五入为指定小数位数的数字.num必需,规定小数的位数,是 0 ~ 20 之间的值,包括 0 和 20,有些实现可以支持更大的数值范围.如果省略了该参数,将用 0 代替.返回 NumberObject 的字符串表示,不采用指数计数法,小数点后有固定的 num 位数字.如果必要,该数字会被舍入,也可以用 0 补足,以便它达到指定的长度.如果 num 大于 le+21,则该方法只调用 NumberObject.toString(

sqlserver 只有函数和扩展存储过程才能从函数内部执行

一个SQLServer的自定义函数中调用一个自定义的存储过程,执行此函数后发出如下提示:“只有函数和扩展存储过程才能从函数内部执行". 原因:函数只能使用简单的sql语句,逻辑控制语句,复杂一点的存储过程是不能调用的,在函数里也不能使用execute  sp_executesql  或者execute .解决方法把函数改为存储过程,然后在另一个存储过程中象调用函数一样使用此存储过程就可以了. 下面是一个存储过程调用另一个存储过程的实例,有参数传递的. --存储过程sp_B    create 

ES6学习(二):函数的扩展

chapter07 函数的扩展 7.1 函数默认值 7.1.1 参数默认值简介 传统做法的弊端(||):如果传入的参数相等于(==)false的话,仍会被设为默认值,需要多加入一个if判断,比较麻烦. 参数变量是默认声明的,不可在函数体内部重复声明. 参数的默认值会在每次调用的时候重新计算 7.1.2 和解构赋值默认值结合使用 用两个例子来说明 Example1 function foo({x, y=5}) { console.log(x, y); } foo({}) // undefined,

Kotlin教程学习-dataclass,objectclass,use函数,类扩展,socket

Kotlin提供了一些机制来扩展已有的类,如下: 还记得我们之前写过的Point3D类吗?(将其略作修改,将成员变量改为Double类型) 让我们为其扩展一个length函数 扩展的方法很简单,只要在函数名前面加上类名就行了. 这样Point3D的对象就有了一个名为length的方法. 运行的结果不出所料: 除此之外,在Kotlin中还有一些特殊的类,比如Data Class: 有些类只包含数据,不需要包含方法,就可以声明为data class,当然data class并不是不能包含方法. da

ES6函数的扩展

1.运用ES6的默认参数 2.|| 和  |     && 和  & 什么区别? https://zhidao.baidu.com/question/2118237346586349547.html a||b  a为true的话后面就不执行了a|b   a为true的话后面继续判断ba&&b   a如果是false 后面的b就不去判断a&b   a如果是false 后面继续判断b 3.rest参数(形式为"...变量名")可以称为不定参数

ES6小实验-函数的扩展

函数参数默认值 ES6允许为函数的参数直接设置默认值,即直接写在参数定义的后面 function log (x, y = "world") { console.log(x, y) } log("Hello")//Hello world 上面代码中,y是默认声明的,参数默认值可以与解构赋值的默认值,结合使用 function log ({x, y = "world"}) { console.log(x, y) } log({x: "Hel