JavaScript基础知识小记

前言

最近发现自己许多JavaScript基础知识掌握不牢固。趁空闲时间,整理一下JavaScript的基础知识。

正题

数据类型

JavaScript一共有8中数据类型,其中7中是基本数据类型:undefined、null、Boolean、Number、String、Symbol、BigInt(es10新增)。还有一种引用类型Object(其中包括Function、Date、Array等)。
基本数据类型在内存中直接存储其值
引用数据类型在内存中存储的是其地址指针

js的内置对象

全局的对象( global objects )或称标准内置对象,不要和 "全局对象(global object)" 混淆。这里说的全局的对象是说在
全局作用域里的对象。全局作用域中的其他对象可以由用户的脚本创建或由宿主程序提供。
标准内置对象的分类
(1)值属性,这些全局属性返回一个简单值,这些值没有自己的属性和方法。
例如 Infinity、NaN、undefined、null 字面量
(2)函数属性,全局函数可以直接调用,不需要在调用时指定所属对象,执行结束后会将结果直接返回给调用者。
例如 eval()、parseFloat()、parseInt() 等
(3)基本对象,基本对象是定义或使用其他对象的基础。基本对象包括一般对象、函数对象和错误对象。
例如 Object、Function、Boolean、Symbol、Error 等
(4)数字和日期对象,用来表示数字、日期和执行数学计算的对象。
例如 Number、Math、Date
(5)字符串,用来表示和操作字符串的对象。
例如 String、RegExp
(6)可索引的集合对象,这些对象表示按照索引值来排序的数据集合,包括数组和类型数组,以及类数组结构的对象。例如 Array
(7)使用键的集合对象,这些集合对象在存储数据时会使用到键,支持按照插入顺序来迭代元素。
例如 Map、Set、WeakMap、WeakSet
(8)矢量集合,SIMD 矢量集合中的数据会被组织为一个数据序列。
例如 SIMD 等
(9)结构化数据,这些对象用来表示和操作结构化的缓冲区数据,或使用 JSON 编码的数据。
例如 JSON 等
(10)控制抽象对象
例如 Promise、Generator 等
(11)反射
例如 Reflect、Proxy
(12)国际化,为了支持多语言处理而加入 ECMAScript 的对象。
例如 Intl、Intl.Collator 等
(13)WebAssembly
(14)其他

寄生式组合继承

所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的形式来继承方法。

function Person(name) {
 this.name = name;
}

Person.prototype.sayName = function() {
 console.log("My name is " + this.name + ".");
};

function Student(name, grade) {
 Person.call(this, name);
 this.grade = grade;
}

Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

Student.prototype.sayMyGrade = function() {
 console.log("My grade is " + this.grade + ".");
};

ES6模块和CommonJS模块的差异

  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令 import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。
  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。CommonJS 模块就是对象,即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为“运行时加载”。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段才会生成。

深拷贝(考虑日期、正则等特殊对象解决循环引用)

function deepClone(obj, hash = new WeakMap()) {
  if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  // 可能是对象或者普通的值  如果是函数的话是不需要深拷贝
  if (typeof obj !== "object") return obj;
  // 是对象的话就要进行深拷贝
  if (hash.get(obj)) return hash.get(obj);
  let cloneObj = new obj.constructor();
  // 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
  hash.set(obj, cloneObj);
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 实现一个递归拷贝
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }
  return cloneObj;
}
let obj = { name: 1, address: { x: 100 } };
obj.o = obj; // 对象存在循环引用的情况
let d = deepClone(obj);
obj.address.x = 200;
console.log(d);

防抖函数

function debounce(func, wait = 1000){
   let timer = null
   return function(...params){
       clearTimeout(timer)
       timer = setTimeout(()=>{
           timer = null
           func.call(this, ...params)
       },wait)
   }   
}
const a = debounce(function(flag){
   console.log(flag)
},1000)
a(1)
a(2)
a(3)
a(4)

使用reduce实现数组扁平化

const arr = [123,[123,12432,[12321,1232123,12321421,[1232123],12321,[12321],[12321]],12321],1232123]
function myFlat (arr){
    return arr.reduce((pre, cur) => {
        return pre.concat(Array.isArray(cur) ? myFlat(cur) : cur);
    }, []);
}
console.log(myFlat(arr))
// [123, 123, 12432, 12321, 1232123, 12321421, 1232123, 12321, 12321, 12321, 12321, 1232123]

实现call

Function.prototype._call = function (context, ...args){
    //  null,undefined,和不传时,context为 window
    context = context == null ? window : context;
    // 必须保证 context 是一个对象类型
    let contextType = typeof context;
    if (!/^(object|function)$/i.test(contextType)) {
        // context = new context.constructor(context); // 不适用于 Symbol/BigInt
        context = Object(context);
    }
  
    let result;
    context['fn'] = this; // 把函数作为对象的某个成员值
    result = context['fn'](...args); // 把函数执行,此时函数中的this就是context
    delete context['fn']; // 设置完成员属性后,删除
    return result;
}

实现apply

Function.prototype._apply = function (context, args){
    //  null,undefined,和不传时,context为 window
    context = context == null ? window : context;
    // 必须保证 context 是一个对象类型
    let contextType = typeof context;
    if (!/^(object|function)$/i.test(contextType)) {
        // context = new context.constructor(context); // 不适用于 Symbol/BigInt
        context = Object(context);
    }
  
    let result;
    context['fn'] = this; // 把函数作为对象的某个成员值
    result = context['fn'](...args); // 把函数执行,此时函数中的this就是context
    delete context['fn']; // 设置完成员属性后,删除
    return result;
}

实现bind

Function.prototype._bind = function(context, ...params){
    const _this = this;
    return function(...args){
        _this.call(context, ...params.concat(args))
    }
}

实现map

Array.prototype._map = function(callback, context){
  const arr = this;
  const res = []
  for(let i = 0; i< arr.length; i++){
    res.push(callback.call(context, arr[i],i ,arr))
  }
  return res
}

这里有一个有趣的面试题

// 返回什么?
['100','200','300','400'].map(Number) 
// 返回什么?
['100','200','300','400'].map(parseInt) 
// 为什么呢?

实现filter

Array.prototype._filter = function(callback, context){
  const arr = this;
  const res = []
  for(let i = 0 ; i< arr.length; i++){
    if(callback.call(context,arr[i], i ,arr)){
      res.push(arr[i])
    }
  }
  return res
}

实现reduce

Array.prototype._reduce = function(callback, inital){
  const arr = this;
  let prev = inital
  let initalKey= 0
  if(!inital){
    for(let i = 0;i<arr.length;i++){
      if(arr[i]){
        initalKey = i
        prev = arr[i]
        break
      }
    }
  }
  for(let i = initalKey; i< arr.length; i++){
    prev = callback.call(undefined, prev, arr[i], i, arr)
  }
  return prev
}

实现promise.all

Promise._all = function(promiseList){
  return new Promise((resolve, reject) => {
    let flag = 0
    const result = []
    promiseList.forEach(promise => {
      promise.then(res => {
        result.push(res)
        flag++
        if(flag === promiseList.length){
          resolve(result)
        }
      }).catch(err => {
        reject(err)
      })
    })
  })
}

这里有一个有趣的面试题
要求手写一个并发数为3的promise.all

Promise._allWithLimit3 = function(promiseList){
  return new Promise((resolve, reject)=>{
    const len = promiseList.length
    const taskList = promiseList.splice(0,3)
    const otherList = promiseList.splice(0)
    const result = []
    let total = 0;
    taskList.forEach(promise=>{
      singleTaskRun(promise)
    })
    function singleTaskRun (promise){
      promise.then(res=>{
        result.push(res)
        total++
        if(otherList.length > 0){
          const task = otherList.shift()
          singleTaskRun(task)
        } 
        if(total === len){
          resolve(result)
        }
      }).catch(err=>{
        reject(err)
      })
    }
  })
}
// 测试代码
let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("1");
  }, 1000);
});
let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("2");
  }, 1500);
});
let p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("3");
  }, 2000);
});
let p4 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("4");
  }, 2500);
});
let p5 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("5");
  }, 5000);
});

let all = Promise._allWithLimit3([p1, p3, p2, p4, p5]);
all.then(
  data => {
    console.log("data", data); 
  }
).catch(err => {
  console.log('err',err)
})
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,226评论 6 524
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,509评论 3 405
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,523评论 0 370
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,181评论 1 302
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,189评论 6 401
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,642评论 1 316
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,993评论 3 431
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,977评论 0 280
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,527评论 1 326
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,547评论 3 347
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,661评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,250评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,991评论 3 340
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,422评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,571评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,241评论 3 382
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,737评论 2 366