前端js基础整理

  1. js中的数据类型

基本类型:String,Number,Boolean,null,Undefined,Symbol,BigInt

引用数据类型:Object,Array,Function,Date,RegExp

  1. es6相对于es5的变化

let和const以及var

箭头函数

模板字符串

解构赋值

扩展运算符

Promise

模块的 Import 和 Export(es6的模块系统)

Map、Set

Array、String新增的api(Array.from(),String.prototype.startsWith(),String.prototype.endsWith())

  1. 闭包

闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。

闭包的优点:

1. 逻辑连续,当闭包作为另一个函数调用的参数时,避免你脱离当前逻辑而单独编写额外逻辑。

2. 方便调用上下文的局部变量。

3. 加强封装性,第2点的延伸,可以达到对变量的保护作用。

闭包的缺点:

1.常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。   

   2.还有有一个非常严重的问题,那就是内存浪费问题,这个内存浪费不仅仅因为它常驻内存,更重要的是,对闭包的使用不当会造成无效内存的产生。

常见的闭包的应用:防抖、节流、模块化

  1. new的原理及手写new函数

原理:

  1. 创建一个空对象obj。

  1. 给空对象obj的__proto__(隐式原型)赋值为构造函数的prototype(原型对象)。

  1. 将this指向这个空对象obj。

  1. 将构造函数的参数传入空对象的方法中,并执行方法。

  1. return新对象obj.

手写源码:

function myNew(Class, ...args) {
    // 1.创建一个空对象
    let obj = {};

    // 2.将空对象的__proto__指向构造函数的prototype
    obj.__proto__ = Class.prototype;

    // 3.将this指向空对象
    // 4.执行构造函数中的代码,为空对象添加属性和方法(call方法会改变this的指向,并且自动执行)
    Class.call(obj, ...args);

    // 5.返回新的对象
    return obj;
}
  1. Promise的核心原理和手写源码

关于Promise的几个核心疑问:

1、Promise怎么控制then中的函数的执行?

then中的回调函数并不会都马上立即执行,而是会先被注册,放入回调执行队列中,只有当状态发生改变的时候,才会触发执行整个队列,即发布订阅模式。

2、Promise是如何实现连续then调用的?

then方法执行的时候,会new一个新的Promise,因为then方法是其原型上的,所以可以连续调用。

手写源码:摘自51CTO的wx60d5b00b4a867

/**
 * 1. new Promise时,需要传递一个 executor 执行器,执行器立刻执行
 * 2. executor 接受两个参数,分别是 resolve 和 reject
 * 3. promise 只能从 pending 到 rejected, 或者从 pending 到 fulfilled
 * 4. promise 的状态一旦确认,就不会再改变
 * 5. promise 都有 then 方法,then 接收两个参数,分别是 promise 成功的回调 onFulfilled, 
 *      和 promise 失败的回调 onRejected
 * 6. 如果调用 then 时,promise已经成功,则执行 onFulfilled,并将promise的值作为参数传递进去。
 *      如果promise已经失败,那么执行 onRejected, 并将 promise 失败的原因作为参数传递进去。
 *      如果promise的状态是pending,需要将onFulfilled和onRejected函数存放起来,等待状态确定后,再依次将对应的函数执行(发布订阅)
 * 7. then 的参数 onFulfilled 和 onRejected 可以缺省
 * 8. promise 可以then多次,promise 的then 方法返回一个 promise
 * 9. 如果 then 返回的是一个结果,那么就会把这个结果作为参数,传递给下一个then的成功的回调(onFulfilled)
 * 10. 如果 then 中抛出了异常,那么就会把这个异常作为参数,传递给下一个then的失败的回调(onRejected)
 * 11.如果 then 返回的是一个promise,那么会等这个promise执行完,promise如果成功,
 *   就走下一个then的成功,如果失败,就走下一个then的失败
 */

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function Promise(executor) {
    let self = this;
    self.status = PENDING;
    self.onFulfilled = [];//成功的回调
    self.onRejected = []; //失败的回调
    //PromiseA+ 2.1
    function resolve(value) {
        if (self.status === PENDING) {
            self.status = FULFILLED;
            self.value = value;
            self.onFulfilled.forEach(fn => fn());//PromiseA+ 2.2.6.1
        }
    }

    function reject(reason) {
        if (self.status === PENDING) {
            self.status = REJECTED;
            self.reason = reason;
            self.onRejected.forEach(fn => fn());//PromiseA+ 2.2.6.2
        }
    }

    try {
        executor(resolve, reject);
    } catch (e) {
        reject(e);
    }
}

Promise.prototype.then = function (onFulfilled, onRejected) {
    // PromiseA+ 2.2.1 / PromiseA+ 2.2.5 / PromiseA+ 2.2.7.3 / PromiseA+ 2.2.7.4
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
    let self = this;
    // PromiseA+ 2.2.7
    // setTimeout用于模拟异步
    let promise2 = new Promise((resolve, reject) => {
        if (self.status === FULFILLED) {
            //PromiseA+ 2.2.2
            //PromiseA+ 2.2.4 --- setTimeout
            setTimeout(() => {
                try {
                    //PromiseA+ 2.2.7.1
                    let x = onFulfilled(self.value);
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    //PromiseA+ 2.2.7.2
                    reject(e);
                }
            });
        } else if (self.status === REJECTED) {
            //PromiseA+ 2.2.3
            setTimeout(() => {
                try {
                    let x = onRejected(self.reason);
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    reject(e);
                }
            });
        } else if (self.status === PENDING) {
            self.onFulfilled.push(() => {
                setTimeout(() => {
                    try {
                        let x = onFulfilled(self.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                });
            });
            self.onRejected.push(() => {
                setTimeout(() => {
                    try {
                        let x = onRejected(self.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                });
            });
        }
    });
    return promise2;
}

function resolvePromise(promise2, x, resolve, reject) {
    let self = this;
    //PromiseA+ 2.3.1
    if (promise2 === x) {
        reject(new TypeError('Chaining cycle'));
    }
    if (x && typeof x === 'object' || typeof x === 'function') {
        let used; //PromiseA+2.3.3.3.3 只能调用一次
        try {
            let then = x.then;
            if (typeof then === 'function') {
                //PromiseA+2.3.3
                then.call(x, (y) => {
                    //PromiseA+2.3.3.1
                    if (used) return;
                    used = true;
                    resolvePromise(promise2, y, resolve, reject);
                }, (r) => {
                    //PromiseA+2.3.3.2
                    if (used) return;
                    used = true;
                    reject(r);
                });

            } else {
                //PromiseA+2.3.3.4
                if (used) return;
                used = true;
                resolve(x);
            }
        } catch (e) {
            //PromiseA+ 2.3.3.2
            if (used) return;
            used = true;
            reject(e);
        }
    } else {
        //PromiseA+ 2.3.3.4
        resolve(x);
    }
}

  1. call、apply、bind的原理极其源码

关于this指向,众所周知有这么几种情况:

  1. 普通函数的this指向是:谁调用指向谁。

  1. 箭头函数的this指向是:在哪里定义的指向谁。

  1. 全局作用域下,浏览器的this指向window、nodejs的this指向global。

  1. 定时器中的this指向全局。

注:在非严格模式和严格模式下,this的指向有一些不同的。

// call的源码(apply和call的唯一区别就是传参的形式不同)
const myCall = function (...arguments){
    // 没有传参的时候,直接绑定全局作用域
    const that = arguments[0] || window
    // myCall被调用的时候,this为我们实际要执行的函数,如下面对类数组的操作,在调用call的时候,里面的this就是slice.
    const params = [].slice.call(arguments,1)
    that.fn = this // 我们接一下这个函数
    that.fn(...params)
    delete that.fn // 执行完毕后,我们删除绑定,避免造成修改
}
Function.prototype.myCall = myCall、
// bind的源码
const myBind = function(...arguments){
    const that = arguments[0] || window
    const params = [].slice.call(arguments,1)
    const fn = this
    return function(){
        that.fn = fn
        that.fn(...params)
        delete that.fn
    }
}

7.深拷贝、浅拷贝

深拷贝:不同的指针,不同的堆内存空间。数据独立

浅拷贝:不同的指针,相同的堆内存空间。数据相互影响

常见的深拷贝方法:

1. 使用递归的方式实现深拷贝

//使用递归的方式实现数组、对象的深拷贝
    function deepClone1(obj) {
      //判断拷贝的要进行深拷贝的是数组还是对象,是数组的话进行数组拷贝,对象的话进行对象拷贝
      var objClone = Array.isArray(obj) ? [] : {};
      //进行深拷贝的不能为空,并且是对象或者是
      if (obj && typeof obj === "object") {
        for (key in obj) {
          if (obj.hasOwnProperty(key)) {
            if (obj[key] && typeof obj[key] === "object") {
              objClone[key] = deepClone1(obj[key]);
            } else {
              objClone[key] = obj[key];
            }
          }
        }
      }
      return objClone;
    }

2. 通过 JSON 对象实现深拷贝

  //通过js的内置对象JSON来进行数组对象的深拷贝
    function deepClone2(obj) {
      var _obj = JSON.stringify(obj),
        objClone = JSON.parse(_obj);
      return objClone;
    }
    JSON对象实现深拷贝的一些问题 
    *无法实现对对象中方法的深拷贝

3. 通过jQuery的extend方法实现深拷贝

 var array = [1,2,3,4];
 var newArray = $.extend(true,[],array);

4、es6的展开语法

let a = {
   name : '张三',
    age : '18'
}
let b = {...a};
b.name = '李四';
console.log('a:',a);
console.log('b:',b);
*注意:es6的展开语法只针对第一层,对多层还是浅拷贝方式

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值