wangjie-fourth 的个人博客

记录精彩的程序人生

目录
JS函数
/    

JS函数

JS中函数也是一种对象。

定义函数

1、具名函数

function 函数名(形式参数1, 形式参数2){
    方法体;  
    return 返回值;  
}

这种函数是由Function构造出来的。

2、匿名函数

let a = function(x,y){ return x+y}

也叫函数表达式

3、箭头函数

let f1 = x => x*x
let f2 = (x,y) => x+y
let f3 = (x,y) => {return x+y}

4、用构造函数定义函数

let f = new Function('x','y', 'return x+y')

这种方式基本没人使用,但可以让你知道函数是谁构造的。从而:所有函数都是Function构造出来的,包括Object、Array、Function

注意
(1)具名函数的作用域
普通具名函数的函数名作用域是全局,但如果使用变量接收的话,它的作用域仅限于方法定义。比如:

let a = function fn(x,y){ return x+y }
fn(1,2)//报错:fn没有定义。这是因为上面这种定义,fn只作用于等号右边

(2)如何让箭头函数返回一个对象

let f1 = x => { name:x };//这里返回的是undefined,js会将name:x作为label;js会将花括号优先看作作用域
  
let f1 = x => ( {name:x} );//用圆括号括起来即可

函数要素

每个函数都有以下:

  • 调用时机
  • 作用域
  • 闭包
  • 形式参数
  • 返回值
  • 函数提升
  • arguments(除了箭头函数)
  • this(除了箭头函数)

调用时机

JS中,只有加上()才表示调用函数。

let fn = () => console.log('hi');
fn//不会有任何操作
fn()//执行函数
let fn2 = fn;
fn2();

相当于fnfn2只是保留了箭头函数地址的变量而已。只有加上()时,才是执行这个函数

作用域

花括号抱起来的部分就是作用域。
(1)全局变量、局部变量
在顶级作用域声明的变量是全局变量;window的属性是全局变量;
其他都是局部变量;

(2)就近原则

function f1(){
    let a = 1  
    function f2(){
        let a = 1  
        console.log(a)  
    }  
    console.log(a)  
    a = 3  
    f2();  
}

闭包

如果一个函数用到了外部的变量,那么这个函数加这个变量就叫做闭包

形式参数

JSJava一样,都是按值传递。除了平常定义形式参数外,还可以使用:

function add(x, y){
    return x + y;  
}
等价于
function add(){
    var x = arguments[0];  
    var y = arguments[1];  
    return x+y;  
}

返回值

每一个函数都有返回值。没有return语句,就会返回undefined

函数提升

使用具名函数定义的方式,即function fn(){},无论他在哪一行,最后都会在第一行。

argumentsthis

argumentsthis是每个函数都有的,除了箭头函数。
1、arguments
arguments是用来存储函数参数信息的伪数组
每次调用函数时,都会对应产生一个 arguments

2、this

  • this默认指向window对象;
  • 如果通过call指定this对象,如果传入非对象,会自动转为对象;
  • 在方法体加入use strict,可以避免上述转换
fn(){
    console.log(this)  
}
fn();// window对象

可以通过函数.call()来指定this指向谁

fn.call(1);// this 等价于Number{1}

可以通过use strict来避免转换

fn(){
    'use struct'  
    console.log(this)  
}
fn.call(1); // this 等价于 1

3、没有this时,如何表示当前对象

let person = {
    name: 'frank',
    sayHi(){
        console.log('你好,我叫' + person.name)
    } 
}

我们先用对象地址的变量来代替this

带来的问题?

class Person{
    constructor(name){
        this.name = name;//这里的 this 是new强制指定的  
    }  
    sayHi(){
        console.log(???)  
    }  
}

这里仅声明了类,还没有创建对象,如何解决在这里引用未来对象的name属性呢?

  • 告诉他未来的对象地址
class Person{
    constructor(name){
        this.name = name;  
    }  
  
    sayHi(p){
        console.log('你好,我叫' + p.name)  
    }  
}
let person = new Person('frank');
person.sayHi(person);

这里JS可以帮你优化一下,跟java一样。每个函数默认都会把当前对象地址作为隐藏参数传进去,并规定通过this来获取这个对象地址。

问题?也就清楚了全局函数的this为什么是window对象。
这个call方法就需要你手动传入对象的,并且指定this的指。
全局函数如果传undefined代表thiswindow

image.png
thisArray.forEach上面的使用
image.png

多个的话,函数前面的对象作为this
image.png

绑定this
image.png

绑定this就不会再改变了。这在VueReact后面会使用到。


箭头函数:没有argumentsthis。外面函数的this是什么,箭头函数的this就是什么。
image.png

立即执行函数:用的少
1、解决的问题
解决想执行一些初始化操作,但不要留下痕迹。这时候就要使用局部变量,但在早期jsvar命名,会让这个变量挂在window的属性上,所以只能创建一个函数,这个函数的变量就全部是局部变量。但是这个函数也会成为window的属性。这里通过创建匿名函数,并且立马执行匿名函数,就可以达到这个效果。

2、格式

! function (){
    函数体  
} ();//声明匿名函数后,立马执行

!符号是试出来的,不写的话会报错。

3、现在的解决方案

{
    函数体;  
}

不要使用括号来作为匿名函数
image.png

其实加分号就好

评论