【第三章】闭包和高阶函数

闭包作用

封装变量

把不需要暴露在全局的变量封装成 “私有变量”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//计算乘积一般方法
var mult = function(){
var a = 1
for(var i=0;l=arguments.length;i<l;i++){
a *= arguments[i]
}
return a
}
/*
对于相同的参数来说,每次进行计算是一种浪费
所以可以加入缓存机制来提高这个函数的性能
*/
var cache = {}
var mult = function () {
var args = Array.prototype.join.call(arguments, ',')
//args = '1,2,3' 类数组使用join方法
if (cache[args]) {
return cache[args]+'[]'
}
var a = 1
var l = arguments.length;
for (var i = 0; i < l; i++) {
a *= arguments[i]
}
return cache[args] = a
// cache = { '1,2,3': 6 ,...}
}
console.log(mult(1,2,3)) // 6
console.log(mult(1,2,3)) // 6[] 不进行再次循环 直接取cache内存的值
console.log(mult(1,2,5)) // 10
console.log(cache) // { '1,2,3': 6 ,'1,2,5': 10}
/*
虽然 cache 只在mult函数中使用
但是 被放在了全局变量中 不能被释放
实现在mult中
通过闭包的方式实现 */
var mult = (function(){
var cache = {}
return function(){
var args = Array.prototype.join.call(arguments, ',')
if (cache[args]) {
return cache[args]+'[]'
}
var a = 1
var l = arguments.length;
for (var i = 0; i < l; i++) {
a *= arguments[i]
}
return cache[args] = a
}
})()
//提炼函数
var mult = (function(){
var cache = {}
var calculate = function(){
var a = 1
for(var i=0,l=arguments.length;i<l;i++){
a *= arguments[i]
}
return a
}

return function(){
var args = Array.prototype.join.call(arguments,',')
if( args in cache ){
return cache[args]
}
return cache[args] = calculate.apply(null,arguments)
//用apply主要是因为arguments是一个数组 更方便传参 不需要处理类型
//es6也可以直接用 calculate(...arguments)
}
})()

延长局部变量的寿命

变量一直处于被引用状态 所以不会释放缓存?

高阶函数

需要满足的条件

  1. 函数可以作为参数被传递
  2. 函数可以作为返回值输出

函数作为参数传递

  1. 回调函数

    回调函数的应用不仅只在异步请求中,当一个函数不适合执行一些请求时,我们也可以把这些请求封装成一个函数,并把它作为参数传递给另外一个函数,“委托”给另外一个函数来执行。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var appendDiv = function (callback) {
    for (var i = 0; i < 100; i++) {
    var div = document.createElement('div');
    div.innerHTML = i;
    document.body.appendChild(div);
    if (typeof callback === 'function') {
    callback(div);
    }
    }
    };
    appendDiv(function (node) {
    node.style.display = 'none'
    })
    1. Array.prototype.sort
      Array.prototype.sort 接受一个函数当作参数,这个函数里面封装了数组元素的排序规则。从Array.prototype.sort 的使用可以看到,我们的目的是对数组进行排序,这是不变的部分;而使用什么规则去排序,则是可变的部分。把可变的部分封装在函数参数里,动态传入Array.prototype.sort,使 Array.prototype.sort 方法成为了一个非常灵活的方法,代码如下
      1
      2
      3
      4
      5
      6
      7
      8
      9
      //从小到大排列
      [ 1, 4, 3 ].sort( function( a, b ){
      return a - b;
      }) // [1,3,4]

      //从大到小排序
      [ 1, 4, 3 ].sort( function( a, b ){
      return b - a;
      }) // [4,3,1]

    函数作为返回值输出

  2. 判断数据的类型

    通过 Object.prototype.toString.call(obj) 判断数据类型(最好的方法)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var isType = function(type){
    return function(obj){
    return Object.prototype.toString.call(obj) == '[object '+type+']'
    }
    }

    isType('String')('a') //true
    isType('Array')([1,2]]) //true

【第二章】this、call和apply

this

指向一个对象。具体指向哪一个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。

执行上下文:

JavaScript引擎在JavaScript代码正式执行之前会先创建执行环境,在执行环境中作预处理工作

  • 工作内容:
    1.创建空对象
    2.该空对象用于收集变量、函数,函数的参数
    3.创建作用域链
    4.确定this的指向

  • 执行上下文栈:
    1.在全局代码执行之前,JavaScript引擎就会创建一个栈来存储管理所有的执行上下文对象
    2.在全局执行上下文确定后,将其添加到栈中(压栈)
    3.在函数执行上下文创建后,将其添加到栈中(压栈)
    4.在当前函数执行完后,将栈顶的对象移除(出栈)
    5.当所有的代码执行完后,栈中只剩下window

  • this指向
    1.作为对象的方法调用 指向对象
    2.作为普通函数调用 指向全局对象(window)
    3.构造函数调用 指向实例对象
    4.Function.prototype.call或Function.prototype.apply调用 指向第一个参数对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    //1.作为对象的方法调用
    var obj = {
    a : 1,
    getA : function(){
    console.log( this === obj ) //true
    console.log( this.a ) // 1
    }
    }

    //2.作为普通函数调用
    window.name = 'globalName'
    var obj = {
    name : 'localName',
    getName : function(){
    console.log(this.name)
    }
    }
    var getName = obj.getName
    getName() //globalName
    obj.getName() //localName

    //3.构造函数调用
    var Obj = function(){
    this.name = 'doreen'
    this.age = 11
    }
    var obj = new Obj()
    obj.name = 'sherry'
    console.log(obj) //sherry

    //4.Function.prototype.call或Function.prototype.apply调用
    var obj = {
    name: 'doreen',
    getName: function(){
    return this.name
    }
    }

    var obj2 = {
    name: 'sherry'
    }
    console.log(obj.getName()) //doreen
    console.log(obj.getName.call(obj2)) //sherry

call和apply

  • call和apply的区别

    call多个参数 .call(对象,…)
    apply是两个参数 .apply(对象,数组)

1
2
3
4
5
6
var func = function(a,b,c){
console.log([a,b,c])
}

func.call(null,1,2,3) //[1,2,3]
func.apply(null,[1,2,3]) //[1,2,3]
  • call和apply的用途

    1. 改变this指向

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      var obj1 = {
      name: 'doreen'
      }
      var obj2 = {
      name: 'sherry'
      }
      var window.name = 'winow'
      var getName = function(){
      console.log(this.name)
      }

      getName() //window
      getName.call(obj1) //doreen
      getName.call(obj2) //sherry
    2. Function.prototype.bind

      1
      2
      3
      4
      5
      6
      7
      // 实现方法
      Function.prototype.bind = function(context){
      var obj = this
      return function(){
      return obj.apply(context,arguments)
      }
      }

      延迟执行,call和apply是改变this之后直接执行函数,而bind是返回一个函数 需要在调用才能执行

    3. 借用其他对象的方法

    • 场景一 “ 借用构造函数 ” 实现继承

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      var A = function(name){
      this.name = name
      }
      var B = function(){
      A.apply(this,arguments)
      }
      B.prototype.getName = function(){
      console.log(this.name)
      }
      var b = new B('doreen')
      b.getName() //doreen
    • 场景二 处理 “ 类数组对象 ”

      函数的参数列表 arguments 是一个类数组对象,虽然它也有“下标”,但它并非真正的数组,所以也不能像数组一样,进行排序操作或者往集合里添加一个新的元素。这种情况下,我们常常会借用 Array.prototype 对象上的方法。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      (function(){
      Array.prototype.push.call(arguments,3)
      console.log(arguments) //[1,2,3]
      })(1,2)

      /*数组的特性
      1.对象本身要可以存取属性
      2.对象的length属性可读写
      */

【第一章】面向对象的JavaScript

动态类型语言和鸭子类型

编程语言按照数据类型 可以分为 静态类型语言和动态类型语言

        静态类型语言:声明时确定变量类型
            优:
            1. 在编译时就能发现类型不匹配的错误,提前避免程序在运行期间有可能发生的一些错误。[提高可靠性]
            2. 如果在程序中明确地规定了数据类型,编译器还可以针对这些信息对程序进行一些优化工作,提高程序执行速度。
            缺:
            1. 具有强迫性 不够灵活
            2. 类型的声明会增加代码量 分散业务逻辑这个重点
        动态类型语言:赋值时确定变量类型(JavaScript)
            优:
            1. 简化代码量 侧重点更能集中在业务逻辑上面
            2. 代码灵活性增强
            缺:
            1. 无法保证变量的类型 [可靠性低]

动态语言和鸭子类型的关系

鸭子类型概念:如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭子(关注的是has a xx 而不是 is a xx)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
我的理解:
动态语言无法保证变量的类型
那么只要他所赋值的变量有某种类型的特性 那么它就是某一类型
*/
//书中的例子
var duck = { //鸭子
voice: function(){
console.log('嘎嘎嘎')
}
}
var chicken = { //鸡
voice: function(){
console.log('嘎嘎嘎')
}
}

var Ducks = [] //鸭子类型
var joinDucks = function(animal){
if( animal && typeof animal.voice === 'function' ){
Ducks.push(animal)
console.log('恭喜加入鸭子类型')
}
}

joinDucks(duck) //恭喜加入鸭子类型
joinDucks(chicken) //恭喜加入鸭子类型

多态

对象继承类的属性/方法 但是可以对属性/方法进行针对性的改变
就是构造函数根据传入的变量不同,对同一方法,有不同的返回结果

1
2
3
4
5
6
7
8
9
var Animal = function( sound ){
this.sound = function(){
console.log(sound)
}
}
var duck = new Animal('嘎嘎嘎')
var chicken = new Animal('咯咯咯')
duck.sound() //嘎嘎嘎
chicken.sound() //咯咯咯

封装

封装的目的就是将信息隐藏 不在乎过程 只要能使用

异步请求-数据传递

解决了一个困扰了一天的bug

基本信息描述

1
2
3
4
5
就是一个创建主题的界面  
在没有进行操作的时候 第一次进入需要弹框进行填写 数据库用户名和密码等操作
填写完之后会返回一个数据库表名的数组
弹框是一个子组件 通过获取信息有没有存储在本地来判断是否是第一次操作


我的基本思路

  
1.当弹框信息填写完毕 提交之后 会请求接口获取 数据库表数组
2.请求成功之后 将数组信息存放到 sessionStorage 里面
3.通过 $emit在点击确定按钮的时候 把信息发送给父组件 关闭弹框
4.然后父组件就可以直接获取到信息并且渲染出来

bug描述

问题就在于 子组件是基于父组件而存在的  
父组件是渲染完成之后 才会显示的子组件
在点击确定按钮的时候 发送请求是异步的
所以会先执行$emit操作和弹框关闭操作
所以传递过去的值 是空的!!!

/**
在父组件 可以正常打印 但是就是不能渲染在页面上
一开始 我以为是因为传的是对象 不能渲染页面用 $set 但没有任何作用
然后我就觉得是父组件获取数据太快 用定时器的方法来异步获取数据 也不行

后面以为是传值的原因 用了vuex,refs啥啥啥的 都没有成功

后面在弹框组件内 保存按钮的函数下打印数据 发现打印的值为空!这个时候才定位到错误源
*/

解决

原因我猜想是请求接口是异步的,所以用$emit传递的时候 数据还没有被赋值
所以用setTimeout延迟操作了200ms
同样弹框状态也要和$emit一样延迟
然后父组件就可以正常获取到数据了

vue-element-admin中vuex多模块问题

store的配置文件

src/store/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
Vue.use(Vuex)

// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', true, /\.js$/)

// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
// 大概理解下 不用去一个一个模块的导入 他已经写好了方法 来遍历modules文件下的各个子模块
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
return modules
}, {})

const store = new Vuex.Store({
modules, //引入全部子模块
getters
})

export default store

modules文件中存放的是各个小模块,分割store,每个模块内部都可以有自己的state、mutation、action、getter

src/store/modules/subject.js

1
2
3
4
5
6
7
8
9
10
11
12
13
const state = {
DBNames: []
}
const mutations = {
changedb(state, db) {
state.DBNames = db
}
}
export default {
namespaced: true, //独立的命名空间 模块内部的action、mutation、getter被注册在独立的命名空间内 false 则注册在全局
state,
mutations
}

使用方式:
①直接使用

在需要的 .vue 文件的<script>内的合适位置

1
2
3
4
5
6
//this.$store.state.模块名.变量名
this.$store.state.subject.DBNames

//this.$store.commit( '模块名/函数名' , 参数 )
this.$store.commit('subject/changedb','lll')


②配合辅助函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { mapState,mapMutations } from "vuex"

...

computed: {
...mapState({
name: state => state.subject.DBNames
})

...mapState('subject',{
name: state => state.DBNames
})
},

//使用 this.name

methods: {
...mapMutations({
dbChange: 'subject/changedb' // 改变的函数名:' 模块名/函数名 '
}),

...mapMutations('subject',{
dbChange: 'changedb' // 改变的函数名:' 模块名/函数名 '
}),
}
//使用 this.dbChange(参数)

③配合模块辅助函数使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { createNamespacedHelpers } from "vuex"
const { mapState,mapMutations } = createNamespacedHelpers('subject')

...
//调用方法和②一样
computed: {
...mapState({
name: state => state.DBNames
})
},
methods: {
...mapMutations({
dbChange: 'changedb'
}),
}

秋招记录

11.28
三方的流程弄完寄去公司 我的秋招正式结束
因为是明年七月入职 为了给自己留条后路
所以我又马不停蹄的找了份实习
12.2
入职 现在是我实习的第二个星期


秋招那几个月对我来说真的十分痛苦 度日如年
以前说考研是孤军奋战 现在看来找工作才是
我们一个班30个人 考研考公的占80%
我去交就业协议的时候 我们系加上我就三个人
我连找个一起去宣讲会的人都没有
周末对着电脑、手机不知道干嘛
想了想还是记录、整理一下秋招这几个月的心路历程
从大概大二的时候有想从事前端方面的工作的想法
大三两个学期 基本都是在学相关的内容
虽然说学习时间很充裕
可能我自己也不是这块料 在加上自学要学好本来就比较难
我现在掌握的 了解的还是很局限
升大四的那个暑假在家一个多月基本都在准备工作相关的东西
忙着补习算法、数据结构、网络相关的内容,刷题、看视频、看面经、查公司、投简历
虽然没有在学校的学习效率高 但也是靠着自制力坚持下来了
貌似在八月底有了第一个大公司的面试(shopee)
这是我第一次感受到了严重的打击
内心在问自己 “我是怎么敢去报大厂的?我有什么资格和那么多优秀的人去竞争?我怎么这么垃圾?……”
从那之后我基本没有怎么投过大公司后来收到的大厂笔试或者面试几乎都是在这之前投递的简历
但是坏情绪也没有持续很久 因为秋招才刚刚开始 觉得还有机会
九月份是面试最多的时间有过几家公司的面试
因为基本都在主城面试 所以基本都是来来回回的坐车、坐车,是真的身心俱疲
每次等待结果的过程都很焦虑
通过了会开心的睡不着,没通过会伤心的睡不着
最后都没有一个好的结果

到了十月的时候 整个人几乎每天都是崩溃的状态
那应该是我有史以来过的最丧的国庆
什么都不想干,也没有什么事可以干
国庆过后仿佛秋招已经宣告结束
什么消息都没有 翻遍了各种求职的软件 也找不到能投递的公司
大公司进不去 小公司不要我

说来也巧 每次机会的到来和失去基本都是在同一时间段
十月中下旬的时候 有两家公司几乎同时找的我
一家技术面 面了我一个小时 两轮hr面 最后一面终面总监告诉我第二天hr要和我谈薪资 我以为稳了
刚好第二天第二家公司二面
第二天大老远跑去成都面完 就知道自己凉了
一直激动的等着第一家公司hr来和我谈薪资
然而一天、两天……并没有结果
大概意识到我是因为性格原因被涮了
这两家公司是我在面试里体验最不好的
一家给你开空头支票吊着你,一家cto十分自大看不起人
行吧 我惹不起 也不适合与这种领导沟通

后面一段时间就基本放弃了 准备考完试就去长沙的那家小公司上班
但是人生就是起起落落
11月3号早上6:30出发去本部参加了双选会
投了八份简历 只有一家回复
而就是那家技术面的前一天又有两家公司找了我 并且安排了面试
又很不巧的时间撞上了
那一天我面了三家公司( 常德、深圳、成都 )
深圳的那次面试真的又让我意识到自己的浅薄
面试官之前是腾讯的,算法转的后端转前端
很不一样的面试体验问的问题我的题库基本没有涉及
基本都是从一个更深层次的维度去问你问题的
真的让我找回了shopee面试的那种压迫感
感觉度秒如年
想快点结束但是没想到过了
并且约了第二天二面
然而就在同一天成都的hr过来和我谈薪资了
真的挺开心的 终于有一份像样的offer
既激动又紧张

直到现在我还是没有安全感
明年体检通过后才能入职
如果我能成功入职当然是值得开心的但是没有呢?那我怎么办?

没有工作经验
没有了应届毕业生这个条件
没有了学校的资源
……

我不知道如果真的走到那天
我还能不能有那么强大的内心承受这么大的压力
我真的不想在重来一次了
我真的很累了

  • Copyrights © 2019-2023 John Doe
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信