2020/7/26前端学习日记

JavaScript

操作文档API
文档对象模型(DOM)
选择DOM元素: document.querySelector(‘a’)
(较老的浏览器中会使用document.getElementById()等方法)
创建新结点:document.createElement(‘p’)
(创建文本节点 :document.createTextNode())
插入DOM中:document.appendChild()
(insertBefore() 方法:可在已有的子节点前插入一个新的子节点。语法 :insertBefore(newchild,refchild))
删除结点:removeChild()
(删除自身结点:Node.parentNode.removeChild(Node))
操作样式
Node.style.color = ‘white’
window API
window.innerWidth 和 window.innerHeight分别可以获取窗口宽高。

js中var const let的区别
在这里插入图片描述
ES6中一般用let来代替var,用const来定义常量。

XMLHttpRequest(XHR)
步骤:1.创建一个新的请求对象:let request = new XMLHttpRequest();
2.使用open()方法指定HTTP请求的方法和url:request.open(‘GET’, url);
3.设置期待的响应类型(默认为Text):request.responseType = ‘text’;
4.send()函数发送请求:request.send();

Fetch
fetch(url)相当于request.open()
fetch返回一个promise使用then()函数进行处理,相当于XHR中的onload()事件处理程序。
使用.text()方法是将响应作为原始文本返回,相当于responseType = ‘Text’
在这里插入图片描述
2020/7/27补充:fetch发送post请求为什么总发送两次,第一次状态码是204,第二次才成功?
因为使用fetch请求时,导致fetch第一次发送了一个options请求,询问服务器是否支持,如果支持才在第二次中发送真正的请求。
关于promise
fetch()会返回一个解析HTTP响应的promise,在.then()中定义的任何函数会被自动给予一个响应作为参数,意思是无论参数名称可以是任何名字,实体都是返回的响应。

XHR和Fetch如何选择
XHR面世较久,比较成熟,老式的浏览器都支持,Fetch和promise都是比较新的产物,不过大部分浏览器都已经支持。

客户端存储API
Web Storage API

  • localStorage
    为每一个给定的源(相同域名的URL)维持一个独立的存储区域。即使关闭浏览器数据依然存在,除非手动删除。
  • sessionStorage
    功能与localstorage相同,但是生命周期不同。当关闭浏览器后自动删除,只要浏览器处于打开状态,页面刷新和恢复该数据依然存在。

检测localStorage是否可用函数

function storageAvailable(type) {
    var storage;
    try {
        storage = window[type];
        var x = '__storage_test__';
        storage.setItem(x, x);
        storage.removeItem(x);
        return true;
    }
    catch(e) {
        return e instanceof DOMException && (
            // everything except Firefox
            e.code === 22 ||
            // Firefox
            e.code === 1014 ||
            // test name field too, because code might not be present
            // everything except Firefox
            e.name === 'QuotaExceededError' ||
            // Firefox
            e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
            // acknowledge QuotaExceededError only if there's something already stored
            (storage && storage.length !== 0);
    }
}

设置值:localStorage.setItem();
获取值:localStorage.getItem();
删除记录:localStorage.removeItem();
localStorage.clear(); 清空域名对应的整个存储对象

额外知识:事件监听器在对象发生改变时会触发,即创建/更新/删除数据时,重复设置相同的键值不会触发。

IndexedDB API

IndexedDB是一个事务型数据库系统,类似于基于SQL的RDBMS。用于储存大量的结构化数据,而localStorage用于存储少量数据。

Web Worker API
使用Web Workers可以在后台独立运行一个脚本操作,从而使主线程不会因此阻塞。
使用构造函数(如Woker()创建一个worker对象,构造函数接受一个JavaScript文件URL。可以在worker线程中运行任意代码,除了直接操纵DOM元素以及一些window对象中的某些方法和属性。
主线程和worker之间使用postMessage()方法来发送消息。并通过onmessage这个event handler来接受消息。

第三方API
在这里插入图片描述
JavaScript语法
在函数中有一个名为arguments的内部对象,包括了被传入的所有参数:

function add() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        sum += arguments[i];
    }
    return sum;
}

add(2, 3, 4, 5); // 14

也可以这样表示:

function avg(...args) {
  var sum = 0;
  for (let value of args) {
    sum += value;
  }
  return sum / args.length;
}

avg(2, 3, 4, 5); // 3.5

需要注意的是,无论“剩余参数操作符”被放置到函数声明的哪里,它都会把除了自己之前的所有参数存储起来。比如函数:function avg(firstValue, …args) 会把传入函数的第一个值存入 firstValue,其他的参数存入 args。

闭包!!(划重点)

现在先看这段代码

function makeAdder(a) {
  return function(b) {
    return a + b;
  }
}
var add5 = makeAdder(5);
var add20 = makeAdder(20);
add5(6); // ?
add20(7); // ?

一开始看的我一脸懵逼,完全无法理解add5和add20明明是两个函数的引用为什么还能传入参数?
看官方的解释:
当调用 makeAdder 时,解释器创建了一个作用域对象,它带有一个属性:a,这个属性被当作参数传入 makeAdder 函数。然后 makeAdder 返回一个新创建的函数(暂记为 adder)。通常,JavaScript 的垃圾回收器会在这时回收 makeAdder 创建的作用域对象(暂记为 b),但是,makeAdder 的返回值,新函数 adder,拥有一个指向作用域对象 b 的引用。最终,作用域对象 b 不会被垃圾回收器回收,直到没有任何引用指向新函数 adder。
其实已经很明白了,makeAdder返回值为一个函数,add5和add20分别指向各自函数的引用,所以属性a仍然被引用所以不会被回收。
闭包概念:一个闭包,就是 一个函数 与其 被创建时所带有的作用域对象 的组合。(我的理解就是makeAdder就是一个闭包)

看到一个更详细的解释,上链接:
https://www.cnblogs.com/frankfang/archive/2011/08/03/2125663.html
重要信息:

  1. 当你return的是内部function时,就是一个闭包。内部function会close-over外部function的变量直到内部function结束。
  2. 如果一个函数访问了它的外部变量,那么它就是一个闭包。从技术上来讲,在JS中,每个function都是闭包,因为它总是能访问在它外部定义的数据。
  3. 闭包经常用于创建含有隐藏数据的函数(但并不总是这样)
    很受用的例子:
var db = (function() {
  // 创建一个隐藏的object, 这个object持有一些数据
  // 从外部是不能访问这个object的
  var data = {};
  // 创建一个函数, 这个函数提供一些访问data的数据的方法
  return function(key, val) {
    if (val === undefined) { return data[key] } // get
    else { return data[key] = val } // set
  }
  // 我们可以调用这个匿名方法
  // 返回这个内部函数,它是一个闭包
})();
db('x');    // 返回 undefined
db('x', 1); // 设置data['x']为1
db('x');    // 返回 1
// 我们不可能访问data这个object本身
// 但是我们可以设置它的成员

闭包这个概念真的很难理解,看了这么多解释也是稀里糊涂。
https://stackoverflow.com/questions/111102/how-do-javascript-closures-work
MDN和上面这位大神都推荐了stackoverflow的这篇文章,有机会一定要去看看。

算法题

用两个栈实现队列
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

示例 1:

输入:
[“CQueue”,“appendTail”,“deleteHead”,“deleteHead”]
[[],[3],[],[]]
输出:[null,null,3,-1]
示例 2:

输入:
[“CQueue”,“deleteHead”,“appendTail”,“appendTail”,“deleteHead”,“deleteHead”]
[[],[],[5],[2],[],[]]
输出:[null,-1,null,null,5,2]

class CQueue {
    Stack<Integer> stack1 = new Stack<Integer>();//存放临时数据
        Stack<Integer> stack2 = new Stack<Integer>();//正向存放数据


    public CQueue() {
        
    }
    
    public void appendTail(int value) {
        while(!stack2.empty()){
            stack1.push(stack2.pop());
        }
        stack2.push(value);
        while(!stack1.empty()){
            stack2.push(stack1.pop());
        }
    }
    
    public int deleteHead() {
        if(stack2.empty()){
            return -1;
        }else{
            return stack2.pop();
        }
    }
}

我的思路是一个栈只有在存入新数据时用于存放临时变量,另一个栈用于存放队列中的数据。这样删除头元素只需要pop存放数据的栈的栈顶元素即可。
官方题解有一个回答是一个栈用于插入操作,一个栈用于删除操作,大致思路差不多。题目比较简单。

斐波那契数列
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:

F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

class Solution {
    public int fib(int n) {
        if(n == 0) return 0;
        if(n == 1) return 1;
        int[] dp = new int[n+1];
        //int dp1 = 0;
        //int dp2 = 1;
        int res = 0;
        for(int i = 2; i < n+1 ; i++){
            dp[i] = dp[i-1] + dp[i-2];
            dp[i] %= 1000000007;
        }
        return dp[i];
    }
}

本题虽然是简单难度,但是第一想法是用递归做,但是当n>=45时递归的方法就会超时(也是被这题的标签误导了),然后一看大神的题解是用动态规划做,这样时间和空间复杂度都是O(n)。还有空间复杂度更小的做法,其实使用两个变量来储存dp[i-1]和dp[i-2]就可以了,这样空间复杂度只有O(1)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值