声明式编程 【高阶函数】【剩余参数】【箭头函数的this】【声明式函数与赋值式函数】【undefined和null】【作用域】

本文深入探讨JavaScript中的高阶函数,如map()、filter()、reduce(),及其应用场景。同时,解析了this指向、箭头函数、基础语法、作用域等关键概念,为前端开发者提供全面的技术指南。
摘要由CSDN通过智能技术生成

目录

高阶函数

forEach() 和 map() 的应用场景

剩余参数

动态改变函数体内部this的指向(call, apply) 对象继承

声明式函数与赋值式函数(或叫:匿名函数)

箭头函数

this指向

基础语法

undefined和null

全局作用域、函数作用域、块级作用域

arguments对象

arguments对象+类数组转数组+apply() 的例子

其它 


高阶函数

高阶函数是对其他函数进行操作的函数,可以将它们作为参数或返回它们。简单来说,高阶函数是一个函数,它接收函数作为参数或将函数作为输出返回。

例如,Array.prototype.map,Array.prototype.filter和Array.prototype.reduce是语言中内置的一些高阶函数。

 

var numbers = [1,2,3,4,5]
var doubled = numbers.map(function(n) {
  return n * 2
})
console.log(doubled) //=> [2,4,6,8,10]
var numbers = [1,2,3,4,5]
var total = numbers.reduce (function (sum, n) {
  return sum + n
});
console.log (total) //=> 15

 【当这个类里面是2种类型时,例子为number和boolean】


forEach() 和 map() 的应用场景

forEach() may be preferable when you’re not trying to change the data in your array, but instead want to just do something with it — like saving it to a database or logging it out

And map() might be preferable when changing or altering data. Not only is it faster but it returns a new Array. This means we can do cool things like chaining on other methods ( map()filter()reduce(), etc.)

let arr = [1, 2, 3, 4, 5];
let arr2 = arr.map(num => num * 2).filter(num => num > 5);
// arr2 = [6, 8, 10]
  • 能用forEach()做到的,map()同样可以,反过来也是如此。
  • forEach()允许callback更改原始数组的元素。map()则返回新的数组。
let arr = [1, 2, 3, 4, 5];

let doubled = arr.map(num => {
    return num * 2;
}); // arr = [2, 4, 6, 8, 10]

arr.forEach((num, index) => {
    return (arr[index] = num * 2);
}); // arr = [2, 4, 6, 8, 10]

Array.prototype.map()

map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。


剩余参数

剩余参数语法允许我们将一个不定数量的参数表示为一个数组。

可实现浅拷贝

   

> function rr(a, ...test) {console.log(a,"___",test)}
> rr(1,2,3,4,5)
// 1 "___" (4) [2, 3, 4, 5]

动态改变函数体内部this的指向(call, apply) 对象继承

语法:Function.call([thisObj[,arg1[, arg2[, [,.argN]]]]])
定义:调用一个对象的一个方法,以另一个对象替换当前对象。即 thisObj 继承了 Function 的属性和方法。

number 本身没有 max 方法,但是 Math 有,我们就可以借助 call 或者 apply 使用其方法:

var  numbers = [5, 458 , 120 , -215 ]; 
var applyMaxInNumbers = Math.max.apply(Math, numbers);  //458
var applyMaxInNumbers = Math.max.apply(null, numbers);  //458 指定null会自动替换为指向全局对象
var applyMinInNumbers = Math.min.apply(Math,numbers); //-215

借用构造函数实现继承:

function Person(name,age) {
    this.name=name;
    this.age=age;
}

var Student=function(name,age,gender) {
    Person.call(this,name,age);//this继承了person的属性和方法
    this.gender=gender;
}
var student=new Student("陈安东", 20, "男");
alert("姓名:"+student.name+"\n"+"年龄:"+student.age+"\n"+"性别:"+student.gender);

// 姓名:陈安东 年龄:20 性别:男

声明式函数与赋值式函数(或叫:匿名函数)

JS的函数定义分为3种,声明式函数:function test() {}; 匿名函数:var test = function() {}。前面2种比较常用,最后一种是构造函数定义:var fun3 = new Function("a", "b", "return a * b");

JS的解析过程分为2个阶段,预编译期和执行期。预编译期就是:将函数声明和变量声明提升到当前作用域的顶端,需要注意的是此时处理的函数只是声明式函数,变量也只是进行了声明并未初始化和赋值。执行期就是从上到下编译代码块。

 函数和变量相比,会被优先提升。这意味着函数会被提升到更靠前的位置。

 JavaScript中的代码块是指由<script>标签分割的代码段。

Fn() // 打印:test2,因为同名函数后面会覆盖前面

function F() {
    console.log("test1")
}
function F() {
    console.log("test2")
}
Fn(); // 打印:"test 1",因为声明式的Fn()函数在预编译阶段就被处理了,所以即使Fn()调用在声明式函数之前也能执行。

function Fn() {
    console.log("test 1");
}

var Fn = function() {
    console.log("test 2");
} // 所以函数表达式中的Fn也不会是个函数,Fn在预编译期被放入了词法环境中,
// 被赋值为undefined,等到执行期才会变为一个function

只有声明var a这个操作会被提升,而= 233这个赋值操作并不会被提升。但是为什么a是undefined呢?因为在预编译期JS会找到var 声明的变量添加到词法环境中,并初始化一个值undefined。等后期执行的时候再把233赋值给a。

console.log(a); // 打印"undefined",因为变量在预编译期仅声明,并未初始化及赋值
var a = 233;

var x = 1;                 // 声明 + 初始化 x
console.log(x + " " + y);  // '1 undefined'
var y = 2;                 // 声明 + 初始化 y

最佳实践:无论是函数还是变量,都先声明再使用。 

function testOrder(arg) {
    console.log(arg); // arg是形参,不会被重新定义
    console.log(a); // 因为函数声明比变量声明优先级高,所以这里a是函数
    var arg = 'hello'; // var arg;变量声明被忽略, arg = 'hello'被执行
    var a = 10; // var a;被忽视; a = 10被执行,a变成number
    function a() {
        console.log('fun');
    } // 被提升到作用域顶部
    console.log(a); // 输出10
    console.log(arg); // 输出hello
}; 
testOrder('hi');
/* 输出:
hi 
function a() {
        console.log('fun');
    }
10 
hello 
*/

 参考:https://blog.csdn.net/chen_zw/article/details/18502937

https://juejin.im/post/5d36b06af265da1ba84ad143


箭头函数

this指向

引入箭头函数有两个方面的作用:更简短的函数并且不绑定this

  • 在箭头函数出现之前,每一个新函数根据它是被如何调用(运行期)的来定义这个函数的this值(在全局函数中,this指向windows对象;当函数被作为某个对象的方法调用时,this就等于那个对象
  • 箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this,在函数定义时就继承了定义函数的对象

基础语法

  • (参数1, 参数2, …, 参数N) => { return 表达式; }  // 相当于:(参数1, 参数2, …, 参数N) => { 函数声明 }
  • 当只有一个参数时,圆括号是可选的。没有参数的函数应该写成一对圆括号。
  • 当箭头函数的函数体只有一个 `return` 语句时,可以省略 `return` 关键字和方法体的花括号。
  • 加括号的函数体返回对象字面表达式: 参数=> ({foo: bar})
  • 在一个简写体中,只需要一个表达式,并附加一个隐式的返回值。在块体中,必须使用明确的return语句。
var func = x => x * x;                  
// 简写函数 省略return

var func = (x, y) => { return x + y; }; 
//常规编写 明确的返回值

undefined和null

undefined == null; // true

if (!undefined) {console.log(233)} // 打印:233
if (!null) {console.log(233)} // 打印:233

null的作用:给一个变量赋值,基本数据类型可以直接赋值,那么我要赋值一个对象,或者清空一个对象的赋值,该怎么办呢?

 那就发一个空的对象吧,即:null。当然变量被赋值为 null 后,还有另一层作用,那就是方便JS引擎对这个变量进行垃圾回收。

  • undefined,用于变量声明时;
  • null,用于变量赋值时;

全局作用域、函数作用域、块级作用域

es6之前没有块级作用域。

如果一个变量在函数体内声明,则该变量的作用域为整个函数体。

由于JavaScript的函数可以嵌套,此时,内部函数可以访问外部函数定义的变量,反过来则不行。

不在任何函数内定义的变量就具有全局作用域。

ES6标准引入了新的关键字const来定义常量,constlet都具有块级作用域。 


arguments对象

arguments对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,第一个参数在索引0处。

arguments对象不是一个 Array 。它类似于Array,但除了length属性和索引元素之外没有任何Array属性。例如,它没有 pop 方法。但是它可以被转换为一个真正的Array

var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);

// ES2015
const args = Array.from(arguments);
const args = [...arguments];

arguments对象+类数组转数组+apply() 的例子

需求:定义一个 log 方法,让它可以代理 console.log 方法,并给每一个 log 消息添加一个"(doView)"的前辍

function log(){
  var argsData = Array.prototype.slice.call(arguments);
  argsData.unshift('(doView)');
  console.log.apply(window, args);
};

其它 

       【加括号的函数体】

    -------------


filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。 


reduce() 

var initialValue = 0;
var sum = [{x: 1}, {x:2}, {x:3}].reduce(
    (accumulator, currentValue) => accumulator + currentValue.x
    ,initialValue
);

console.log(sum) // logs 6

export const enum TemplateRegion {
  Head = 'Head',
  Neck = 'Neck',
  Thorax = 'Thorax',
}

export interface RegionImageSource {
  id: TemplateRegion;
  text: string;
  src: string
}

export const IMAGE_SOURCES: RegionImageSource[] = [
  {id: TemplateRegion.Head, text: 'hi', src: 'hei'},
  {id: TemplateRegion.Neck, text: 'hi', src: 'hei'},
  {id: TemplateRegion.Thorax, text: 'hi', src: 'hei'}
]

interface Activate<T extends { id: any }> {  // 不要直接extends RegionImageSource
  data: T;
  active: boolean;
}

export const regions: Activate<RegionImageSource>[] = IMAGE_SOURCES.map((s) => ({
  data: s,
  active: false,
}));

在控制台打印,结果如下:

console.log(regions)

[{data: {id: TemplateRegion.Head, text: 'hi', src: 'hei'},
active: false
},
{data: {id: TemplateRegion.Neck, text: 'hi', src: 'hei'},
active: false
},
{data: {id: TemplateRegion.Thorax, text: 'hi', src: 'hei'},
active: false
}]

改变 this 的指向:

  • 使用 ES6 的箭头函数
  • 在函数内部使用 _this = this
  • 使用 applycallbind
  • new 实例化一个对象

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值