关于函数

看到代码就开始答题,必错!!!声明提前!!!变量提升!!!

一、函数的 5 种声明(重点匿名,具名,箭头)

  • 1、具名函数
function f(x,y){
     return x+y
 }
 f.name // 'f'
var f5 = function f4(){ //f4的作用域是这个函数本身
 
}
console.log(f);//可访问
  • 2、匿名函数
var f
 f = function(x,y){ //f引用函数 f记录的是函数的地址,不是函数本身
     return x+y
 }
var f2 = f;//复制的函数地址,同时指向函数
 f.name // 'f' ,他是匿名函数,但是他有name
 f2.name // 'f'
  • 3、具名函数赋值
var f
 f = function f2(x,y){ return x+y }
 f.name // 'f2'
 console.log(f2) // undefined
  • 4、window.Function
 var f = new Function('x','y','return x+y')
 f.name // "anonymous"
  • 5、箭头函数
    var fn6 = i=>i+1 //一个参数
    var fn7 = (i,j)=>i+j //两个参数
    var fn8 = (i,j)=>{console.log(1);return i+j;}//执行多条内容,用{括起来}
 var f = (x,y) => {
     return x+y
 }
 var sum = (x,y) => x+y
 var n2 = n => n*n

这几种方法大体相同,只是this不同

二、如何调用函数

f.call(asThis, input1,input2)
其中 asThis 会被当做 this,[input1,input2] 会被当做 arguments
禁止使用 f(input1, input2)

三、作用域

  • 按照语法树,就近原则
  • 我们只能确定变量是哪个变量,但是不能确定变量的值
    拿到代码直接做——必然会错。请先提升声明!!!(只提声明,不带值)
    词法作用域(静态作用域)练习:
var global1 = 1
 function fn1(param1){
     var local1 = 'local1'
     var local2 = 'local2')
     function fn2(param2){
         var local2 = 'inner local2'
         console.log(local1)
         console.log(local2)
     }

     function fn3(){
         var local2 = 'fn3 local2'
         fn2(local2)
     }
 }
词法树.png

词法树只用来分析语义,和值没有关系
面试题1

var aa = 1;
function f(){
  console.log(aa)
}
aa = 2;
f.call()
var a = 1
function f1(){
    alert(a) // 是多少
    var a = 2
}
f1.call()

答案:

var a = 1
function f1(){
     var a //声明提前
    alert(a) // undefined
     a = 2
}
f1.call()

面试题2

var a = 1
function f1(){
    var a = 2
    f2.call()
}
function f2(){
    console.log(a) // 是多少
}
f1.call()

答案:

var a = 1
function f1(){
    var a = 2 //a=2只在当前作用域(f1)内有效
    f2.call() 
}
function f2(){
    console.log(a) //1,拿的是全局a = 1
}
f1.call()

面试题3

var liTags = document.querySelectorAll('li')
for(var i = 0; i<liTags.length; i++){
    liTags[i].onclick = function(){
        console.log(i) // 点击第3个 li 时,打印 2 还是打印 6?
    }
}

深入阅读:

四、什么是 call stack

stack堆:先进后出
队列:先进先出
浏览器不是先运行代码,而是先把申明提到前面


图片.png

五、this 和 arguments

function f(){
      console.log(this)
      console.log(arguments)
  }
  f.call() // window
  f.call({name:'frank'}) // {name: 'frank'}, []
  f.call({name:'frank'},1) // {name: 'frank'}, [1]
  f.call({name:'frank'},1,2) // {name: 'frank'}, [1,2]

不传this,默认window
不传arguments,默认是空数组[]
为什么用call,不用f()直接调,用f()是阉割版的f.call(),就不容易分辨出this代表是什么

function f(){
    'use strict'
    console.log(this)
    console.log(arguments)
    return undefined
}
f.call();//需传入this和arguments([]),如果没有传,window不给this,就默认是undefined,也就是window(小写window,google浏览器打印出来是Window,所以运行结果是window,[]
f.call(1,2,3) // this 为 1,arguments 为 [2,3]
  • this为什么必须是对象

因为 this 就是函数与对象之间的羁绊

var person = {
          name: 'frank',
          sayHi: function(person){
              console.log('Hi, I am' + person.name)
          },
          sayBye: function(person){
              console.log('Bye, I am' + person.name)
          },
          say: function(person, word){
              console.log(word + ', I am' + person.name)
          }
      }
      person.sayHi(person)
      person.sayBye(person)
      person.say(person, 'How are you')

      // 能不能变成 
      person.sayHi()
      person.sayBye()
      person.say('How are you')

      // 那么源代码就要改了
      var person = {
          name: 'frank',
          sayHi: function(){
              console.log('Hi, I am' + this.name)
          },
          sayBye: function(){
              console.log('Bye, I am' + this.name)
          },
          say: function(word){
              console.log(word + ', I am' + this.name)
          }
      }
      // 如果你不想吃语法糖
      person.sayHi.call(person)
      person.sayBye.call(person)
      person.say.call(person, 'How are you')

      // 还是回到那句话:this 是 call 的第一个参数
      // this 是参数,所以,只有在调用的时候才能确定
      person.sayHi.call({name:'haha'})  // 这时 sayHi 里面的 this 就不是 person 了
      // this 真的很不靠谱

      // 新手疑惑的两种写法
      var fn = person.sayHi
      person.sayHi() // this === person
      fn()  // this === window
sum(x,y){
  return x+y
}
sum.call(undefined,1,2);//undefined必须写

六、call / apply

n.call(asThis, p1,p2) 是函数的正常调用方式
当你不确定参数的个数时,就使用 apply
fn.apply(asThis, params)

function sum(){
  var n = 0;
  for(var i = 0;i<arguments.length;i++){
    n+= arguments[i]
  }
  return n
}
sum(1,2,3,4,5,6);//21
//若调用为一个数组
var a = [1,2,3,4,5,6]
sum.call(undefined,a[0],a[1],a[2]...)
更新用apply:
sum.apply(undefined,a);//21

七、bind

call 和 apply 是直接调用函数,而 bind 则是返回一个新函数(并没有调用原来的函数),这个新函数会 call 原来的函数,call 的参数由你指定。

八、return

每个函数都有 return

如果你不写 return,就相当于写了 return undefined

九、柯里化 / 高阶函数

返回函数的函数

* 柯里化:将 f(x,y) 变成 f(x=1)(y) 或 f(y=1)x
 //柯里化之前
  function sum(x,y){
      return x+y
  }
  //柯里化之后
  function addOne(y){
      return sum(1, y)
  }
  //柯里化之前
  function Handlebar(template, data){
      return template.replace('{{name}}', data.name)
  }
  //柯里化之后
  function Handlebar(template){
      return function(data){
          return template.replace('{{name}}', data.name)
      }
  }

柯里化可以将真实计算拖延到最后再做
关于柯里化的高级文章:

  1. http://www.yinwang.org/blog-cn/2013/04/02/currying
  2. https://zhuanlan.zhihu.com/p/31271179
* 高阶函数:

在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:
a、 接受一个或多个函数作为输入:forEach、sort、 map、 filter、reduce
b、输出一个新函数:bind、lodash.curry
fn.bind.call(fn,{},1,2,3)//
c、不过它也可以同时满足两个条件:Function.prototype.bind

高阶函数用call的方式理解.png

[高阶函数的应用区别]https://blog.csdn.net/kingan123/article/details/79818566

偶数相加求和
array = [1,2,3,4,5,6,7,8]
var sum = 0;
for(var i= 0;i<array.length;i++){
  if(array[i] % 2 ===0){
    sum+=array[i]
  }
}
console.log(sum)
法一:array.filter(function(n){n%2===0});//[2,4,6,8]
        .reduce(function(prev,next){return prev+next})
法二:reduce(filter(array,function(n){n%2===0}),function(prev,next){return prev+next},0)
取奇数从小到大排序
array1 = [3,2,1,4,5,6,7,8]
sort(filter(array1,function(n){n%2===1}),function(a,b){return a-b})

接收一个函数,叫高阶函数
返回一个函数,叫高阶函数
函数被当作参数,叫回调
函数返回的函数参数比原函数少一个参数叫柯里化

十、回调

名词形式:被当做参数的函数就是回调
动词形式:调用这个回调
注意回调跟异步没有任何关系

十一、构造函数

返回对象的函数就是构造函数
一般首字母大写

new Number(1)//Number { 1 }
new String(1)
function Empty(){
    this.name = '空'
    return this //可不写 
}
var empty = new Empty;//写new,自动返回 Empty.call({})

十二、箭头函数

箭头函数没有this,

setTimeout(function(){
  console.log(this);//{name:'jack'}
}.bind({name:'jack'}),1000)
setTimeout(function(){
  console.log(this);//window
},1000)
setTimeout(function(){
  console.log(this);//{name:'jack'}
  setTimeout(function(){
    console.log(this);//window
  },1000)
}.bind({name:'jack'}),1000)

setTimeout(function(){
  console.log(this);//{name:'jack'}
  setTimeout(function(){
    console.log(this);//{name:'jack'}
  }.bind(this),1000)
}.bind({name:'jack'}),1000)
//箭头函数
setTimeout(function(){
  console.log(this);//{name:'jack'}
  setTimeout((a)=>console.log(this),1000);//{name:'jack'}
}.bind({name:'jack'}),1000)

十三、闭包

如果一个函数,使用了他范围外的值,那么(这个函数+这个变量)就叫做闭包

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

https://zhuanlan.zhihu.com/p/22486908

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • 函数和对象 1、函数 1.1 函数概述 函数对于任何一门语言来说都是核心的概念。通过函数可以封装任意多条语句,而且...
    道无虚阅读 4,527评论 0 5
  • 1.当调用函数时,除了传入在定义中显式声明的参数之外,同时还传入两个隐式参数,arguments 和 this。 ...
    悸动无语阅读 408评论 0 0
  • 原文链接 Haskell和scala都支持函数的柯里化,JavaScript函数的柯里化还与JavaScript的...
    dreamapple阅读 2,515评论 0 24
  • 前言:本文将详细的介绍JS中函数的相关概念(包括函数的call stack 、this 、作用域、闭包、柯里化、高...
    EnochQin阅读 640评论 2 2
  • 我一直在等 等我忘了你 等我找回自己 等我放过自己 等你奔向光 奔向未来 等我再也无法出现在你的明天里
    七情九歌阅读 358评论 0 0