当前位置: 首页 > news >正文

数据类型之函数笔记

  1. 函数声明的方式:
//函数声明,结尾无需分号
function print(s) {
  console.log(s);
}
复制代码
//将一个匿名函数赋值给变量,称函数表达式,语句结尾需要分号
//如果写上函数名,用处:可以在函数体内部调用自身;方便除错
var print = function(s) {
  console.log(s);
};
复制代码
//不直观的构造函数,少用
var add = new Function(
  'x',//参数
  'y',//参数
  'return x + y'//函数体
);

// 等同于
function add(x, y) {
  return x + y;//函数体
}
复制代码
  1. 如果同一个函数被多次声明,后面的声明就会覆盖前面的声明。
  2. 函数可以调用自身,这就是递归(recursion)。
//计算斐波那契数列
function fib(num) {
  if (num === 0) return 0;
  if (num === 1) return 1;
  return fib(num - 2) + fib(num - 1);
}

fib(6) // 8
复制代码
  1. 凡是可以使用值的地方,就能使用函数。可以把函数赋值给变量和对象的属性,也可以当作参数传入其他函数,或者作为函数的结果返回。函数与其他数据类型地位平等,在 JavaScript 语言中称函数为第一等公民。
  2. JavaScript 引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。但是,如果采用赋值语句定义函数,JavaScript 就会报错。

如果同时采用function命令和赋值语句声明同一个函数,最后总是采用赋值语句的定义。

var f = function () {
  console.log('1');
}

function f() {
  console.log('2');
}

f() // 1
复制代码
  1. 函数的name属性返回函数的名字。如果是通过变量赋值定义的函数,那么name属性返回变量名。如果变量的值是一个具名函数,那么name属性返回function关键字之后的那个函数名。函数的length属性返回函数预期传入的参数个数,即函数定义之中的参数个数。函数的toString方法返回一个字符串,内容是函数的源码包括注释。
  2. 函数外部声明的变量就是全局变量(global variable),可以在函数内部读取。在函数内部定义的变量,外部无法读取,称为“局部变量”(local variable)。函数内部定义的变量,会在该作用域内覆盖同名全局变量。对于var命令来说,局部变量只能在函数内部声明,在其他区块中(比如if语句中)声明,一律都是全局变量。
  3. 与全局作用域一样,函数作用域内部也会产生“变量提升”现象。
  4. 函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域。
var a = 1;
var x = function () {
  console.log(a);
};

function f() {
  var a = 2;
  x();
}

f() // 1
复制代码
  1. 函数参数不是必需的,JavaScript 都不会报错。省略的参数的值就变为undefined。没有办法只省略靠前的参数,而保留靠后的参数。如果一定要省略靠前的参数,只有显式传入undefined。
function f(a, b) {
  return a;
}

f( , 1) // SyntaxError: Unexpected token ,(…)
f(undefined, 1) // undefined
复制代码
  1. 函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是传值传递(passes by value)。这意味着,在函数体内修改参数值,不会影响到函数外部。 如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递(pass by reference)。也就是说,传入函数的原始值的地址,因此在函数内部修改参数,将会影响到原始值。如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值。
var p = 2;

function f(p) {
  p = 3;
}
f(p);

p // 2
复制代码
var obj = { p: 1 };

function f(o) {
  o.p = 2;
}
f(obj);

obj.p // 2
复制代码
var obj = [1, 2, 3];

function f(o) {
  o = [2, 3, 4];
}
f(obj);

obj // [1, 2, 3]
复制代码
  1. 如果有同名的参数,则取最后出现的那个值。
function f(a, a) {
  console.log(a);
}

f(1) // undefined
复制代码

使用arguments对象。

function f(a, a) {
  console.log(arguments[0]);
}

f(1) // 1
复制代码
  1. arguments对象:一种可以在函数体内部读取所有参数的机制。 正常模式下,arguments对象可以在运行时修改。
var f = function(a, b) {
  arguments[0] = 3;
  arguments[1] = 2;
  return a + b;
}

f(1, 1) // 5
//严格模式下,arguments对象只读,修改无效,不报错。
复制代码

arguments.length判断函数调用时到底带几个参数。 arguments,类数组。数组专有的方法(比如slice和forEach),不能在arguments对象上直接使用。 将arguments转为真数组:

var args = Array.prototype.slice.call(arguments);

// 或者
var args = [];
for (var i = 0; i < arguments.length; i++) {
  args.push(arguments[i]);
}
复制代码

arguments对象带有一个callee属性,返回它所对应的原函数。可以通过arguments.callee调用函数自身。严格模式禁用,不建议使用。

var f = function () {
  console.log(arguments.callee === f);
}

f() // true
复制代码
  1. 闭包的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在。
function createIncrementor(start) {
  return function () {
    return start++;
  };
}

var inc = createIncrementor(5);

inc() // 5
inc() // 6
inc() // 7

复制代码

闭包的另一个用处,是封装对象的私有属性和私有方法。滥用闭包会造成网页的性能问题。 15. 立即执行函数的写法:

(function(){ /* code */ }());
// 或者
(function(){ /* code */ })();
//最后分号必须
复制代码

任何让解释器以表达式来处理函数定义的方法,都能产生同样的效果。下面的写法都可以。

var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();
!function () { /* code */ }();
~function () { /* code */ }();
-function () { /* code */ }();
+function () { /* code */ }();
复制代码

只对匿名函数使用这种“立即执行的函数表达式”。它的目的有两个:一是不必为函数命名,避免了污染全局变量;二是 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。

本文整理自阮一峰所作《JavaScript教程》。

转载于:https://juejin.im/post/5c1097185188250d2722aa06

相关文章:

  • Flutter redux 进阶
  • 为什么携程要做好持续交付?
  • 变频电源老化测试重要吗?需要做老化测试吗
  • JS笔记1
  • EOS区块链智能合约开发
  • Oracle 11g:bin目录下3个特效权限的文件:root用户所有者 + s权限
  • 如何使用虚拟机来运行linux,并通过ftp来访问linux服务器(多图详细教学)
  • FaaS 的简单实践
  • 身为极客,一道题测出你究竟有多机智!|活动推荐
  • java web service 写入图片到web/img/
  • 通过调研开源基准测试集,解读大数据的应用现状和开源未来
  • 如何保证以太坊DApp本地存储localStorage的安全性?
  • 数据库做分表查询
  • mount时候遇到mount: /dev/sdd1 写保护,将以只读方式挂载。mount: 未知的文件系统类型“(null)”...
  • 阿里云开发者工具上手体验
  • [NodeJS] 关于Buffer
  • Angular 响应式表单 基础例子
  • Angularjs之国际化
  • co模块的前端实现
  • Docker容器管理
  • httpie使用详解
  • IDEA 插件开发入门教程
  • in typeof instanceof ===这些运算符有什么作用
  • JAVA并发编程--1.基础概念
  • js递归,无限分级树形折叠菜单
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • Linux Process Manage
  • Python_OOP
  • RxJS: 简单入门
  • webgl (原生)基础入门指南【一】
  • 不发不行!Netty集成文字图片聊天室外加TCP/IP软硬件通信
  • 浮现式设计
  • 汉诺塔算法
  • 后端_MYSQL
  • 前端每日实战:61# 视频演示如何用纯 CSS 创作一只咖啡壶
  • 使用Swoole加速Laravel(正式环境中)
  • 微信小程序开发问题汇总
  • 详解NodeJs流之一
  • postgresql行列转换函数
  • ​iOS安全加固方法及实现
  • ​力扣解法汇总946-验证栈序列
  • #ubuntu# #git# repository git config --global --add safe.directory
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • (02)Cartographer源码无死角解析-(03) 新数据运行与地图保存、加载地图启动仅定位模式
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (js)循环条件满足时终止循环
  • (Ruby)Ubuntu12.04安装Rails环境
  • (板子)A* astar算法,AcWing第k短路+八数码 带注释
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (分布式缓存)Redis哨兵
  • (六)软件测试分工
  • (四)Controller接口控制器详解(三)
  • (新)网络工程师考点串讲与真题详解
  • (一)SpringBoot3---尚硅谷总结
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite