复习一下前端基础

398 阅读5分钟

背景

这两天复习了一下前端的一些初级的基础知识,很多东西长时间不看,就会只记得一个大概,再加深一下印象。

闭包

堆栈

深浅克隆 demo4.js

对象最好不要超过7层

浅克隆就是只克隆了第一层

堆栈内存和闭包作用域 -> demo1

函数堆对象 + 上下文作用域 = 闭包

闭包: 私有化变量

  • 堆: 存储引用类型值的空间
  • 栈: 存储基本类型的值和指定代码的环境

symbol

valueOf

一道阿里的函数的题录 demo5.js

同步异步

异步: async await setTimeout Promise

事件队列: (先执行微任务,再执行宏任务)

  1. 微任务: await resolve() 【哪个在前面,先执行哪个,队列】
  2. 宏任务: setTimeout 事件绑定 ajax

PS : new Promise 的时候,会立即执行里面的函数

箭头函数

不能被new, 没有原型, 没有构造函数

柯里化

下面就是函数柯里化

const curried = (a) => {
    return (b) => {
        return a + b; 
    }
}
const addTen = curried(5);

addTen(5); // 10

手写深拷贝

function deepClone(obj = {}) {
    if (typeof obj !== 'object' || obj === null) {
        return obj;
    }
    let result;
 
    if (obj instanceof Array) {
        result = [];
    } else {
        result = {}
    }

    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            result[key] = deepClone(obj[key]);
        }
    }
    return result;
}

基础类型

基础类型, 直接存在栈里; 引用类型是存放内存地址在栈里

引用类型的实际的值, 存在堆里面

引用类型

对象,数组,null, 特殊引用类型,函数function

typeof 运算符

  • 可以识别出所有的值类型
  • 判断函数
  • 判断是否是引用类型

类型转化

if (obj.a == null) {}
// 相当于
if (obj.a === null || obj.a === undefined) {}

truly 变量: !!a === true

class

class的本质是函数,可见是语法糖

typeof People === 'function'

每个class都有显式原型,

每个实例都有隐式原型,指向class的显示原型

原型

隐式原型: xialuo.__proto__

等于

显式原型: Student.prototype

原型链

作用域

函数作用域

全局作用域

ES6块级作用域

自由变量

一个变量在当前作用域没有定义,但被使用了

向上级作用域,一层一层的依次寻找,直到找到为止

闭包 closure

  • 函数作为参数被传递
  • 函数作为返回值被返回

应该在定义时候的作用域,向上级寻找

// 函数作为返回值
function createFun () {
    let a = 100;
    return function () {
        console.log(a) // 应该在定义时候的作用域,向上级寻找
    }
}
let fn = createFun();
let a = 200;
fn() // 100

// 函数作为参数

function print(fn) {
    let a = 100;
    fn()
}
let a = 200;
function fn () {
    console.log(a) // 应该在定义时候的作用域,向上级寻找
}
print(fn) // 200

总结: 自由变量的查找,是在函数定义的地方,向上级查找,不是在执行的地方 闭包影响: 变量会常驻内存,得不到释放 ,不能乱用

手写深拷贝

function deepClone(obj) {
    if (typeof obj !== 'object' || obj == null) {
        return obj;
    }
    let result;

    if (obj instanceof Array) {
        result = [];
    } else {
        result = {};
    }

    for(let key in obj) {
        // 保证key 不是原型的属性
        if (obj.hasOwnProperty(key)) {
            result[key] = deepClone(obj[key]);
        }
    }
    return result;
}

Object.assign() 不是深拷贝, 浅层拷贝

requestAnimateFrame

作用域和闭包

this

function fn () {
	console.log(this);
}
const fn1 = fn.call({a: 1}) // {a: 1}
fn1() // {a: 1}

const fn2 = fn.bind({b: 1})
fn2(); // {b: 1}

手写bind 函数

Function.prototype.bind = function () {
    // 参数转化为数组
    let args = Array.prototype.slice.call(arguments);
    
    // 数组的第一个参数,作为要绑定的this
    const p = args.shift();
    // 当前函数
    const that = this;
    return function () {
        return that.apply(p, args);
    }
}

手写apply

Function.prototype.apply = function (context) {
    if (context == null) {
        context = window;
    }
    context.fn = this;
    const args = [...arguments].slice(1);
    let result;
    if (args[0]) {
        result = context.fn(...args[0]);
    } else {
        result = context.fn();
    }
    delete context.fn
    return result;
}

手写call

Function.prototype.call = function (context) {
    let args = [...arguments].slice(1);
    context.fn = this;
    const result = context.fn(...args);
    delete context.fn;
    return result;
}

异步

// 1,3,5,4,2
console.log(1);

setTimeout(() => {
    console.log(2);
}, 1000)

console.log(3);

setTimeout(() => {
    console.log(4);
}, 0)
console.log(5);

DOM API

// 创建文档片段,目的是为了减少操作DOM的次数
const frag = document.createDocumentFragment();

事件

  • 事件绑定
  • 事件冒泡
  • 事件代理

手写一个ajax

XMLHttpRequest

const xhr = new XMLHttpRequest();
// true  指的是异步的请求 
xhr.open('GET', '/v1/url/id', true);
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
        if (xhr.state === 200) {
            
        }
    }
}
xhr.send(null);

跨域

  • jsonp
  • CORS 设置 http header

cookie

  • 存储大小,最大4KB
  • http请求的时候需要发送到服务器端,增加了请求的数据量
  • API很难用

localStorage & sessionStorage

  • HTML5专门为了存储而设计的,最大可存储5M,而且是针对域名来说的
  • API简单

区别

  • localStorage 数据会永久存储,除非代码或手动删除
  • sessionStorage 数据只存在于当前会话,浏览器关闭则清空

隐式类型转换

if , 逻辑运算, ==, +号

手写深度比较, isEqual

主要是用了递归

function isObject(params) {
    return typeof params === 'object' && params !== null;
}
function isEqual(obj1, obj2) {
    if (!isObject(obj1) || !isObject(obj2)) {
        return obj1 === obj2;
    }

    if (obj1 === obj2) {
        return true
    }

    const len1 = Object.keys(obj1);
    const len2 = Object.keys(obj2);
    if (len1 !== len2) return false;

    for (let key in obj1) {
        const res = isEqual(obj1[key], obj2[key]);
        if (!res) return false;
    }
    return true;
}

函数声明,函数表达式

  • 函数声明,会预加载
  • 函数表达式

Object

  • new Object() 创建一个对象,也就是 {}, 自带prototype
  • Object.create() 必须传入一个参数
// 创建一个空对象,然后把原型指向传入的参数
Object.create(null) // 这样就没有原型了
Object.create({aaa: 1}) // 指定一个原型 {aaa: 1}

this 场景题

函数 this 的值,在执行的时候,才知道

const user = {
    name: 'lys',
    sum: () => {
        console.log(this.name); // undefined
    },
    getName: function (params) {
        console.log(this.name); // lys
    }
}
const fun = user.sum;
console.log(user.sum()); // undefined
fun(); // undefined

作用域

// 返回4个4, 因为index的作用域在外层
let index;
for (index = 0; index < 4; index++) {
    setTimeout(() => {
        console.log(index);
    }, 0);
}

手写trim

String.prototype.trim = function (params) {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
};

捕获JS中的异常

window.onerror = function () {

}

什么是JSON

  • JSON是一种数据格式,本质上是一段字符串
  • JSON格式和JS对象结构一致,对JS语言更友好

获取当前页面URL

  • location.search
  • URLSearchParams, 新API 兼容性不太好 这个很简单

substr(start, length) substring(start, end) slice(start, end)

function query(name) {
    const search = location.search.substr(1);
    // * 是0个或多个 >=0
    const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`, 'i'); 

    const res = search.match(reg);
    if (res == null) {return null}
    return res[2];
}

将URL参数解析为JS对象

手写flatern 考虑多层级

也就是拍平

// 只能拍平一层
Array.prototype.concat.apply([], arr);

function flat(arr) {
    // 判断各个元素里面是否有数组
    const isDeep = arr.some((item) => item instanceof Array);
    // 递归的暂停条件
    if (!isDeep) {
        return arr;
    }

    const res = Array.prototype.concat.apply([], arr);

    return flat(res); // 递归
}

数组去重

  1. forEach 循环,然后使用indexOf,或者includes来判断新数组,是否有这个item
  2. Set方式
function unique(arr) {
    const set = new Set(arr);
    return [...set];
}

instanceof

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

// 语法

object instanceof constructor