IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> JavaScript函数进阶 -> 正文阅读

[JavaScript知识库]JavaScript函数进阶

1. 函数的定义和调用

1.1 函数的定义方式

  • 函数声明方式function 关键字(命名函数)
 function fn() { };
  • 函数表达式(匿名函数)
 var  fun = function() { };
  • 利用 new Function ,了解即可,因为效率低,也不方便书写,较少使用
var  fn = new Function'参数1''参数2'..., '函数体');
// Function里面参数都必须是字符串格式
//所有的函数都是Function的实例(对象)
//函数也属于对象

在这里插入图片描述

1.2 函数的调用方式

  • 普通函数
function fn () {
console.log('hello');}
fn();
fn.call();
  • 对象的方法
var hi = {
	sayHi: function(){
	console.log('hello');
    }
}
hi.sayHi();
  • 构造函数
function Star() { };
new Star();
  • 绑定事件函数
btn.onclick = function() { }; //点击了按钮就可以调用这个函数
  • 定时器函数
setInterval(function() { }, 1000); //这个函数是定时器自动1秒调用一次
  • 立即执行函数
(function() {})(); //自动调用

2. this

2.1 函数内this的指向

这些this的指向,是当我们调用函数的时候确定的。
调用方式的不同决定了this的指向不同

一般指向我们的调用者:

调用方式this指向
普通函数调用window
对象方法调用该方法所属对象
构造函数调用实例对象 原型对象里面的方法也指向实例对象
事件绑定方法绑定事件对象
定时器函数window
立即执行函数window

2.2 改变函数内this的指向

JS为我们专门提供了一些函数方法更优雅的处理函数内部this的指向问题,常用的又 call()、 apply()、 bind() 三种方法

  • call()方法
    调用一个对象,简单理解为调用函数的方式,但是它可以改变函数的this指向
    主要应用场景:call经常做继承。
 fn.call(thisArg, arg1,arg2,...)
  • apply()方法
    调用一个对象,简单理解为调用函数的方式,但是它可以改变函数的this指向
    主要应用场景:例如借助于数学内置对象求最大值( 经常跟数组有关系)
 fn.apply(thisArg, [argsArray])
 //thisArg: 在fn函数运行时指定的this值
 //argsArray: 传递的值,必须包含在数组里面
 // 返回值就是函数的返回值,因为它就是调用函数

var arr = [1,77,3,5,2];
Math.max.apply(Math,arr);
//apply的主要应用:例如借助于数学内置对象求最大值
  • bind()方法—重点记住
    不会调用原来的函数,但可以改变函数的this指向
    典型应用: 如果有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向,此时用blind()方法,比如改变定时器内部this指向,这个方法用的较多
 fn.bind(thisArg, arg1,arg2,...)
 //thisArg: 在fn函数运行时指定的this值
 //argsArray: 传递的其他参数
 // 返回由指定的this值和初始化参数改造的原函数拷贝(返回的是原函数改变this之后产生的新函数)
 
 //有一个按钮,想要点击后,就禁用这个按钮,3秒钟之后开启这个按钮
var btn = document.querySelector('button');
btn.onclick = function(){
    this.disabled = true; //这个this指向btn
    setTimeout(function(){
    }.bind(this),3000) //bind应该放在定时器函数外面,这里的this就是上面的this,指向btn
}

3. 严格模式

JS除了提供正常模式外,还提供了严格模式(strict mode),即在严格条件下运行JS代码。
严格模式对正常的JS语义做了一些更改:

  • 消除了JS语法的一些不合理、不严谨之外,减少了一些怪异行为
  • 消除代码运行的一些不安全之处,保证代码运行的安全
  • 提高编译器效率,增加运行速度
  • 禁用了在ECMAScript的未来版本中可能会定义的一些语法,为未来新版本的JavaScript做好铺垫。比如一些保留字: class、enum、 export、 extends、 import、 super不能做变量名

3.1 开启严格模式

严格模式可以应用到整个脚本或者个别函数中。因此在使用时,我们可以讲严格模式分为脚本开启严格模式为函数开启严格模式两种情况。

  • 为脚本(script标签)开启严格模式

有的script脚本文件是严格模式,有的是正常模式,这样不利于文件合并,所以可以将整个脚本文件放在一个立即执行的匿名函数之中,这样独立创建一个作用域而不影响其他script脚本文件。

'use strict';
//单引双引都可以

<script>
    (function () {
        'use strict';
        var num = 10;
        function fn() { }
    })();
</script>
  • 为函数开启严格模式
function fn() {
        'use strict';
        //下面的代码按照严格模式执行
}

function fn() {
        //下面的代码按照普通模式执行
}

3.2 严格模式中的变化

严格模式对js的语法和行为,都做了一些改变

变量规定

  • 在正常模式中,如果一个变量没有声明就赋值,默认是全局变量; 严格模式下禁止这种用法,变量必须先声明,再使用
  • 严禁删除已经声明变量,例如 delet a; 语法报错

严格模式下this指向问题

  • 以前在全局作用域函数中的this指向window对象
  • 严格模式下全局作用域中函数中的this是undefined
  • 以前构造函数不加new也可以,会被当成普通函数,因为this指向window全局对象
  • 严格模式下,如果构造函数不加new调用,this会报错,因为是undefined
  • new实例化的构造函数指向创建的对象实例
  • 严格模式下,定时器this还是指向 window
  • 事件、对象还是指向调用者

函数变化

  • 函数不能有重名的参数
  • 函数必须声明在顶层,ES6引入块级作用域,不允许在非函数的代码块声明函数,例如,if 、for里面不要直接写函数
  • 更多严格模式要求参考:https://developer.mozilla.org/zh-Cn/docs/Web/JavaScript/Reference/Strict_mode

4. 高阶函数

高阶函数是对其他函数进行操作的函数,它接收函数作为参数或者将函数作为返回值输出
函数也是一种数据类型,同样可以作为参数,传递给另外一个参数使用,最典型的就是作为回调函数

<script>
     function fn(callback){
         callback && callback();
     }
     fn(function(){alert('hi')})
 </script>


 <script>
     function fn(){
         return function(){}
     }
     fn();
 </script>
 //此时fn 就是一个高阶函数

5. 闭包

5.1 变量作用域

变量根据作用域的不同分为两种:全局变量和局部变量

  • 函数内部可以使用全局变量
  • 函数外部不可以使用局部变量
  • 当函数执行完毕,本作用域内的局部变量会销毁

5.2 什么是闭包

闭包(closure) 指有权 访问另一个函数作用域中变量函数
简单理解就是,一个作用域可以访问另外一个函数内部的局部变量

闭包的作用: 延伸了变量的作用范围

案例1: 循环注册点击事件

 <script>
        /* 闭包应用: 点击li输出当前索引号 */
        var lis = document.querySelectorAll('.nav li');

        /* 第一种做法(以前的做法):利用动态添加属性的方式 */
        for (var i = 0; i < lis.length; i++) {
            lis[i].index = i;
            lis[i].onclick = function () {
                // 注意:这里不能直接打印i,因为这里的function是异步任务,只有点击了之后才会去执行   
                // 但是for循环是同步任务,会立马执行,  0 1 2 3 for循环执行完i++,最终i=4,点击任何li输出都是4  
                console.log(i);
                //要动态添加属性
                console.log(this.index);
            }
        }



        /* 第二种做法:闭包方式 */
        for (var i = 0; i < lis.length; i++) {
            //利用for循环创建四个  立即执行函数
            (function (i) {
                lis[i].onclick = function () {
                    console.log(i);
                }
            })(i);
        }
    </script>

案例2: 3秒钟之后打印li内容

<script>
        /* 闭包应用: 3秒钟之后,打印所有li元素中的内容 */
        var lis = document.querySelectorAll('.nav li');
        for (var i = 0; i < lis.length; i++) {
            //异步任务主要有三种情况:定时器中的回调函数、事件中的回调函数(鼠标点击、经过)、ajix中的回调函数
            //异步任务只有触发才会执行,这里只有三秒钟之后才会去执行这个回调函数,
            //即使你把3000改成0,定时器里面函数也不会立即执行,因为属于异步任务,会把这个函数放入任务队列
            //但是for循环属于同步任务,会立马执行,i又会变成4,lis[4]拿不到innerHTML
            /* setTimeout(function () {
                console.log(lis[i].innerHTML)
            }, 3000) */

            //利用闭包,每次循环都会创建一个立即执行函数
            (function (i) {
                setTimeout(function () {
                    console.log(lis[i].innerHTML)
                }, 3000)
            })(i);

        }
    </script>

案例3: 计算打车价格

   <script>
        /* 闭包应用: 计算打车价格
        打车起步价13块钱(3公里内),之后每多一公里多5块钱,用户输入公里数就可以计算打车价格
        如果有拥堵情况,总价格多收10块钱拥堵费 */
        var car = (function () {
            var start = 13;  //起步价
            var total = 0;   //总价
            return {
                //正常的总价
                price: function (n) {
                    if (n <= 3) {
                        total = start;
                    } else {
                        total = (n - 3) * 5 + start;
                    }
                    return total;
                },
                //拥堵后的费用
                yongdu: function (flag) {
                    return flag ? total + 10 : total;
                }
            }
        })();

        console.log(car.price(3));
        console.log(car.yongdu(true));
    </script>

思考题:立即执行函数的 this 指向 window

6. 递归

6.1 什么是递归

如果一个函数在内部可以调用其本身,那么这个函数就是递归函数
简单理解:函数内部自己调用自己,这个函数就是递归函数
由于递归很容易发生 “栈溢出” 错误(stack overflow),所以必须加退出条件 return

6.2 利用递归

利用递归函数求1-n阶乘 1 * 2 * 3 * 4 …n

     function fn(n) {
            if (n == 1) {
                return 1;
            }
            return n * fn(n - 1);
        }
        console.log(fn(3));
        console.log(fn(4));

6.3 浅拷贝和深拷贝

浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用

Object.assign(target,...sources)
//ES6新增方法可以浅拷贝

深拷贝拷贝多层,每一级别的数据都会拷贝

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 16:08:57  更:2022-04-06 16:12:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:36:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码