小志的前端之路

JS 里的函数

2018-03-20  本文已影响0人  小志1

讲函数前,先了解Function和function的区别。

声明函数有两种方法1.关键字声明 2.new Function声明
1.具名函数 function f(){ return undefined} 2.匿名函数 var f f = function(){} 这两个属于第一种
3.new Function('x','y','return x+y ') 这个属于第二种(除非无聊或者想用字符串拼凑的时候才有这种)

函数的五种声明方式

  1. function f(x,y){ return x+y }
  2. var f = function (x,y){ return x+y }
  3. var f = function x(x,y){ return x+y }
  4. var f = new Function('x','y','return x+y') // window.Function
  5. var f= (x,y) => { return x+y }//es6的箭头函数
    var f = (x,y) => x+y //return和花括号一起省略
    var f = n => n*n //参数只有一个时,参数的括号可以省略

name知识点

每个函数都有名字,但是比较鸡肋,基本用不到

function f(){}  
f.name     //     f
var f2 = function(){}
f2.name    //    f2
var f3 = function f4(){}
f3.name    //    f4
f4.name    //    f4 is not defined
f5 = new Function('x','y','return x+y ')
f5.name    //    anonymous

函数是可以反复调用的代码块 调用函数英文是call

call

var f = {}
f.params = ['x','y']
f.functionBody = 'console.log("fff")'
f.call = function (){
    return window.eval(f.functionBody)
}
f.call()  //    fff
call
call其实就是函数的复杂写法 f(1,2) === f.call(undefined,1,2),实际参数从第二个开始传,undefined是this , 1,2是arguments
call的第一个参数可以用this得到,call后面的参数可以用arguments得到
f和的区别 f是函数体 f.call()指向这个对象的函数体
call

其中可以执行代码的对象就叫函数(我们写的代码)

函数原型Function.prototype有三个重要的方法call apply bind,会重写toString方法覆盖Object的toString方法

this

在普通模式下,如果this是undefined,浏览器会自动把this变成window

  f = function (){
     console.log(this == = window)
  }
  f.call(undefined)  // true

如果是严格模式,给undefined打印出的就是undefined,

  f = function (){
     'use strict'
     console.log(this === window)
  }
  f.call(undefined)  //false

arguments

argument是伪数组,因为它的原型链上没有Array.prototype,或者 proto没有指向Array.prototype
下面判断

f = function(){
    arguments.push(4)
    console.log(arguments)
}
f.call(undefined,1,2,3)   

会报arguments.push is not a function的错,所以是伪数组
很好判断是不是伪数组,给push方法

call stack 调用栈

Stack Overflow 和中国的segment fault 这两个网站的由来就是从栈溢出而来的

function sum(n){
    if(n==1){
        return 1
    }else{
        return n + sum.call(undefined, n-1)
    }
}
sum.call(undefined,9650)  //46566075

再大就栈溢出Maximum call stack size exceeded,所有栈的调用最多在9650左右,再多就栈溢出了

call stack

作用域

在使用变量的时候 ,怎么去找它的声明 ,就找这个作用域里面的声明,找不到找外面作用域的声明,如果还找不到 。再往外面找,就近原则
声明提升:变量提升,函数的声明也提升,先提升在看代码

f1里的console.log是什么

var a = 1
function f1(){
    f2.call()
    console.log(a)    //undefined
    var a = 2
    function f2(){
        var a = 3
        console.log(a)
    }
}
f1.call()
console.log(a)   
//3 
//undefined 
//1

变量提升改写代码

var a = 1
function f1(){
    var a
    function f2(){
        var a
        a = 3
        console.log(a) // a定义再赋值在console.log前面,所以是3    }
    f2.call()
    console.log(a)  // a先定义,赋值在console.log下面,所以是undefined
    a = 2
}
f1.call()
console.log(a)

例2
f4打印的是什么

var a = 1
function f1(){
    console.log(a)
    var a = 2
    f4.call()
    
}
function f4(){
    console.log(a)     //1, f4的a 一定是f4的作用域或者它的父作用域  
}
f1.call()
console.log(a)

f1的a只在f1函数里有效,而f4的a 一定是f4的作用域或者它的父作用域 ,不用和上面的变量提升搞混

例3
????里的内容有没有可能是的a输出的不是1

var a = 1
function f4(){
    console.log(a)
}
???????   //a =  2   不是立刻执行就可能是2
f4.call()

作用域说的是a是那个a,但并没有说a是哪个a的值,如果????里设置了延时代码,那么a就不一定是1了

闭包

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

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

上一篇下一篇

猜你喜欢

热点阅读