JavaScript高级笔记_003_函数进阶

  • 函数进阶
    • 函数的定义和调用
      • 函数的定义方式
      • 函数的调用方式
    • this
      • 改变函数内this 的指向
    • 严格模式
      • 什么是严格模式
      • 开启严格模式
      • 严格模式中的变化
    • 高阶函数
    • 闭包
      • 变量作用域
      • 什么是闭包
      • 闭包的案例
    • 递归
      • 什么是递归?
      • 利用递归求数学题
      • 利用递归求:根据id返回对应的数据对象
      • 浅拷贝和深拷贝

函数进阶

课程链接:

https://www.bilibili.com/video/BV1KJ411x7X7?p=50

函数的定义和调用

函数的定义方式

  1. 函数声明方式function 关键字(命名函数,自定义函数)

  2. 函数表达式(匿名函数)

  3. new Function('参数1', '参数2', '函数体')

    var f = new Function('a', 'b', 'console.log(a + b)');
    f(1, 2);
    
    • Function里面的参数必须是字符串格式

    • 第三种方式执行效率低,也不方便书写,因此较少使用

    • 所有函数都是****** 的实例(对象)**

    • 函数也属于对象

函数的调用方式

  1. 普通函数

    function fn() {console.log('人生巅峰');
    }fn();
    // 或者
    fn.call();
    
  2. 对象的方法

    var o = {sayHi: function() {console.log('人生的巅峰');}
    }
    
  3. 构造函数

    function Star() {console.log('人生的巅峰');
    }new Star();
    
  4. 绑定事件函数

    btn.onclick = function() {};
  5. 定时器函数

    // 这个函数是定时器1秒钟自动调用一次
    setInterval(function(){}, 1000);
  6. 立即执行函数

    (function() {console.log('人生巅峰');
    })();
    // 立即执行函数自动调用
    

this

改变函数内this 的指向

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

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

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

  1. call() 方法

    call() 方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的this 的指向。

    语法

    fun.call(thisArgm, arg1, arg2, ...);
    

    例子

    var o = {name: 'andy'
    }function fn() {console.log(this);
    };
    fn.call(o);
    

    ****主要作用可以实现继承

    function Father(uname, age, sex) {this.uname = uname;this.age = age;this.sex = sex;
    }function Son(uname, age, sex) {Father.call(this, uname, age, sex);
    }var son = new Son('刘德华', 18, '男');
    console.log(son);
    
  2. apply方法

    apply() 方法调用一个函数。简单理解为调用函数的方式,但是它可以改变this 指向

    语法

    fun.apply(thisArg, [argsArray]);
    
    • thisArg :在fun函数运行时指定的this

    • argsArray :传递的值,必须包含在数组里面(伪数组)

    • 返回值就是函数的返回值,因为它就是调用函数

    例子

    var o = {name: 'andy'
    };function fn(arr) {console.log(this);console.log(arr);
    }
    fn.apply(o, ['andy']);
    

    ****** 的主要应用**:比如说我们可以利用apply 借助数学内置对象求最大值

    var arr = [1, 66, 3, 99, 4];
    var max = Math.max.apply(Math, arr);
    var min = Math.min.apply(Math, arr);
    concole.log(max);
    concole.log(min);
  3. ****** 方法(重点)**

    bind() 方法不会调用函数。但是能改变函数内部this 指向

    语法

    fun.bind(thisArg, arg1, arg2, ...);
    • thisArg:在fun函数运行时指定的this值

    • arg1, arg2:传递的其他参数

    • 返回由指定的this值和初始化参数改造的原函数拷贝

    例子

    var o = {name: 'andy'
    };function fn(a, b) {console.log(this);console.log(a + b);
    }// 不会调用原来的函数,可以改变原函数内部的this
    var f = fn.bind(o, 1, 2);
    // 返回的是原函数改变this之后产生的新函数
    f();
    
    1. 不会调用原来的函数,可以改变原来函数的内部的this指向

    2. 返回的是原函数改变this 之后产生的新函数

    3. 如果有的函数不需要立即调用,但是又想改变这个函数内部的this指向,此时用bind

    4. 我们有一个按钮,当我们点击了之后,就禁用这个按钮,3秒之后开启这个按钮

      var btn = document.querySelector('button');
      btn.onclick = functionn() {this.disabled = ture; // 这个this指向的是btn这个按钮setTimeout(function() { // 定时器函数里面的this指向的是windowthis.disabled = false;}.bind(this), 3000) // 这个this指向的是btn这个对象
      }
      

严格模式

什么是严格模式

JavaScript除了提供正常模式外,还提供了严格模式(strict mode)。ES5的严格模式是采用具有限制性javascript变体的一种方式,即在严格的条件下运行JS代码。

严格模式在IE10以上版本的浏览器才会被支持,旧版本浏览器中会被忽略

严格模式对正常的javascript语义做了一些修改:

  1. 消除了javascript语法的一些不合理,不严谨之处,减少了 一些怪异行为

  2. 消除了代码运行的一些不安全之处,保证代码运行的安全

  3. 提高编译器效率,增加运行速度

  4. 禁用了在ECMAScript的未来版本中可能会定义的一些语法,为未来新版本的javascript做好铺垫。比如一些保留字如:class enum export extends inport super 不能做变量名

开启严格模式

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

  1. 为脚本开启严格模式

    需要在所有语句之前放一个特定语句"use strict";(或’use strict’;)

    'use strict';
    // 下面JS代码就会按照严格模式执行代码
    
    // 为整个脚本(script标签)开启严格模式的两种方法
    <script>'use strict';
    </script>
    <script>(function(){'use strict';})()
    </script>
    
  2. 为函数开启严格模式

    要给某个函数开启严格模式,需要把"use strict";(或’use strict’)声明放在函数体所有语句之前

    <script>function fn() {'use strict';...}function fun() {...}
    </script>
    

严格模式中的变化

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

  1. 变量规定

    1. 在正常模式中,如果一个变量没有声明就赋值,默认是全局变量。严格模式禁止这种用法,变量都必须先用var命令声明,然后再使用

    2. 严禁删除已经声明变量、例如,delete x;是语法错误的

  2. 严格模式下****** 指向问题**

    1. 以前在全局作用域函数中this指向window对象

    2. 严格模式下全局作用域函数中this指向undefined

    3. 以前构造函数时不用加new也可以调用,当普通函数,this指向全局对象

    4. 严格模式下,如果构造函数不加new调用,this会报错

    5. new实例化的构造函数指向创建的对象实例

    6. 定时器的this还是指向window

    7. 事件对象还是指向调用者

  3. 函数变化

    1. 函数不能有重名的参数

    2. 函数必须声明在顶层,新版本的javascript会引入“块级作用域”(ES6中已引入)。为了与新版本接轨,不允许在非函数的代码块内声明函数

高阶函数

高级函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出

function fn() {callback && callback();
}
fn(function(){alert("HELLO");});
function fn() {return function() {}
}
fn();

此时fn就是一个高阶函数

函数也是一种数据类型,同样可以作为参数,传递给拎一个参数使用。最典型的就是作为回调函数

闭包

变量作用域

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

  1. 函数内部可以使用全局变量

  2. 函数外部不可以使用局部变量

  3. 函数执行完毕,本作用域内的局部变量会销毁

什么是闭包

闭包(closure)指有权访问另一个函数 作用域中变量的函数

简单理解就是,一个作用域可以访问另一个函数内部的局部变量

function fn() {var num = 10;function fun() {console.log(num);}fun();
}
fn();
// 此时fn就是闭包

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

闭包的案例

  1. 循环注册点击事件

    <div class = 'nav'><li>榴莲</li><li>臭豆腐</li><li>鲱鱼罐头</li><li>大猪蹄子</li>
    </div>
    
    // 获取小li的方式// 1. 我们可以利用动态添加属性的方式
    var lis = document.querySelector('.nav').querySelectorAll('li');
    for(var i = 0; i < lis.length; i++) {lis[i].index = i;lis[i].onclick = function() {console.log(this.index);}
    }
    // 2. 利用闭包的方式得到当前小li的索引号
    for(var i = 0; i < lis.length; i++) {(function(i) {lis[i].onclick = function() {console.log(i);}})(i) // 把 i 传入立即执行函数
    }
    // 此时的闭包并不好
    
  2. 循环中的setTimeout()

    <div class = 'nav'><li>榴莲</li><li>臭豆腐</li><li>鲱鱼罐头</li><li>大猪蹄子</li>
    </div>
    
    // 闭包应用3秒之后打印所有li元素的内容
    var lis = var lis = document.querySelector('.nav').querySelectorAll('li');
    for(var i = 0; i < lis.length; i++) {(function(i) {setTimeout(function(){console.log(lis[i].innerHTML);}, 3000)})(i);
    }
    
  3. 计算打车价格

    // 打车起步价13(3公里内),之后没多一公里增加5块钱,用户输入公里数就可以计算打车价格
    // 如果有拥堵情况,总价格多收取10块钱拥堵费
    var car = (function() {var start = 13; // q起步价var total = 0; // 总价return {// 正常的总价pricr: function(n) {if(n <= 3) {total = start;} else {total = start + (n - 3) * 5;}return total;},// 拥堵之后的费用yd: function(flag) {return flag ? total + 10 : total;} }
    })();
    console.log(car.price(5)); // 23
    console.log(car.yd(ture)); // 33console.log(car.price(1)); // 13
    console.log(car.yd(false)); // 13
    

递归

什么是递归?

如果一个函数在内部可以调用其本身,那么这个函数就是递归函数

简单说:自己调用自己

递归函数的作用和循环效果一样

由于递归很容易出现“栈溢出”错误(stack overflow),所以必须加退出条件return

// 打印六句话
var num = 0;
function fn() {console.log('我要打印六句话');if(num === 6) {return; // 必须加return}num++;fn();
}
fn();

利用递归求数学题

  1. 求1*2*3*4*5*…*n 阶乘

    function fn(n) {if(n === 1 || n === 0) {return 1;}return n * fn(n - 1);
    }
    console.log(fn(4));
    
  2. 求斐波那契数列

    function fn(n) {if(n === 2 || n === 1) {return 1;}return fn(n - 1) + fn(n - 2);
    }console.log(fn(4));
    

利用递归求:根据id返回对应的数据对象

var data = [{id: 1,name: '家电’,goods: [{id: 11,gname: '冰箱'}, {id: 12,gname: '洗衣机'}]
}, {id: 2,name: '服饰'
}];// 我们想要做输入id号,就可以返回的数据对象
// 1. 利用forEach去遍历里面的每一个对象
function getId(json, id) {var o = {};json.forEach(function(item) {if(item.id == id) {// console.log(item);return item;} else if(item.goods && item.goods.length > 0) {// 2. 得到里层的数据0 = getId(item.goods, id);}});return o;
}console.log(getId(data, 11));

浅拷贝和深拷贝

  1. 浅拷贝只是拷贝一层,更深层次对象的值拷贝引用

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

    // 浅拷贝拷贝更层次的时候只是拷贝地址
    var obj = {id: 1,name: 'andy'
    };
    var o = {};
    for(var k in obj) {// k是属性名,obj[k]属性值o[k] = obj[k];
    }// 浅拷贝的语法糖
    Object.assign(o, obj); // 把obj拷贝给o
    
    // 深拷贝
    var obj = {id: 1,name: 'andy',mdg: {age: 18},color: ['red','green']
    };
    var o = {};// 封装函数
    function deepCopy(newObj, oldObj) {for(var k in oldObj) {// 判断我们的属性值属于哪种数据类型// 1. 获取属性值 oldObj[k]var item = oldObj[k];// 2. 判断这个值是否为数组if (item instanceof Array) {newObj[k] = [];deepCopy(newObj, item);} else if(item instanceof Object) {// 3. 判断这个值是否是对象newObj[k] = {};deepCopy(newObj[k], item);} else {// 4. 属于简单数据类型newObj[k] = item;}}
    }deepCopy(o, obj);
    // 数组也属于对象
    

JavaScript高级笔记_003_函数进阶相关推荐

  1. JavaScript 高级3 :函数进阶

    JavaScript 高级3 :函数进阶 Date: January 19, 2023 Text: 函数的定义和调用.this.严格模式.高阶函数.闭包.递归 目标: 能够说出函数的多种定义和调用方式 ...

  2. JavaScript高级笔记_002_构造函数和原型

    JavaScript高级笔记_002_构造函数和原型 构造函数和原型 构造函数和原型 概述 构造函数 构造函数的问题 构造函数原型`prototype` 对象原型`__proto__` (四个下划线) ...

  3. JavaScript 高级笔记

    JavaScript 高级笔记 1. 基础总结深入 1.1 数据类型 1.1.1 数据类型分类 1.1.2 数据类型判断 1.1.3 数据类型相关问题 1.2 数据.变量与内存 1.2.1 什么是数据 ...

  4. JavaScript高级day02-AM【函数的prototype、显式原型与隐式原型、原型链】

    笔记.视频.源码:JavaScript(基础.高级)笔记汇总表[尚硅谷JavaScript全套教程完整版] 目   录 P15 15.尚硅谷_JS高级_函数的prototype 15:04 1. 函数 ...

  5. 菜鸟教程-Javascript学习笔记-JS函数之前

    教程连接是: https://www.runoob.com/js/js-tutorial.html DOM(一些操作页面元素的方法) BOM(一些操作浏览器的方法) ################# ...

  6. Python学习笔记---day12函数进阶

    day12函数进阶 函数的嵌套 闭包 装饰器 上述内容均属于函数部分必备知识,以后开发时直接和间接都会使用,请务必理解(重在理解,不要去死记硬背). 1. 函数嵌套 Python中以函数为作用域,在作 ...

  7. 轩小陌的Python笔记-day11 函数进阶

    day11 函数进阶 目标:掌握函数相关易错点 & 项目开发必备技能. 今日概要: 参数的补充 函数名到底是什么? 返回值和print,傻傻分不清楚. 函数的作用域 1.参数的补充 在函数基础 ...

  8. JavaScript高级 笔记

    1. 预编译 1.1 全局对象(GO对象) window js引擎会整合所有<script>标签中的内容, 产生window对象 全局变量: 全局对象的一个属性 全局函数: 全局对象的一个 ...

  9. Javascript学习笔记2——函数

    在Javascript中,function才是Javascript的第一型.当我们写下一段函数时,其实不过是建立了一个function类型的实体. 就像我们可以写成这样的形式一样: function ...

  10. JavaScript高级笔记

    今日内容: 1. JavaScript:1. ECMAScript:2. BOM:3. DOM:1. 事件 DOM简单学习:为了满足案例要求 * 功能:控制html文档的内容 * 获取页面标签(元素) ...

最新文章

  1. Jupyter Notebook快捷键
  2. java 计算器 小程序_java应用小程序计算器
  3. Java多线程之CAS深入解析
  4. React开发(112):不要写多余的select
  5. Python 图像处理实战 | 图像的灰度非线性变换之对数变换、伽马变换
  6. 那些年我们清除过的浮动
  7. 程序抓取网站数据HttpWebRequest
  8. Devexpress VCL Build v2014 vol 14.2.6 发布
  9. python 中类与对象
  10. SharePoint开发中上传Excel问题 无法更新Microsoft Office文档
  11. 计算机科学工学,2016考研工学类专业介绍:计算机科学与技术
  12. MySQL 函数:IF(expr,v1,v2) 判断
  13. 从无到有构建计算机网络
  14. 阿里云企业邮箱的imap和pop3设置
  15. VSTOOutlook发邮件时To中和中按照名字首字母排序
  16. BZOJ---4484:[Jsoi2015]最小表示【bitset】
  17. 《一封来自姐姐的信》
  18. 英特尔David Tuhy:英特尔®傲腾技术成功的原因
  19. Every Document Owns Its Structure: Inductive Text Classification via Graph Neural Networks论文理解
  20. ESP8266-天猫精灵(智能家居)

热门文章

  1. SVN及Git使用方法
  2. scrapy 爬取今日头条报错 'SSL routines', 'SSL23_GET_SERVER_HELLO', 'unknown protocol'
  3. 你知道什么是半自动驾驶系统吗
  4. 东华大学2021计算机OJ题——基本练习(15 abc数字)
  5. 职场小白之隐藏或显示按钮
  6. [VB.NET]100分求一小段代码 ~~ 在线等 ~~ 当日揭帖
  7. 使用scrapy爬取stl容器的时间复杂度
  8. 量子计算机代表人类最强科技,量子计算机和可控核聚变,谁对人类未来发展更重要?...
  9. 国际电子邮件协会判定垃圾邮件规则
  10. 可以救命的地震预警你开了吗?