首页 > 编程语言 >javascript函数的理解

javascript函数的理解

时间:2022-11-30 17:58:54浏览次数:73  
标签:function return 函数 age javascript 理解 birth var

参考:https://www.liaoxuefeng.com/wiki/1022910821149312/1023021087191360

在js里,函数是一等公民。

  • 函数可以分配给变量
  • 函数可以作为参数传递给其他函数
  • 函数可以从其他函数返回

1 定义函数

方式1

function abs(x) {
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
}

方式2

var abs = function (x) {
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
};

其中方式2定义了一个匿名函数,然后赋值给abs

上述两种定义完全等价

2 调用函数

JavaScript允许传入任意个参数而不影响调用,因此传入的参数比定义的参数多也没有问题,虽然函数内部并不需要这些参数

abs(10, 'blablabla'); // 返回10
abs(-9, 'haha', 'hehe', null); // 返回9

传入的参数比定义的少也没有问题

 abs(); // 返回NaN 

此时abs(x)函数的参数x将收到undefined,计算结果为NaN。

3 arguments

JavaScript还有一个关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array

function foo(x) {
    console.log('x = ' + x); // 10
    for (var i=0; i<arguments.length; i++) {
        console.log('arg ' + i + ' = ' + arguments[i]); // 10, 20, 30
    }
}
foo(10, 20, 30);
//运行结果为
x = 10
arg 0 = 10
arg 1 = 20
arg 2 = 30

4 ...参数

ES6引入了一个新的函数参数写法...

function foo(a,b,...rest){
    console.log(a)
    console.log(b)
    console.log(rest)
}
foo(1,2,3,4,5)
//运行结果
1
2
[3, 4, 5]

5 解构赋值

ES6引入解构赋值

var [x, y, z] = ['hello', 'JavaScript', 'ES6'];
let [, , z] = ['hello', 'JavaScript', 'ES6']; // 忽略前两个元素,只对z赋值第三个元素
//从一个对象中取出若干属性
var person = {
    name: '小明',
    age: 20,
    gender: 'male',
    passport: 'G-12345678',
    school: 'No.4 middle school'
};
var {name, age, passport} = person;
//对一个对象进行解构赋值时,同样可以直接对嵌套的对象属性进行赋值,只要保证对应的层次是一致的
var person = {
    name: '小明',
    age: 20,
    gender: 'male',
    passport: 'G-12345678',
    school: 'No.4 middle school',
    address: {
        city: 'Beijing',
        street: 'No.1 Road',
        zipcode: '100001'
    }
};
var {name, address: {city, zip}} = person;
//输出结果
name; // '小明'
city; // 'Beijing'
zip; // undefined, 因为属性名是zipcode而不是zip
// 注意: address不是变量,而是为了让city和zip获得嵌套的address对象的属性:
address; // Uncaught ReferenceError: address is not defined

如果要使用的变量名和属性名不一致,可以用下面的语法获取

var person = {
    name: '小明',
    age: 20,
    gender: 'male',
    passport: 'G-12345678',
    school: 'No.4 middle school'
};

// 把passport属性赋值给变量id:
let {name, passport:id} = person;
name; // '小明'
id; // 'G-12345678'
// 注意: passport不是变量,而是为了让变量id获得passport属性:
passport; // Uncaught ReferenceError: passport is not defined

6 方法

绑定到对象的函数称为方法。

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
};

xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年调用是25,明年调用就变成26了

7 this关键字

上例中方法中的this指的是当前对象。

但是,全局的this指的是window对象

8 函数的apply()方法

我们看一下下面的代码

function getAge() {
    var y = new Date().getFullYear();
    return y - this.birth;
}

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};

xiaoming.age(); // 25, 正常结果
getAge(); // NaN

如果以对象的方法形式调用,比如xiaoming.age(),该函数的this指向被调用的对象,也就是xiaoming,这是符合我们预期的。

如果单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window

我们可以使用函数的apply方法对上例做一下改造,使得单独调用getAge()时指向函数内部this的指向

function getAge() {
    var y = new Date().getFullYear();
    return y - this.birth;
}

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};

xiaoming.age(); // 25
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空

9 函数的call()方法

call()方法和与apply()类似,唯一的区别是

  • apply()把参数打包成Array再传入;

  • call()把参数按顺序传入。

Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5

10 apply()实现装饰器

这个例子我们修改window.parseInt()方法,加上我们定制化的代码。

'use strict';

var count = 0;
var oldParseInt = parseInt; // 保存原函数

window.parseInt = function () {
    count += 1;
    return oldParseInt.apply(null, arguments); // 调用原函数
};

后续执行parseInt('3')将会首先计算count值,然后再调用真实的parseInt()。起到装饰器的作用

11 高阶函数

如果一个函数,其参数也是一个函数,则我们称之为高阶函数

11.1 map

map()方法定义在Array中

用法举例

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var results = arr.map(x=>x*x); // [1, 4, 9, 16, 25, 36, 49, 64, 81]

上面,我们可以一眼就可以看出代码的用意,即把f(x)=x2作用在Array的每一个元素并把结果生成一个新的Array

再举例,我么把一个整型数组转换为对应的字符串数组

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(String); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']

11.2 reduce

reduce()方法也是Array中定义

在一个数组上应用reduce函数,效果如下

[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)

举例

var arr = [1, 3, 5, 7, 9];
arr.reduce((x, y)=>x+y); // 25

11.3 filter

filter()方法也是定义在Array上

举例

var arr = [1, 2, 4, 5, 6, 9, 10, 15];
arr.filter(x=> x % 2 !== 0);

11.4 Array上其他的高阶函数

除了上面提到的高阶函数,还有一些常用的高阶函数:sort、every、find、findIndex、forEach

12 闭包

定义枯燥无味且难于理解,我们举例说明

我们定义一个函数lazy_sum(),用于计算一个数组的和,我们不返回求和结果,而是返回一个函数

function lazy_sum(arr) {
    var sum = function () {
        return arr.reduce((x, y) => x + y);
    }
    return sum;
}
var f=lazy_sum([1,2,3,4,5])
f() //执行结果是15

在这个例子中,我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,故称之为闭包。这种称为“闭包(Closure)”的程序结构拥有极大的威力。

13 箭头函数

箭头函数可以解决this指向问题

举例,

如果我们不用箭头函数

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = function () {
            return new Date().getFullYear() - this.birth; // this指向window或undefined
        };
        return fn();
    }
};

调用结果

obj.getAge()
NaN

我们使用箭头函数,则完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
        return fn();
    }
};

调用结果

obj.getAge()
32

14 generator

ES6引入了一个新的数据类型generator

generator定义

function* foo(x) {
    yield x + 1;
    yield x + 2;
    return x + 3;
}

generator和函数不同的是,generator由function*定义(注意多出的*号),并且,除了return语句,还可以用yield返回多次

调用

var f=foo(1)
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: false}
f.next(); // {value: 4, done: true}

generator的一个巨大的好处,就是把异步回调代码变成“同步”代码。

有了generator,发送ajax请求时就可以很优雅的写

try {
    r1 = yield ajax('http://url-1', data1);
    r2 = yield ajax('http://url-2', data2);
    r3 = yield ajax('http://url-3', data3);
    success(r3);
}
catch (err) {
    handle(err);
}

 

标签:function,return,函数,age,javascript,理解,birth,var
From: https://www.cnblogs.com/zhenjingcool/p/16936808.html

相关文章

  • iTOP2k1000开发板Makefile基本语法-wildcard函数
    格式:$(wildcardPATTENR)功能:展开指定的目录举例:在/home/topeet/test目录有一个“a.c”的c文件和一个test的文件夹,在/home/topeet/test/test文件夹下有一个......
  • select_related和prefetch_related函数
    在数据库存在外键的其情况下,使用select_related()和prefetch_related()很大程度上减少对数据库的请求次数以提高性能在表中查找数据的时候,使用外键表related_name里面的值......
  • lambda 标准函数
    1、标准函数let,also,with,run和apply1)、let函数,必须让某个对象调用,接收一个Lambda表达式参数,Lambda表达式中的参数为当前调用者,且最后一行代码作为返回值2)、also函数......
  • 用递归函数实现反序输出正整数
    大家下午好呀,今天的分享就是我的作业啦,可能对一些大佬来说很基础,但是我经过综合多方意见,终于写出来啦首先是题目然后我们分析下这道题,一开始我是很懵逼的,不知道老师为啥要说......
  • Job/CronJob的理解(chrono《kubernetes入门实战课》笔记整理)
    【k8s所有的服务是否都可以集成在一个个pod里?】pod里,已经可以直接调度其内部所有的容器,来一起提供一个整体的应用。为什么k8s还有其他额外的对象来做k8s的其他服务呢,直接......
  • 对于事件event触发中this的理解
    上面是书籍中事件触发中MarryEvent(this,newEventArgs());其中this就是类Bridegroon,将this更改为newBridegroom也是可以的;那么,我本示例中,我们将this更改为其它对象可不......
  • Python学习(二):字符串常用函数有哪些?
    1.检验字符串长度:len(str);a="hellopython"len(a)12a="hellopython"len(a[::2])##从头取到尾,隔一个取值的长度6 2.切割字符串:obj.split(str);a="hell......
  • [JavaScript] 自顶向下学习如何手写promise
    引子去年写了一篇有关promise的手写文章,写到一半发现自己的理解还不是很透彻,写的很烂,今年卷土重来,实现部分采用功能分解,目录跳转的形式呈现,力求最通俗易懂得剖析promise,我......
  • 深入理解Docker中Container
    Container与Image的关系既然container是由image运行起来的,那么是否可以理解为container和image有某种关系?其实可以理解为container只是基于image之后的layer而已,也就是可以......
  • Docker的深入理解
    深入探讨Image 说白了,image就是由一层一层的layer组成的。官方image​​https://github.com/docker-library​​例如tomcat的地址​​https://github.com/docker-library/t......