关于函数

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

一、函数的 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)
     }
 }
关于函数_第1张图片
词法树.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

深入阅读:

  • javascript的词法作用域
  • 静态作用域与动态作用域
  • Abstract Syntax Tree 抽象语法树简介

四、什么是 call stack

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


关于函数_第2张图片
图片.png
  • 普通调用
  • 嵌套调用
  • 递归调用

五、this 和 arguments

  • 重要:this 就是 call 第第一个参数!call 的其他参数统称为 arguments
  • this是隐藏的第一个参数,且必须是对象
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

七、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

关于函数_第3张图片
高阶函数用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

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

十、回调

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

十一、构造函数

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

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

你可能感兴趣的:(关于函数)