huangyingzheng / daily_progress

每天进步一点点
1 stars 0 forks source link

深入Js #1

Open huangyingzheng opened 4 years ago

huangyingzheng commented 4 years ago

第一次记录:

伢羽关于(业务类前端的困局)技术和业务之间的联系,自己总结为以下几点:

  1. 了解业务而不只是需求,从全局的角度去规划技术。我做这个功能是否有价值,功能上线之后对核心指标的提升有多少。
  2. 这个需求是否有轮子可用,没有轮子,我造的轮子是否能解决通用的需求。
  3. 技术的深度不仅表现在某项技术的深挖,跟体现在体系化和系统化。体系化思维是认识事物的一种方式,在面对问题的时候,能够针对复杂的问题,列出关键的要素和解决方法,将散乱无序的问题,变得逻辑清晰,有章可循。全链路,向前向后的技术栈。
  4. 技术敏感,是关注业界新技术,如果工作中遇到可以落地的项目,可以先写写demo
huangyingzheng commented 4 years ago

setTimeout 和 setTimeInterval

setTimeout 和 setTimeInterval 都是延迟执行,但是本质是不同的。或者说是延迟一点时间加入任务队列,但是执行时间不一定。

而setTimeInterval 如果发现有相同的任务同样任务队列,任务就会丢失,而且如果执行时间大于间隔时间,两个interval执行时间就没有间隔了。

可以这样

let timer = setTimeout( function() {
                     timer = setTimeout( function() {})
                  },10)

嵌套执行,可以保证第一个执行完第二个才会加入任务队列,也一定会有至少10ms gap

huangyingzheng commented 4 years ago

bind 和 apply 实现

bind 用法,改变函数this指向

function bar() {
    return this.value
}
const foo = {
    value: 10
}
bar.call(foo)
10

模拟开始

huangyingzheng commented 4 years ago

第二次记录:

关于变量对象相关描述

  1. 关于静态作用域,js是静态作用域,所以变量是由定义的是否确定的
  2. 一个函数在被执行的是否会开启执行上下文,和变量作用域不是同一个东西。 举个例子
    function fun3() {
    console.log('fun3')
    }
    function fun2() {
    fun3();
    }
    function fun1() {
    fun2();
    }
    fun1();
Const gs= []
Gs.push( fun1, functionContext)
Gs.push(fun2, fc)
Gs.push(fun3,fc)
Gs.pop()
Gs.pop()
Gs.pop()
//进入globalContext
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f();
}
checkscope();

ECStack.push(<checkscope> functionContext);
ECStack.push(<f> functionContext);
ECStack.pop();
ECStack.pop();

只有在执行的是否才会开启执行上下文

  1. 开启执行上下文还不够,深入的说上下文是由三个部分组成的。- 作用域链 - 变量对象 -this
  2. 全局变量对象是预定义对象,可以理解为就是windows
  3. 简单说说变量对象,主要分成两个部分。进入执行上下文,代码执行。
  4. 进入执行上下文有三个优先级,

变量对象会包括:

  1. 函数的所有形参 (如果是函数上下文)
    • 由名称和对应值组成的一个变量对象的属性被创建
    • 没有实参,属性值设为 undefined
  2. 函数声明
    • 由名称和对应值(函数对象(function-object))组成一个变量对象的属性被创建
    • 如果变量对象已经存在相同名称的属性,则完全替换这个属性
  3. 变量声明
    • 由名称和对应值(undefined)组成一个变量对象的属性被创建;
    • 如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性 举个例子
      console.log(a)// fn
      function a() {
      }
      var a = 10
      console.log(a)// 10
      • 第一个console.log 执行的时候,形参a进入,是undefined跳过,函数变量提示,a=fn,普通变量提升,a已经存在,不改变a的值。console.log执行。打印a=fn。继续执行,function a 被定义但是没被调用,入栈,一会空间会被回收,姑且先这么理解。a赋值执行 第二个console.log执行,进入执行上下文,形参a=10进入,后面步骤省略。打印a=10 PS. 三种参数都在执行函数外面的情况,函数初始化符合上述顺序。
huangyingzheng commented 4 years ago

第三次记录:

闭包和上下文环境 执行

var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}
var foo = checkscope();
foo();

进入全局代码,创建全局执行上下文,全局执行上下文压入执行上下文栈 全局执行上下文初始化 执行 checkscope 函数,创建 checkscope 函数执行上下文,checkscope 执行上下文被压入执行上下文栈 checkscope 执行上下文初始化,创建变量对象、作用域链、this等 checkscope 函数执行完毕,checkscope 执行上下文从执行上下文栈中弹出 执行 f 函数,创建 f 函数执行上下文,f 执行上下文被压入执行上下文栈 f 执行上下文初始化,创建变量对象、作用域链、this等 f 函数执行完毕,f 函数上下文从执行上下文栈中弹出

function f被创建的时候f.[[scope]]中就已经保存了 globalContext.VOcheckscope.AO所以 foo执行的时候能访问到 var scope = "local scope"

var data = [];
for (var i = 0; i < 3; i++) {
  data[i] = function () {
    console.log(i);
  };
}
data[0]();
data[1]();
data[2]();

这里有几个点需要注意,第一个是data[i] 和 console.log(i) 两个i访问的地址是不一样的,第一个i我理解为 simple assignment ,使用的是getValue返回的是具体的值,所以i马上被确定下来了。第二个i是在执行时从作用域链上面找的。

var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
   scope = '1'
    return f;
}
var foo = checkscope();
foo(); // ‘1’
// 上面这个例子说明的就是,说明执行的时候后面传入的值会替换前面的值。

在data[0]() 执行的时候之前,globalContest.VO ={ data: [], i:3},而data[0]创建的执行上下文 =》

{ AO:{
  length: 0 },
Scope:[ AO, globalContext.VO]}

可以看到是没有i的,所以要从gloableContext.Vo中拿,这里的i已经被确定为3了,那么data0,1,2执行的结果都是3. 解决的方法有两个,第一个是将var改成let 第二个是用闭包在作用域链上再加一层,一个立即执行的匿名函数 var data = [];

for (var i = 0; i < 3; i++) {
  data[i] = (function(i){
    return function(){
        console.log(i)
    }
})(i)
}
data[0]();
data[1]();
data[2]();

Data0 的执行上下文变成:[ AO,匿名函数.AO globalContext.VO], 因为是立即执行的,i传入是被保留。

huangyingzheng commented 4 years ago

Mockjs 的使用

正在学习使用 Taro,其中需要一些数据网上公开的api无法提供,所以使用mockjs模拟一些数据,然后拦截axios请求。 简单讲一下步骤

const data = { 'GET /api/book/list': (req, res) => { const { query } = req; const { current, pageSize, dataSource } = Query(query, BookData.data.lists); res.status('200').json({ data: { lists: dataSource.slice((current - 1) pageSize, current pageSize), pageInfo: { current: Number(current), pageSize: Number(pageSize), total: dataSource.length, maxCurrent: dataSource.length % pageSize >= 0 ? Math.ceil(dataSource.length / pageSize) : dataSource.data.length / pageSize } }, statusCode: '200' }) } } module.export = data


- Mock.Random 制作数据,具体可以看官网,或者【https://juejin.im/post/6844903860343963655#heading-12】,总结的很好。
```javascript

const Random=Mock.Random;
{
    'Boolean': Random.boolean, // 随机生成布尔类型
    'Natural': Random.natural(1, 100), // 随机生成1到100之间自然数
    'Integer': Random.integer(1, 100), // 生成1到100之间的整数
    'Float': Random.float(0, 100, 0, 5), // 生成0到100之间的浮点数,小数点后尾数为0到5位
    'Character': Random.character(), // 生成随机字符串,可加参数定义规则
    'String': Random.string(2, 10), // 生成2到10个字符之间的字符串
    'Range': Random.range(0, 10, 2), // 生成一个数组,数组元素从0开始到10结束,间隔为2
    'Date': Random.date(), // 生成一个随机日期,可加参数定义日期格式,默认yyyy-mm-dd
    'Image1': Random.image(Random.size, '#02adea', '#fff','png','Hello'), // Random.size表示将从size数据中任选一个数据,生成Random.size指定大小的,背景为'#02adea'的,前景色为'#fff'的,格式为'png'的,内容为'Hello'的图片。
    'Image2':Random.dataImage('200x100', 'Hello Mock.js!'),//只设置大小
    'Color': Random.color(), // 生成一个颜色随机值
    'Paragraph':Random.paragraph(2, 5), //生成2至5个句子的文本
    'Name': Random.name(), // 生成姓名
    'Url': Random.url(), // 生成url地址
    'Address': Random.province() // 生成地址
}

let template = {
    'Boolean': Random.boolean, // 可以生成基本数据类型
    'Natural': Random.natural(1, 100), // 生成1到100之间自然数
    'Integer': Random.integer(1, 100), // 生成1到100之间的整数
    'Float': Random.float(0, 100, 0, 5), // 生成0到100之间的浮点数,小数点后尾数为0到5位
    'Character': Random.character(), // 生成随机字符,可加参数定义规则
    'String': Random.string(2, 10), // 生成2到10个字符之间的字符串
    'Range': Random.range(0, 10, 6), // 生成一个随机数组
    'Date': Random.date(), // 生成一个随机日期,可加参数定义日期格式
    'Image': Random.image(Random.size, '#02adea', '#fff','png','Hello'),
    'Color': Random.color(), // 生成一个颜色随机值
    'Paragraph':Random.paragraph(2, 5), //生成2至5个句子的文本
    'Name': Random.name(), // 生成姓名
    'Url': Random.url(), // 生成web地址
    'Address': Random.province() // 生成地址
  }
huangyingzheng commented 4 years ago

尾调用和柯里化

function curryUrl(protocol) { return function(hostname, pathname){ return function(pathname){ return ${protocol}${hostname}${pathname}; } } }

const urlHttps = curryUrl('https://'); const urlHosts = urlHttps('www.juejin.im');

const url1 = urlHosts('/user/yan'); const url2 = urlHosts( '/user/tong'); const url3 = urlHosts( '/user/shao');

function add() { let args = [...arguments]; // 第一次的arguments console.log(arguments); let num = function () { args.push(...arguments); // 之后每次的arguments return num; // 每次的结果指向自己,保证多次调用保证后面跟着多个括号可以执行 };

num.toString = function () { return args.reduce(function (pre, cur) { return pre + cur; }); }; return num; } console.log(add(1, 2, 3)(4)(7).toString());