JS面试题--JS函数式编程

news2024/12/25 22:31:21

JS函数式编程

实现apply、call、bind

image-20230110220539663

01_call函数的实现

// apply/call/bind的用法
// js模拟它们的实现? 难度

// 给所有的函数添加一个hycall的方法 同个原型链
Function.prototype.hycall = function (thisArg, ...args) {
  // 在这里可以去执行调用的那个函数(foo)
  // 问题: 得可以获取到是哪一个函数执行了hycall
  // 1.获取需要被执行的函数  这个this就是通过隐式绑定调用函数的时候的---默认绑定调用我们的这个函数  例如foo.hycall() 这里this就是通过隐式绑定到foo这个函数
  var fn = this;

  // 2.对thisArg转成对象类型(防止它传入的是非对象类型)---指定this指向的参数
  // thisArg = thisArg ?Object.create(thisArg) :window 这个情况下如果第一个参数值是0 会变成false 不严谨 ,所以还是最好进行类型判断
  // Object(thisArg)方法--返回结果是传过来的参数对应的类型
  thisArg =
    thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;
  // fn.call(thisArg) 这样写相当于用了内置函数 不过也能实现
  // 3.调用需要被执行的函数 给thisArg添加一个fn属性 用完删除 不直接写fn(),是因为这样就变成独立函数了
  thisArg.fn = fn; //thisArg.fn = fn 这里会多出一个属性fn 最后不用可以删除 delete  或者用fn.call(thisArg)
  // ...args剩余参数 调用函数的时候传入的参数可以不限制数量
  var result = thisArg.fn(...args);
  // 调用完删除属性
  delete thisArg.fn;

  // 4.将最终的结果返回出去
  // 函数用不用写返回值,取决于外面要不要用这个结果
  return result;
};

function foo() {
  console.log("foo函数被执行", this);
}

function sum(num1, num2) {
  console.log("sum函数被执行", this, num1, num2);
  return num1 + num2;
}

// 1.系统的函数的call方法
foo.call(undefined); //获取前面调用的这个函数对象,就可以调用本函数来执行call方法
var result = sum.call({}, 20, 30);
// console.log("系统调用的结果:", result)

// 2.自己实现的函数的hycall方法
// 默认进行隐式绑定
// foo.hycall({name: "why"})
foo.hycall(undefined);
var result = sum.hycall("abc", 20, 30);
console.log("hycall的调用:", result);

// var num = {name: "why"}
// console.log(Object(num))
  ``

02_ES6的剩余参数

// rest parameters
function sum(...nums) {
  // 剩余参数 命名自定义 将我们传入的参数放到一个数组里面 参数是数组类型
  //  例如var 自定义命名 =[里面是传入的参数1,里面是传入的参数2,...]
  // var nums = [10,20,30,...]
  console.log(nums);
}

sum(10);
sum(10, 20);
sum(10, 20, 30);
sum(10, 20, 30, 40, 50);

// 展开运算符 spread
var names = ["abc", "cba", "nba"];
// var newNames = [...names]
function foo(name1, name2, name3) {}
// 内部原理  相当于遍历names这个数组的所有元素,将变量的所有元素放入到names中
foo(...names);

03_apply函数的实现

// 自己实现hyapply的过程
Function.prototype.hyapply = function (thisArg, argArray) {
  // 1.获取到要执行的函数
  var fn = this;

  // 2.处理绑定的thisArg
  thisArg =
    thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;

  // 3.执行函数
  thisArg.fn = fn;
  var result;
  // 普通写法
  // if (!argArray) { // argArray是没有值(没有传参数)直接调用
  //   result = thisArg.fn()
  // } else { // 有传参数
  //   result = thisArg.fn(...argArray)
  // }
  //三元运算符的写法
  // argArray = argArray ? argArray: []
  // 逻辑或写法 有值为 argArray 没值为[]
  argArray = argArray || [];
  result = thisArg.fn(...argArray);

  delete thisArg.fn;

  // 4.返回结果
  return result;
};

// 方法
//参数数量一致 ,形参和实参的数量一致
function sum(num1, num2) {
  console.log("sum被调用", this, num1, num2);
  return num1 + num2;
}
//参数数量不一致 ,形参和实参的数量不一致,形参少
function foo(num) {
  return num;
}
// 参数数量不一致,没有写形参 ,没传参数会默认变成undefined 展开运算符就会有问题--变成...undefined
function bar() {
  console.log("bar函数被执行", this);
}

// 1.系统调用
// apply的第一个参数是this的指向 ,第二个参数类型是数组 ,是传递过来的参数
// var result = sum.apply("abc", 20)
// console.log(result)

// 2.自己实现的调用
var result = sum.hyapply("abc", [20, 30]);
console.log(result);
//
// var result2 = foo.hyapply("abc", [20])
// console.log(result2)

// edge case  其实还有2很多的边界情况
// bar.hyapply(0);

04_bind函数的实现

// 自己实现bind
Function.prototype.hybind = function (thisArg, ...argArray) {
  // 1.获取到真实需要调用的函数
  var fn = this;

  // 2.绑定this
  thisArg =
    thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;

  function proxyFn(...args) {
    // 3.将函数放到thisArg中进行调用
    thisArg.fn = fn;
    // 特殊: 对两个传入的参数进行合并
    var finalArgs = [...argArray, ...args];
    var result = thisArg.fn(...finalArgs);
    delete thisArg.fn;

    // 4.返回结果
    return result;
  }
  // 返回一个新函数
  return proxyFn;
};
// 函数方法
function foo() {
  console.log("foo被执行", this);
  return 20;
}

function sum(num1, num2, num3, num4) {
  console.log(num1, num2, num3, num4);
}

// 1.系统的bind使用
var bar = foo.bind("abc");
bar();
// new函数的bind的使用 写法1.
// var newSum = sum.bind("aaa", 10, 20, 30, 40)
// newSum()
// 写法2 在调用的时候再传
// var newSum = sum.bind("aaa")
// newSum(10, 20, 30, 40)
// 写法3 bind的时候传和调用的时候也传
// var newSum = sum.bind("aaa", 10)
// newSum(20, 30, 40)

// 2.使用自己定义的bind
// var bar = foo.hybind("abc")
// var result = bar()
// console.log(result)

var newSum = sum.hybind("abc", 10, 20);
var result = newSum(30, 40);

认识arguments

image-20230111153959436

05_arguments基本使用

function foo(num1, num2, num3) {
  // 类数组对象中(长的像是一个数组, 本质上是一个对象): arguments
  // console.log(arguments)

  // 常见的对arguments的操作是三个
  // 1.获取参数的长度 是传来的实参参数长度
  console.log(arguments.length);

  // 2.根据索引值获取某一个参数 实参参数
  console.log(arguments[2]);
  console.log(arguments[3]);
  console.log(arguments[4]);

  // 3.callee获取当前arguments所在的函数
  console.log(arguments.callee);
  // arguments.callee()
}

foo(10, 20, 30, 40, 50);

arguments转成array

image-20230111154125153

06_arguments转array

function foo(num1, num2) {
  // 1.自己遍历
  // var newArr = []
  // for (var i = 0; i < arguments.length; i++) {
  //   newArr.push(arguments[i] * 10)
  // }
  // console.log(newArr)

  // 2.arguments转成array类型
  // 2.1.自己遍历arguments中所有的元素

  // 2.2.利用Array.prototype.slice将arguments转成array
  var newArr2 = Array.prototype.slice.call(arguments);
  console.log(newArr2);

  var newArr3 = [].slice.call(arguments);
  console.log(newArr3);

  // 2.3.ES6的语法
  var newArr4 = Array.from(arguments);
  console.log(newArr4);
  var newArr5 = [...arguments]; //遍历arguments中的所有元素,再将元素挨个放到这个数组中
  console.log(newArr5);
}

foo(10, 20, 30, 40, 50);

// 额外补充的知识点: Array中的slice实现
// Array.prototype.hyslice = function(start, end) {
//   var arr = this
//   start = start || 0
//   end = end || arr.length
//   var newArray = []
//   for (var i = start; i < end; i++) {
//     newArray.push(arr[i])
//   }
//   return newArray
// }

// var newArray = Array.prototype.hyslice.call(["aaaa", "bbb", "cccc"], 1, 3)
// console.log(newArray)

// var names = ["aaa", "bbb", "ccc", "ddd"]
// names.slice(1, 3)

箭头函数不绑定arguments

image-20230111155202191

07_箭头函数中没有arguments

// 1.案例一:
// var foo = () => {
// 箭头函数内部是没有arguments,会从作用域上层寻找,不过在浏览器中全局是没有arguments,在node中有arguments
//   console.log(arguments)
// }

// foo()

// 2.案例二:
function foo() {
  var bar = () => {
    console.log(arguments);
  };
  return bar;
}

var fn = foo(123);
fn();

// 3.案例三:
var foo = (num1, num2, ...args) => {
  console.log(args); //[30,40,50]
};

foo(10, 20, 30, 40, 50);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/157656.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

亚马逊云科技:“云”筹帷幄,打造数据驱动型企业

数据对提高企业生产和资源配置的效率、优化经济结构的作用日益凸显。工业和信息化部发布的《“十四五”大数据产业发展规划》已明确将数据作为新时代重要的生产要素和国家基础性战略资源。埃森哲研究显示&#xff0c;到2022年&#xff0c;90%的企业战略明确将把数据作为关键的企…

前端面试题回顾——React重要知识

文章目录React相关问题1. 函数式组件与Class组件有什么不同&#xff1f;2. 说说React的fiber架构&#xff1f;3. 协调4. 虚拟DOM (Virtual DOM)React相关问题 1. 函数式组件与Class组件有什么不同&#xff1f; 答&#xff1a; ① 函数式组件不需要继承&#xff0c;直接 “fun…

数据结构基础——认识数据结构与算法

目录 &#x1f354;什么是数据结构&#xff1f; &#x1f32d;1.数据的逻辑结构 &#x1f32d;NUM 1 : 集合 &#x1f32d;NUM 2 : 线性结构 &#x1f32d;NUM 2 : 树形结构 &#x1f32d;NUM 4 :图结构&#xff08;网状结构&#xff09;…

浅谈反弹shell

目录反弹shell总结一、文件描述符二、重定向1、输入重定向2、输出重定向3、错误输出重定向4、exec 绑定重定向三、实现反弹shell的几种方式方法一&#xff1a; find 反弹ubuntu find反弹shell失败的问题任务计划反弹shell失败的问题方法二&#xff1a;使用python反弹&#xff0…

Flink系列-4、Flink运行架构

版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接和本声明。 大数据系列文章目录 官方网址&#xff1a;https://flink.apache.org/ 学习资料&#xff1a;https://flink-learning.org.cn/ 目录Flink基石Fli…

刚当上leader,我让组员去开会,他非说有更重要的会

☆ 职场上经常有那么一种情况就是组长喊组员开会&#xff0c;开周会&#xff0c;开晨会&#xff0c;开各种会&#xff0c;而更有一种常见的情况呢就是组长缺失威严&#xff0c;喊组员开会&#xff0c;组员不听话&#xff0c;说有更重要的会议&#xff0c;不想参加。 ☆ 本文将以…

VIT学习心得

来源&#xff1a;投稿 作者&#xff1a;橡皮 编辑&#xff1a;学姐 小声逼逼 在过去的两年里&#xff0c;Vision Transformer(ViT)是计算机视觉(cv)领域最有影响力的工作之一。「它推翻了2012年在Alex net中提出的CNN在CV领域的统治地位&#xff1a; 当能够获得足够多的预训练…

无接触式磁旋转编码器AS5040介绍

无接触式磁旋转编码器AS5040简介AS5040 是一款无接触式磁旋转编码器&#xff0c;用于精确测量整个360内的角度。此产品是一个片上系统&#xff0c;在单个封装内整合了集成式Hall 元件、模拟前端和数据信号处理功能。测量角度时&#xff0c;只需简单地配备1 个在芯片中心上方旋转…

Spring5的全细节回顾总结

概述&#xff1a; https://cntofu.com/book/95/33-what-new-in-the-spring-framework.md 这个不错。 轻量级javaee框架。 针对于bean的生命周期进行管理。 解决企业应用开发的复杂性。 核心&#xff1a; ​ IOC&#xff1a;控制反转&#xff0c;把创建对象的过程交给sprin…

第一天 Blender操作 | 大帅老猿threejs特训【超详细】

前言 这一天主要是基础理论的学习。 本人学习资料仓库 https://gitee.com/zhang_dezheng_hsr/three-demo.git YCY-TrainingCamp-S2: 在原有的文件上添加本人的学习记录 第一天 Blender操作 | 大帅老猿threejs特训【超详细】【我在掘金的同名文章】 一、大纲 二、THREE 基础概…

Linux查看某个应用的CPU/内存/网卡使用情况

1.查看CPU的使用率 # ps -ef | grep zabbix 进程号是1715 # top -p 1715 可以看到CPU的使用率是0 &#xff0c; 内存的使用率是0 2.查看内存真实使用了多少 #cat /proc/[pid]/status #cat /proc/1715/status VmPeak:进程所使用的虚拟内存的峰值 VmSize: 进程当前使用…

22.字符串初始化方法及赋值,字符串和指针总结

目录 初始化 1.字符数组初始化 2.指针指向文字常量区&#xff0c;初始化 3.指针指向堆区&#xff0c;堆区存放字符串 使用时赋值 1.字符数组&#xff0c;使用scanf或者strcpy 2.指针指向文字常量区 3.指针指向堆区&#xff0c;堆区存放字符串 初始化 1.字符数组初始化 …

各国家语言代码对照表

来源如下 Language Code Tablehttp://www.lingoes.cn/zh/translator/langcode.htm 详情如下 语言代码语言名称af南非语af-ZA南非语ar阿拉伯语ar-AE阿拉伯语(阿联酋)ar-BH阿拉伯语(巴林)ar-DZ阿拉伯语(阿尔及利亚)ar-EG阿拉伯语(埃及)ar-IQ阿拉伯语(伊拉克)ar-JO阿拉伯语(约旦…

万字详解 Linux 网络管理

万字详解 Linux 网络管理1.Linux处理数据包过程2.和网络相关的几个文件说明网卡配置文件ifcfg-*DNS配置文件/etc/resolv.conf&#xff08;CentOS6环境&#xff09;/etc/services3.网络接口配置和主机名ifconfigifcfghostname命令4.网关/路由5.网关/路由相关命令route命令配置永…

netty(1):NIO 基础之三大组件

1 三大组件 1.1 Channel & Buffer channel 有一点类似于 stream&#xff0c;它就是读写数据的双向通道&#xff0c;可以从 channel 将数据读入 buffer&#xff0c;也可以将 buffer 的数据写入 channel&#xff0c;而之前的 stream 要么是输入&#xff0c;要么是输出&…

如何用idea快速的debug本地程序

介绍大家都经常用idea开发, 开发过程中运行程序就会出现各种意料之外的异常, 如果解决这些异常, 尤其是三方jar包抛出的异常,就是一个很关键和棘手的问题.配置环境在第一个选项位置点开后会弹出配置页面,里面可以配置一些启动需要的环境变量.第二个是debug启动按钮第三个是程序…

SQL 优化方案(规范)

SQL优化1、SQL执行顺序2、前置条件2.1、使用explain分析SQL执行计划2.2、开启慢sql日志2.3、慢查询时间设置。默认情况下long_query_time的值为10秒&#xff0c;可以使用命令修改&#xff0c;也可以在my.cnf参数里面修改。3、基础Sql优化3.1、小表驱动大表3.2、高效的分页3.3、…

【linux入门】Linux基础知识学习笔记

文章目录【第一章-宏观知识】1.硬件和软件的关系2.操作系统 是什么、作用是什么3.常见的操作系统4.Linux的诞生5.Linux内核 是什么6.Linux发行版 是什么7.WSL是什么8.虚拟机快照9.FinalShell&#xff08;Xshell替代品&#xff09;【第二章-Linux基础命令】1.Linux目录结构2.什么…

Linux下ElasticSearch安装和基本使用

安装 下载安装目录:/home/es-7.12.0 es启动用户:zmsz 出于安全考虑,elasticsearch默认不允许以root账号运行,所有一定要创建一个其他用户执行启动命令,不然一定会报错!! 创建用户:useradd zmsz 设置密码:passwd zmsz下载解压 下载:官网 以最新版8.6为准,执行wget …

MySQL中的limit分页的使用

SQL准备 create table tb_students (id int auto_increment primary key comment 主键ID,studentid char(9) unique not null comment 学生学号,name varchar(10) not null comment 学生姓名,gender char(1) not null comment 学生性别 ) comment 学生表;insert into tb_stude…