JavaScript(三)---【this指针,函数定义、Call、Apply、函数绑定、闭包】

零.前言

JavaScript(一)---【js的两种导入方式、全局作用域、函数作用域、块作用域】-CSDN博客

JavaScript(二)---【js数组、js对象、this指针】-CSDN博客

0.1全局对象

在JS中有一个全局对象:“window object”,代指的是整个HTML

一定要慎用全局对象,因为太容易导致程序崩溃了。

一.this指针

this指针所代指的目标,取决于它所在的位置,一般来说它有如下几种情况:

  • 对象方法中,this指的是“对象
  • 单独的情况下,this指的是全局对象
  • 函数中,this指的是全局对象
  • 事件中,this指的是接受事件的元素

下面我们将挨个对上述情况进行实验:

1.1对象方法中的this指针

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        var thisPoint = {
            firstName : "ju",
            lastName : "jingyi",
            myThis : function(){
                return this.firstName + this.lastName;
            }
        };
        console.log(thisPoint.myThis());
    </script>
</body>
</html>

效果:

1.2单独情况下的this指针

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        var x = this;
        console.log(x);
    </script>
</body>
</html>

效果:

1.3函数中的this指针

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        function myThis(){
            return this;
        }
        console.log(myThis())
    </script>
</body>
</html>

效果:

1.4事件中的this指针

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>按钮前的位置</h1>
    <button onclick="this.style.display='none'">点击来删除我!</button>
    <h1>按钮后的位置</h1>
</body>
</html>

效果:

点击前

点击后

二.函数定义

2.1正常的函数定义

非常简单,格式如下:

function myFunction(a, b) {
     return a * b;
}

function”代表是一个函数关键字,“myFunction”是函数名字,“(a,b)”是函数形参

2.2使用函数表达式定义

函数表达式就是“函数定义”的样式

例如:“function (a, b) {return a * b}”就是一个函数表达式函数表达式没有名字。

对于没有名字的函数,我们也叫作“匿名函数”。

匿名函数(函数表达式)的应用多用于存放在变量中,用变量调用函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        x = function (a,b) {return a + b};
        console.log(x(1,2))
    </script>
</body>
</html>

效果:

根据这个特性,我们还可以结合“不加()调用函数,返回函数的定义”,来实现更高效的开发

    <script>
        var x = sample;
        function sample(a,b){
            return a + b;
        };
        console.log(x(1,2));
    </script>

2.3自调用函数

函数表达式可以作为“自调用

自调用函数无需人为的调用,它会在被定义完成后自动执行

同时自调用函数,人为调用是禁止的

使用方法:“在函数的最后添加括号()

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        x = function () {return 1 + 2}();   //自调用函数,x被赋予自调用函数返回值3
        console.log(x)
    </script>
</body>
</html>

自调用函数不是匿名函数时,需要给自调用函数外围添加一个"括号包围起来,再加一个括号"。

    <script>
        var x;
        (function sample(){
            x = 100;
        })();
        console.log(x);
    </script>

效果:

2.4箭头函数

箭头函数用来简写函数表达式偷懒用的

使用箭头函数,我需要书写:“function关键字”、“return关键字”、“花括号”(个人推荐写上,容易歧义)

使用方法:

形参列表 => {函数内容}

一定注意,要写上:“=>”,否则函数无效

    <script>
        x = (a,b) => a * b;
        console.log(x(2,5));
    </script>

效果:

当然推荐写上“花括号

    <script>
        x = (a,b) => {a * b};
        console.log(x(2,5));
    </script>

注意:

如果在对象中使用“箭头函数”做方法是禁止的,因为“箭头函数”没有this指针!!

三.函数参数

3.1arguments对象

在JS函数中有一个arguments内置对象,包含了函数调用时的所有形参,并以数组的形式呈现。

这样可以很方便的使我们遍历形参,从而达成某种目的。

例如:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        function Print(x,y,z){
            console.log("函数的形参列表为:",arguments);
            var max = -Infinity;
            for(let i = 0;i < arguments.length;i++){
                if (arguments[i] > max){
                    max = arguments[i];
                }
            }
            console.log("形参中的最大值为:",max);
        }
        Print(100,250,500);
    </script>
</body>
</html>

效果:

3.2参数传递引起的原始值改变

1.形参是一个值

如果传递给函数形参是一个:“”,那么在函数中修改形参不会改变原始值的大小。

(在js中是“值传递”、和Python一样)

    <script>
        var x = 250;
        function myVariable(x){
            x = 100;
        }
        myVariable(x);
        console.log(x);
    </script>

效果:

通过“值传递”,传递给函数形参x的是一个数值,改变这个形参不会对原始的x同步修改。

2.形参是一个对象

若传递给函数形参的是一个“对象”,那么在函数内部对这个“对象”进行修改,也会对原始对象同步修改。

    <script>
        var x = {name:"ju"};
        function myVariable(x){
            x.name = "jingyi"
        }
        myVariable(x);
        console.log(x);
    </script>

效果:

可以看到原始的x也被同步修改了。

四.函数Call

4.1简介

call()方法主要用来实现“方法重用”,即在不同对象上使用的方法。

call()方法是预定义的JS方法,它可以用来调用所有者对象的属性(方法)的方法。

通俗来讲,使用call()方法,可以将“另一个对象的属性(方法)合并到本对象中

4.2使用方法

在调用本对象方法时,附加:“.call”后缀即可。

    <script>
        var pig = {
            name : "八戒",
            weight : 250,
        }
        var animal = {
            fullName : function () {
                return this.name + "体重是:" + this.weight;
            }
        }
        console.log(animal.fullName.call(pig));
    </script>

效果;

五.函数Apply

5.1简介

apply()方法主要也是实现“方法重用”,本质上跟“call()”方法并无区别。

区别在于:

  • call():call方法是一个一个接受参数
  • apply():apply方法可以接受一个数组形式参数,形参分别对应数组种对应位置的元素

5.2使用方法

在本对象调用方法时,附加后缀:“.apply”即可。

    <script>
        var pig = {
            name : "八戒",
            weight : 250,
        }
        var animal = {
            fullName : function (others) {
                return this.name + "体重是:" + this.weight + "年龄是:" + others[0] + "性别是:" + others[1];
            }
        }
        console.log(animal.fullName.call(pig,["15","女"]));
    </script>

效果:

可以看到others形参对应的是数组中下标索引为0的值,也就是说只接受了数组中的一个参数

但如果我们改成call()

    <script>
        var pig = {
            name : "八戒",
            weight : 250,
        }
        var animal = {
            fullName : function (others) {
                console.log(others);
                return this.name + "体重是:" + this.weight + "年龄是:" + others[0] + "性别是:" + others[1];
            }
        }
        console.log(animal.fullName.call(pig,["15","女"]));
    </script>

效果:

可以看到数组作为一个完整的参数被传递给了“others

六.函数绑定

6.1简介

函数绑定“bind()”用来将某个函数绑定到某个对象上,此时这个函数就成为这个对象的一个“方法”。

而如果函数中有this指针的使用,在绑定到某个的对象上之后,this指针所指就由原来的"window object"变为“对象自身”。

6.2bind的使用

bind()方法将某个函数绑定给某个对象,并且返回绑定后的新函数,并不对原对象进行修改。

此时这个函数就是“某个对象”的一个方法,在这个函数中使用this指针,代指的都是“某个对象”。

    <script>
        var person = {
            name : "ju",
            lastname : "jingyi"
        }
        function addition(){
            return 123;
        }
        var newperson = addition.bind(person);
        console.log(person);
        console.log(newperson);
    </script>

效果:

可以看到并没有对原先的person对象添加addition函数,但是此时的addition函数可以认为是person的一个对象,this指针所代指的就是person对象。

我们也可以在addition中打印this指针看看是不是person对象

    <script>
        var person = {
            name : "ju",
            lastname : "jingyi"
        }
        function addition(){
            console.log(this);
        }
        var newperson = addition.bind(person);
        addition();
        newperson();
    </script>

效果:

可以看到新的函数“newsperson”的this指针是person对象,而addition函数的this指针仍然是window对象。

七.闭包

7.1简介

闭包主要是让函数可以具备局部变量,并且这个变量不会随着函数的释放而释放

如果学过Python或者C++等语言,可以通俗点解释,就是实现一个函数内的“静态变量”。

7.2闭包的使用

JS中使用闭包,一般使用“嵌套函数”的形式来实现。

如果我们不使用“闭包”,我们有一个函数的作用是计时器,当调用一次这个函数,计时器的值就会加一

    <script>
        var counter = 0;
        function addCounter(){
            counter += 1;
        }
        addCounter();
        addCounter();
        addCounter();
        addCounter();
        console.log(counter);
        counter += 1;
        console.log(counter);
    </script>

效果:

可以看到,不使用闭包,我们在函数外的任何地方也可以直接对计时器进行操作,因为“计时器是一个全局变量counter”,而功能的需求是每次调用add函数才加一,在外部无法操作

有些读者可能想到,那我每次返回counter的值不就可以了?

    <script>
        var counter = 0;
        function addCounter(){
            return counter += 1;
        }
        counter = addCounter();
        counter = addCounter();
        counter = addCounter();
        console.log(counter);
    </script>

这是一种可行的方法,不过若是多个线程同时对counter进行操作,很容易出现问题,且代码不容易维护,因为在函数外部仍然可以直接对counter进行修改

那我把counter放到函数内部不可以吗?

    <script>
        function addCounter(){
            var counter = 0;
            return counter += 1;
        }
        counter = addCounter();
        counter = addCounter();
        counter = addCounter();
        console.log(counter);
    </script>

效果:

此时的counter作为函数内部的局部变量,当执行完一次add函数后就被释放了,所以结果自然是1

但如果聪明的读者就会想到,我可以在函数内部再嵌套一层函数不就可以了吗?

    <script>
        var add = (function (){
            var counter = 0;
            return function (){
                return counter += 1;
            }
        })();
        console.log(add());
        console.log(add());
        console.log(add());
    </script>

效果:

同时我们无法在外部访问counter变量。

  • 16
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是洋洋a

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值