【JavaScript】函数专题/IIFE/闭包/短路

8 篇文章 0 订阅

函数

默认参数的设置

//在传参处定义默认值:ES6
const createBooking = function(Num,
	passengers = 1,
	price = 199 * passengers){
//ES5:
passengers = passengers || 1;//利用短路特性
price = price || 199;
}

函数优先

将函数看作对象(Object)的一种,函数也是一种值,因此可以将他们存储为一个变量const a = function(){},或将一个函数作为返回值返回,还有函数的方法(methods)

高阶函数:higher order function

两种形式:
  • 接收另一个函数作为参数的函数:
    addEventListenerbtnNew.addEventListener('click', fA() {} );;
    fA()为回调函数:当监听器被调用,则调用fA;
  • 返回新函数
回调函数例:

优势:使函数更加抽象,避免代码复用

'use strict';//严格模式,语法检测会更严格,错误少

const oneWord = function (str) {
    return str.replace(/ /g, '').toLowerCase();
};

const upperFirstword = function (str) {
    const [first, ...rest] = str.split(' ');
    return [first.toUpperCase(), ...rest].join(' ');
};

const transformer = function (str, fn) { //fn为需要传入的函数
    console.log(`Original string: ${str}`);
    console.log(`Transformed string: ${fn(str)}`);

    console.log(`Transformed by: ${fn.name}`);
}
//不同的调用
transformer('JavaScript is the best!', upperFirstword);
transformer('JavaScript is the best!', oneWord);
函数返回函数
const greet = function (greeting) {
    return function (name) {
        console.log(`${greeting} ${name}`);
    }
};

const greeterHey = greet('Hey');
greeterHey('Jonas');
greeterHey('Steven');

//另一种调用方式
greet('Hello')('Jonas');

//箭头函数方式编写
const greetArr = greeting => name =>console.log(`${greeting} ${name}`);

call、apply、bind

call函数

call是函数的函数,参数首先是函数中this的指向,然后是其他参数:
call函数可以操纵this

//对象1
const lufthansa = { 
  airline: 'Lufthansa',
  iataCode: 'LH',
  bookings: [],
  // book: function() {}
  book(flightNum, name) {
    console.log(
      `${name} booked a seat on ${this.airline} flight ${this.iataCode}${flightNum}`
    );
    this.bookings.push({ flight: `${this.iataCode}${flightNum}`, name });
  },
};
//对象2
const eurowings = {
  airline: 'Eurowings',
  iataCode: 'EW',
  bookings: [],
};
//将函数提取出来
const book = lufthansa.book;

//对新函数使用call,函数中有this,首先指定this的指向
book.call(eurowings, 23, 'Sarah Williams');
apply函数
  • 与call类似,但是后面须传入一个数组:
    Function.apply(obj,args)
  • 可被call代替,使用展开运算符使数组展开即可
bind函数

bind使this绑定在对象上:

const bookEW = book.bind(eurowings);
//this在调用时无需指定
bookEW(23, 'Steven Williams');

//可设置预设参数:
const bookEW23 = book.bind(eurowings, 23);//23是预设参数

this会随着上下文的改变而改变,在事件监听器中,this默认指向事件所绑定的元素

  • call与bind的区别:call会调用函数,而bind只是返回新绑定的函数,不会调用
lufthansa.planes = 300;
lufthansa.buyPlane = function () {
  console.log(this);
  this.planes++;
  console.log(this.planes);
};
document
  .querySelector('.buy')
  .addEventListener('click', lufthansa.buyPlane.bind(lufthansa));
部分应用:partial application

不用于绑定this,而是用于设置预设参数

// Partial application
const addTax = (rate, value) => value + value * rate;
console.log(addTax(0.1, 200));

const addVAT = addTax.bind(null, 0.23);
// 相当于 addVAT = value => value + value * 0.23;

console.log(addVAT(100));
///
//使用函数返回函数的方式
const addTaxRate = function (rate) {
  return function (value) {
    return value + value * rate;
  };
};
const addVAT2 = addTaxRate(0.23);
console.log(addVAT2(100));
console.log(addVAT2(23));

立即调用函数表达式:Immediately Invoked Function Expressions (IIFE)

用圆括号将函数括起来,形成一个表达式,再在后面加一个括号,即可调用这个函数。这个函数在执行后即被销毁,其中变量也无法继续生存。(但可以使用闭包访问)

  • 使用目的:数据封装
(function () {
  console.log('This will never run again');
  const isPrivate = 23;
})();
/
(() => console.log('This will ALSO never run again'))();

数据封装的另一个方式:

在一个代码块内使用letconst
在代码块内使用var会建立一个全局变量,因此var定义变量不是很安全,应该少用

闭包 Closures

简单举例
// Closures
const secureBooking = function () {
  let passengerCount = 0;//pC是这个函数中的局部变量

  return function () {
    passengerCount++;//在此处自增
    console.log(`${passengerCount} passengers`);
  };
};

const booker = secureBooking();//此时应返回secureBooking中的function(),其中的pC应失去其上下文(从栈中弹出)
/调用
booker();//输出1
booker();//输出2
booker();//输出3=>证明pC在本来已经不再上下文的调用中实现了自增,这就是闭包
console.dir(booker);//查看属性

闭包就是封闭变量执行上下文的环境中所创建的函数,在上下文消失后,调用函数,封闭变量仍可被访问到`。

  • 解释:就像函数存在一个不离身的背包,这个背包中是其父环境中所定义的变量。
  • 或:像一个人(函数)永远与他的家乡(父环境)存在不断的联系,能回家拿东西。
  • 闭包无法被手动创建,其中的变量也无法被显式修改

booker这一函数可以访问 passengerCount的上下文,因为booker的定义处是secureBooking的上下文范围,尽管secureBooking出栈了,但是它其中的参数被永远保留在了闭包中可被调用到。
在这里插入图片描述
闭包中定义的元素其优先级高于在作用域链(scope chain)定义元素的优先级,即若存在全局变量passengerCount,在调用booker时依然会使用闭包中的passengerCount。

闭包可被修改“指向”
let f;

const g = function () {
  const a = 23;
  f = function () {
    console.log(a * 2);
  };
};

const h = function () {
  const b = 777;
  f = function () {
    console.log(b * 2);
  };
};

g();
f();
console.dir(f);

// Re-assigning f function
h();
f();
console.dir(f);

短路特性的巧用

要执行的只有一句话,此时无需写if条件,直接将条件与执行的程序用&&连起来,这样利用短路,只要条件不符合,则无法执行。

typeof answer === 'number' && answer < this.answers.length && this.answers[answer]++;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值