14. 函数

176 阅读3分钟

14.1 函数也是对象

匿名函数

let a = function fn(x, y){return x+y}  //fn的作用域只能在等号左边生效

fn(1, 2)  //Uncaught ReferenceError: fn is not defined  
a(1, 2) //3

let a = function (x, y){return x+y}  //a接收一个匿名函数, 和上面效果一样

返回对象:

//1. 返回简单变量
let f4 =  x => x+1

//2. 返回对象
let f4 =  x => ({name:x})    //用括号包裹

用构造函数新建函数:

let f= new Function('x', 'y', 'return x+y')  //基本没人用, 能让人知道函数是由谁构造出来

setTimeout遇见函数的逻辑

会先把所有的语句执行完, 然后再执行setTimeout, 就好像先把这把游戏打完,再吃饭

let a=1
function fn(){
    setTimeout(()=>{console.log(a)}, 0)  //1. 喊你吃饭
}
fn()  //输出 2
a=2  //2. 先把游戏打完

智障的 setTimeout:

//1. 把let放外面,打印是另一种结果
let i = 0
for( i=0; i<6; i++){
  setTimeout(()=>{console.log(i)}, 0) // 打印6个6
}


//2. 把let 放里面结果完全不同,  把let换成var又是6个6
for(let i=0; i<6; i++){   
  setTimeout(()=>{console.log(i)}, 0)  //打印 0 1 2 3 4 5
}

14.2 函数作用域

如何定义全局变量:

  • 定义在最外边的let
  • 挂载在window上的变量

什么是闭包:

14.3 参数和返回值

形参会复制变量的什么东西?

复制变量存在stack区的东西. 简单变量再stack区存的是, 对象在stack区存的是地址. 对象将地址传行参


没写return

没写return , 会自动返回 undefined

14.4 调用栈

函数调用为啥需要用到栈?

函数里面调用其他函数, 顺序是后入先出, 所以需要用到栈

会把什么信息压入栈?

进入一个函数前, 将进入函数的具体位置压入栈, 也就是存档


为啥函数调用能写在函数定义前面?

函数永远跑到第一行

//1. 函数定义自动跑到函数调用前面
add(1, 2)                      //输出3
function add(x, y){
    return x+y
}


//2. 函数自动跑到第一行, 会造成let定义失败
let add = 1
function add(){}  //Uncaught SyntaxError: Identifier 'add' has already been declared

14.5 js第二座大山 this

每个函数都有 arguments 和this, 但箭头函数没有

arguments: 包含所有参数的伪数组

所有人不知道this, 是什么. 不给任何条件, this默认指向window

传值给this:

fn.call(xxx, 1,2,3) xxx就是传值this的参数, 后面的给arguments, 会自动转换成对象.例如1会自动转成Number(1)

解决不要自动转成对象:

function fn(){
    'use strict' //求求你了js, 不要给我乱加东西
    console.log(this) 
}

否则: 自动转成对象, 你传undefined, js给你弄成window

this是隐藏参数, arguments是显性参数

如果没有this,会发生什么?


假如没有this:用实例名字来代替:

let person = {
    name: 'frank',
    sayHi(){
        console.log('你好, 我叫'+ person.name)  //我就用实例的名字: person
    }
}

缺点:

  • 如果person改名, 这个函数就挂了
  • 如果实例没有创建, 只有类, 就没法这样做

如何解决?

  1. 传递实例: 在实例调用函数的时候, 将实例作为参数传递进去. python就用了这个方法

    let person = {
        name: 'frank',
        sayHi(p){
            console.log('你好, 我叫'+ p.name)  //我就用实例的名字: person
        }
    }
    person.sayHi(person) //作为参数传递进去
    

    python的做法:

  1. js走了一个更难理解的路: 用一个this表示将来会创建的, 未知实例.

    具体顺序:

    • 将this给人类, 人类用this定义类中的函数
    • 当class实例化的时候, 把实例传递给this

14.6 要经常用call调用this

大师写法:

大师传值, 第一个参数位是this

写forEach的源代码:

Array.prototype.forEach2 = function(fn){
    for(let i = 0;i<this.length;i++){
        fn(this[i], i)
    }
}

this的值是不确定的


this的显示和隐式传递

强行绑定this

14.7 箭头函数

箭头函数没有this!!!

如果在箭头函数中使用this, 会自动调用函数外面的this

因为对箭头函数加call, 不会改变this

14.8 立即执行函数

var想要局部变量 -> 需要一个全局函数, 在里面定义局部变量 -> 那我就定义匿名函数, 定义局部变量 -> 但是js认为我你们函数不对, -> 那我研究一些技巧骗js-> 在新版语法中很简单