JS 核心之函数

函数是一段可以反复调用的代码块。
函数还能接受输入的参数,不同的参数会返回不同的值。

一、Function 对象

1. 构造函数

Function 构造函数可以创建一个新的 Function 对象,它的语法:

new Function (arg1, arg2, ...argN, functionBody)

用 Function 创建函数时加不加 new 效果是一样的:

var f = new Function('a', 'b', 'return a+b')
var f = Function('a', 'b', 'return a+b')
// f(1,2)    3
2. 字符串之间加变量
var n = 1
var f = new Function('x','y','return x+' + n + '+y')
// f(1,2)   4
3. functionFunction 的区别

function 是关键字,与 var 用法相似,function 用来声明一个函数。
Function 是全局对象,window.Function 用法与 window.Object 相似,也可以用来声明函数。

二、函数的声明

函数有五种声明方式。

1. 具名函数
function f(x, y){
  return x+y
}

函数可以没有参数,但必须有返回值,不写的话则自动 return undefined.

2. 匿名函数
 var f
 f = function(x, y){
     return x+y
 }

单独声明一个匿名函数会报错,需把它赋给一个变量才可以。

3. 具名函数赋值
 var f
 f = function f2(x, y){ return x+y }
 console.log(f2) // Uncaught ReferenceError: f2 is not defined

注意:打印 f2 时报错。采用表达式声明函数时,function 命令后面若加上函数名,该函数名只在函数体内部有效,在函数体外部无效。

4. window.Function
 var f = new Function('x','y','return x+y')
5. 箭头函数
 var f = (x, y) => { return x+y }
 var sum = (x, y) => x+y
 var n2 = n => n*n

箭头函数没有函数名。
如果只有一个参数,可以省略 ()
如果函数体只有一句话,可以同时省略 {}return,不能只省略一个。

三、函数的属性和方法

1. name 属性
  • 函数的 name 属性返回函数的名字。
function f1() {}
f1.name // "f1"
  • 如果是通过变量赋值定义的匿名函数,那么 name 属性返回变量名。
var f2 = function () {};
f2.name // "f2"
  • 若变量的值是一个具名函数,name 属性返回 function 关键字之后的那个函数名。
var f3 = function f4() {};
f3.name // 'f4'
f4.name // 报错
  • 若用 Function 构造一个函数,name 属性返回 anonymous,即“匿名的”。
 var f5 = new Function('x','y','return x+y')
 f5.name // "anonymous"
2. length 属性

函数的 length 属性返回函数定义时的参数个数。无论调用时输入了多少个参数,length 属性始终不变。

function f(x, y) {}
f.length // 2
3. call() 方法

f.call() 方法用来调用函数,即执行这个函数的函数体。f只是代表这个函数,并不能执行它。

f.call(asThis, input1,input2)

其中 asThis 会被当做 this[input1,input2] 会被当做 arguments.

function f(x,y){ return x+y }
f.call(undefined, 1,2) // 3

新手调用函数时最好不要直接用 f(),用 f.call()可以加深对 this 的理解,this就是 call() 的第一个参数。

四、函数其他知识点

1. 参数 thisarguments

call() 的第一个参数可以用 this 得到;
call() 的后面的参数可以用 arguments 得到。

  1. this
    普通模式下,如果 thisundefined,浏览器会自动把 this 变成window.
    严格模式下,this 传的参数的值不会改变。
    this
  • 易错题
    易错题
    (1)this 就是 call 的第一个参数。
    (2)每个函数都有自己的 this,第一个 this 对应的 callf1.call(obj),第二个 this 对应的 callf2.call()
    (3)thisarguments 都是参数,参数都要在函数执行(call)的时候才能确定。
  1. arguments
  • arguments 对象包含了函数运行时的所有参数,arguments[0] 是第一个参数,arguments[1] 是第二个参数,以此类推。
  • arguments 对象是伪数组
  • arguments 对象只有在函数体内部才可以使用。
    arguments
2. call stack 调用栈
  • 代码段执行时,每进入一个函数之前,都会把函数的位置记入到 stack 里面,依次进行,return 时再回到 stack 里最上面的位置。例:
function a() { console.log('a1'); b.call(); console.log('a2'); return 'a' }
function b() { console.log('b1'); c.call(); console.log('b2'); return 'b' }
function c() { console.log('c'); return 'c' }
a.call()
console.log('end')

上面代码段调用栈的过程图解如下:
call stack 调用栈
  • 递归
function sum(n){
  if(n === 1) { return 1 }
  else { return n + sum.call(undefined, n-1) }
}
sum.call(undefined, 3) // 6
// sum(3) = 3 + sum(2),sum(2) = 2 + sum(1),sum(1) = 1

n 不可以无限大,超过栈内存就会发生溢出 stack overflow.

3. 作用域
  1. 定义:作用域(scope)指变量存在的范围。
    全局作用域:变量在整个程序中一直存在,所有地方都可以读取;
    函数作用域:变量只在函数内部存在。
    函数外部声明的变量是“全局变量”(global variable),它可以在函数内部读取。
    在函数内部定义的变量,为“局部变量”(local variable),外部无法读取。
  • 对于var命令,局部变量只能在函数内部声明,在其他区块中声明,一律都是全局变量。
  • 对于a = 3 语句,会优先认为它是一个赋值语句,并按作用域从小到大找变量a,找到后给变量a赋值;若整个作用域里都找不到变量a,则认为它是声明并赋值,此时会声明一个全局变量a并赋值为3.
  1. 变量提升
    函数作用域内部也会产生“变量提升”现象。var命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部。
  • 易错题 1:变量提升
var a = 1
function f1(){
    f2.call()
    console.log(a)  // 断点 1
    var a = 2
    function f2(){
        var a = 3
        console.log(a)  // 断点 2
    }
}
f1.call()
console.log(a)

问:运行到断点1时,打印出 a 的值为?
答:由于变量提升,正确答案是 undefined.
技巧:看到题目后,第一件事是先做变量提升。

// 变量提升后
var a = 1
function f1(){
    var a  // f1 的变量提升
    function f2(){
        var a  // f2 的变量提升
        a = 3
        console.log(a)  // 断点 2
    }
    f2.call()
    console.log(a)  // 断点 1
    a = 2
}
f1.call()
console.log(a)
  • 易错题 2:作用域
var a = 1
function f1(){
    console.log(a)
    var a = 2
    f4.call()
}
function f4(){
    console.log(a)  // 断点 3
}
f1.call()
console.log(a)

问:断点 3 处 函数 f4 打印出 a 的结果是?
答:a = 1。函数 f4 的变量只在它自己的作用域或它的父作用域里有效。

  • 易错题 3
var a = 1
function f1(){
    console.log(a)
    var a = 2
    f4.call()
}
function f4(){
    console.log(a)  // 断点 4
}
a = 2
f1.call()
console.log(a)

问:断点 3 处 函数 f4 打印出 a 的结果是?
答:a = 2。因为函数的执行在语句a = 2之后发生。

  • 易错题 4

    问:点击“选项3”,打印出的两个 i 分别是多少?
    易错题 4
    答:打印出的两个 i 都是 6。因为 “用户移动鼠标点击的时间” 远远小于 “for 循环的时间”,所以点击 “选项 2” 时 for 循环已执行完毕,第一个 i=6;第二个 i 打印是在跳出 for 循环之后,所以结果也为 6。
4. 闭包
  • 定义:如果一个函数使用了它作用域以外的变量,那么“这个函数”+“函数内部能访问到的变量”(环境)的总和,就叫做闭包。下面的一段代码就是闭包:
var a = 1
function f(){
  console.log(a)
}
  • 闭包的用途:
    闭包可以用来间接访问一个变量,即隐藏一个变量。
    如果一个变量不方便别人直接访问,这时可以在一个函数作用域中声明这个变量,用子函数操作这个变量并将结果 return 到外部函数,使他人间接访问这个变量。例:
!function f1(){
  var a = 0;
  function f2(){
    return a += 1
  }
  return f2
}()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容