前端学习(五十七) JavaScript-函数进阶(javaScript)

this对象

全局环境中的this指向全局对象,也就是window

this.abc="abc"

console.log(window.abc)   //'abc'

注意:全局环境下的this不推荐使用,使用的话更倾向于使用window

函数中的this对象,取决于函数是如何被调用的,大致分为:简单调用对象方法调用call和apply调用构造函数调用

简单调用

就是直接用()的调用

function f(){

console.log(this)  //window,如果是在严格模式下,还会报undefined

}

f()

对象方法调用

let obj={

f(){

console.log(this)  //obj

}

}

也就是说作为对象方法调用,指向的是对象本身

这边有一个坑,示例如下

let a={

aa() {

    console.log(this); //Obejct

    function aaa(){

        console.log(this); //window

    }

    aaa();

}

}

a.aa()

这边的函数aaa()里的this指向的是window,而不是自以为的Object,这边往往会出错,修正使用call和apply

let a={

aa() {

    console.log(this); //Obejct

    function aaa(){

        console.log(this); //Object

    }

    aaa.call(this);

}

}

a.aa()

构造函数调用

function B(){

    this.a='a'

};

let ba=new B();

console.log(ba.a);   //'a'

  • 函数作为普通函数使用,那么函数中的this指向的是全局对象,如果没有显示的值,返回的是undefined
  • 函数作为构造函数使用,那么函数中的this指向的是实例对象,如果没有显示的值,默认返回的是this对象

函数的双重功能

ES6中的函数内部有两个不同的方法:[[Call]][[Constructor]],当使用普通方式调用函数时[[call]]会被执行,当使用构造函数调用时[[constructor]]方法会被执行

new.target元属性

当以构造函数的形式调用函数时new.target指向的是构造函数本身,因此当我们需要把函数仅作为构造函数时不希望作为普通函数调用时,可以设置,如下示例

            function Person(name) {
                if(new.target === Person){
                    this.name = name
                }
                else{
                    throw new Error("必须使用New关键字")
                }
            }
            let person=new Person("John");
            console.log(person);
            let person1=Person("john"); //报错
            console.log(person1);  

函数参数的传递方式

函数的参数,分按值传递按引用传递

  • 按值传递:参数形参的值是调用函数所传入实参的副本,也就是后面对形参的修改不会影响外面的实参
  • 按引用传递:函数形参的值是调用函数所传入实参的引用,后面对形参的修改会影响实参

函数应用(重点)

详细见单独一章

箭头函数

  • 没有自己的this,super,arguments和new.target,它们是离该箭头函数最近的非箭头函数的绑定
  • 不能使用new来调用
  • 没有原型对象
  • 内部的this无法改变,意味这不能使用call,apply等方法修改this的指向
  • 形参名称不能重复

箭头函数有几种变体,但大致都是有 参数=>函数体 组成的,不需要return关键字,就代表返回

示例代码1:

            var double=value=>value*2;
            //等同于
            var double=function(value){
                return value*2
            }

示例代码2:

            var double=(a,b)=>a*b;
            //等同于
            var double=function(a,b){
                return a*b
            }

示例代码3:

            var double=()=>'john';
            //等同于
            var double=function(){
                return 'john'
            }

示例代码4:

            var double=()=>{};

这是的参数为空,函数体也为空,那么函数体需要用大括号括起来,否则会报错

示例代码5:

            var double=(a,b)=>({a:a,b:b});

这是将参数返回一个对象,对象需要用大括号括起来,否则会报错

箭头函数的语法是宽松绑定

            var double = x=>(x % 2) === 0? x : 0

箭头的优先级比其他所有的都要低,因此注意加括号

            var double = (x=>(x % 2) === 0)? x : 0

因此可以看出函数体如果是一个表达式,则不需要加{},如果是语句则要加{}

示例6

            let value=[2,3,1];
            let result=value.sort(function(a,b) {
                return a-b
            })
            let result=value.sort((a,b)=>(a-b))
            console.log(result);

尾调用优化

在执行某个函数时,如果最后一部是一个函数调用,并且被调用函数的返回值直接被当作函数返回,就被称为尾调用

传统函数调用

            function e(x) {
                return x;
            }
            function f(x) {
                const y=x+1;
                return e(y)
            }
            console.log(f(2));

尾调用的要求

  • 尾调用不需要访问当前栈中的变量,也就是没有闭包
  • 返回到尾调用处时,不用再做其他事情
  • 尾调用的返回值,直接返回给调用它所在函数的调用者

尾递归

前面知道了,如果函数调用本身时是一个尾调用,则称之为尾递归

            function abd(n) {
                if(n===1||n===2){
                    return 1;
                }
                return abd(n-1)+abd(n-2)
            }

改成尾调用

            function abd2(n,a=0,b=1) {
                if(n===0){
                    return 1
                }
                if(n===2){
                    return b;
                }
                return abd2(n-1,b,a+b)
            }

猜你喜欢

转载自blog.csdn.net/zy21131437/article/details/81381054
今日推荐