DIY熙

  • 首页
  • 归档
  • 服务

  • 搜索
TypeSCript 设计模式 前端 算法 electron React Node.js 规范 直播服务器 服务器 小熙js脚本库 油猴脚本 面试

略解《JavaScript语言精粹》- 函数

发表于 2022-02-14 | 0 | 阅读次数 407

前言

  1. 本篇博客因篇幅有限,仅提取出个人认为十分重要且有用的精华,由于本人能力有限,文章可能未能一一提及,仅供各位同学参考学习。

  2. 本文章所有代码已在WebMaker上有代码测试用例。请点击略解《JavaScript语言精粹》代码片段访问配合学习。

函数对象

JavaScript的函数就是对象。每个函数在创建的时候会附加两个隐藏属性:函数的上下文和实现函数行为的代码。

附属资料:理解JavaScript函数是一等公民

函数字面量

函数可以通过函数字面量来创建。

let add = function(a,b) {
  return a + b
}

调用方式

方法调用模式

当一个函数被保存为对象的一个属性时候,我们称他为方法。

let http = {
  url: '',
  get: ()=>{ 
    console.log("get方法")
  }
}

方法可以使用this访问自己所属的对象。

函数调用模式

当一个函数并非一个对象的属性时,那么它就是被当作一个函数来调用的。

let sum = add(3,4)

this指向的是全局对象。这是一个语言设计上的错误,正确的设计应该是当内部函数调用的时候this应该仍然绑定到外部函数的this变量而不是全局对象。

因此我们在ES6之前,大多数都是使用let that = this去访问外部函数的this。

var state = {
    value: 1,
    add: function() {
        let that = this
        const addNum = function (){
            that.value++
        }
        addNum()
    }
}
state.add()
console.log(state.value)

ES6之后,有了箭头函数,现箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者。

const state = {
    value: 1,
    add: function() {
        const addNum = ()=>{
            this.value++
        }
        addNum()
    }
}
state.add()
console.log(state.value)

构造器调用模式

  1. 使用 new 引导构造函数, 创建了一个实例对象
  2. 在创建对象的同时, 将this指向这个刚刚创建的对象
  3. 在构造函数中, 不需要 return , 会默认的 return this
  4. return 非对象全部失效 return 其他对象, 返回 return 后面的对象

不推荐使用这种形式的构造器函数,如果调用构造器函数时没有在前面加上new,回发生错误!

var Status = function (status) {
    this.status = status
}

Status.prototype.get_status = function () {
    return this.status
}

let myStatus = new Status('200')

console.log(myStatus.get_status())

Apply调用模式

函数可以拥有方法,apply方法让我们构建一个参数数组传递给调用函数,它也允许使用this的值,apply接受两个参数,第一个是绑定this的值,第二个是参数数组。

// 修改this指向
let state = {
    name: 'xiaoxi'
}
let fun = function() {
    console.log(this.name)
}
fun.apply(state)
// 传递参数
let state2 = {
    name: 'xiaoxi'
}
let fun2 = function(str,str2) {
    console.log(str + this.name + str2)
}
fun2.apply(state,['我是',',收到请回复'])

除apply之外还有call、bind能够实现改变this对象。

  1. bind 返回的是一个新的函数,你必须调用它才会被执行。
  2. bind和call 的参数是直接放进去的参数用逗号分开。
  3. apply 的所有参数都必须放在一个数组里面传进去。
  4. call 和 apply 都是立即执行。

JavaScript 中 call()、apply()、bind() 的用法

参数

函数被调用的时候会得到一个arguments数组,函数可以通过访问此数组得到所有调用它传递的参数列表,包括没有分配的、未定义的参数。

因为语言的设计错误,arguments并非是一个真正的数组,而是类数组,只有length长度属性,没有数组的方法。

闭包

闭包 我们在bing搜索上会得到一句话:能够读取其他函数内部变量的函数。相信很多同学(包括我)应该马上就会理解并跳过,但是我们其实可以深入了解一下为什么要叫闭包?对谁封闭?什么是包?

作用域可以使内部函数访问到外部函数的变量,闭包则是一种有趣的场景,内部函数的生命周期比外部函数的生命周期长,通过调用一个函数的初始化,该函数返回一个对象字面量,并且在内部定义了一个变量,该变量对对象字面量里面的方法可见,但函数的作用域对其他地方的程序是不可见的。

结论:函数的内部变量对其他地方的程序封闭,包指的是函数返回的对象字面量,且对象字面量中的方法对函数的内部变量可见,总称闭包。

const fun = function() {
    // 函数内部变量
    let value =  1
    // 包我们可以理解为 {} 包起来的,这种实际上叫对象字面量
    const bao = {
        get:function(){
            return value;
        },
        set:function(val){
            value  = val
        }
    }
    return bao
}

const myFun = fun()
console.log(myFun.get())
myFun.set(2)
console.log(myFun.get(2))
// 无法访问
console.log(myFun.value)
// 无法访问
console.log(fun.value)

如果对闭包感兴趣您可以点击闭包更加详细的解释

级联

有些方法没有返回值此时我们可以返回this就可以启用级联,java高级工程师会把这样的操作称为链式调用。

写法1 - 对象字面量

const state = {
    value: 1,
    add: function(val) {
        const addNum = (val)=>{
            this.value = this.value + val
        }
        addNum(val)
        return this
    },
    min: function(val) {
        const addNum = (val)=>{
            this.value = this.value - val
        }
        addNum(val)
        return this
    }
}
state.add(1)
console.log(state.value)
state.add(2).add(3).min(4).add(1).add(3)
console.log(state.value)

写法2 - 闭包

const fun = function() {
    // 函数内部变量
    let value =  1
    // 包我们可以理解为 {} 包起来的,这种实际上叫对象字面量
    const bao = {
        get:function(){
            return value;
        },
        add:function(val){
            value  = value + val
            return this
        },
        min:function(val){
            value  = value - val
            return this
        }
    }
    return bao
}

const myFun = fun()

myFun.add(2).min(3).add(5)

console.log(myFun.get())

还有网上比较容易查到的原型链方式这里就不再列出,可以点击文章顶部的链接进行查看。

柯里化

柯里化允许我们把函数与传递给他的参数相结合,产生一个新的函数。

// 支持多参数传递
function curry(fn) {
    const curried = (...rest) =>{
        console.log(rest)
        if(rest.length < fn.length) {
            return (...rest2) => {
                return curried(...[...rest,...rest2])
            }
        } else {
            fn(...rest)
        }
    }
    return curried
}
function add (a,b,c) {
    console.log(a+b+c)
}
const curryAdd = curry(add)
curryAdd(1)(3)(4)
// 实现一个add方法,使计算结果能够满足如下预期:
// add(1)(2)(3) = 6;
// add(1, 2, 3)(4) = 10;
// add(1)(2)(3)(4)(5) = 15;

const add =  (...rest)=> {
    const args = [...rest]
    const adder =(...rest) =>{
        args.push(...rest)
        return adder
    }
    adder.toString =  ()=> {
        return args.reduce(function (a, b) {
            return a + b
        })
    }
    return adder
}

console.log(add(1)(2)(3))

记忆

函数可以将先前的操作结果记录到某个对象里面,从而避免无谓的重复计算。通常也可以叫做缓存。

function fibnan(n) {
        const memo = [0, 1]; // 缓存计算结果
        const fib = (n) => {
          if (memo[n] != null) { // 如果已经被计算就返回他
            return memo[n];
          }
          return (memo[n] = fib(n - 1, memo) + fib(n - 2, memo));  // 否则将他计算加入缓存
        };
        return fib;
      }

总结

通过上列的学习,我们了解了函数的各大调用方法以及函数的一些特性,包括我们对闭包的理解和使用更加透彻,同时也学会了一些函数的高级用法。

  1. 三种调用方式:方法、函数、构造器
  2. 四种高级函数使用:级联、柯里化、记忆、闭包
  • 本文作者: 大熙哥
  • 本文链接: https://blog.diyxi.top/archives/略解javascript语言精粹-函数
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
略解《JavaScript语言精粹》- 原型
略解《JavaScript语言精粹》- 继承
  • 文章目录
  • 站点概览
大熙哥

大熙哥

38 日志
11 分类
13 标签
RSS
Github
Creative Commons
Links
  • Ziki
  • 咸鱼的窝
  • Farmer的自习室
  • 一个肥肥的自习室
  • lafish
  • 小呆呆的生活
  • hekvn
© 2023 大熙哥
由 Halo 强力驱动
|
主题 - NexT.Mist v5.1.4
粤ICP备20011435号-1
0%