关于函数

2019-03-08  本文已影响0人  H_uan

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

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

function f(x,y){
     return x+y
 }
 f.name // 'f'
var f5 = function f4(){ //f4的作用域是这个函数本身
 
}
console.log(f);//可访问
var f
 f = function(x,y){ //f引用函数 f记录的是函数的地址,不是函数本身
     return x+y
 }
var f2 = f;//复制的函数地址,同时指向函数
 f.name // 'f' ,他是匿名函数,但是他有name
 f2.name // 'f'
var f
 f = function f2(x,y){ return x+y }
 f.name // 'f2'
 console.log(f2) // undefined
 var f = new Function('x','y','return x+y')
 f.name // "anonymous"
 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 就是函数与对象之间的羁绊

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

上一篇 下一篇

猜你喜欢

热点阅读