基础知识,理解,背就完事了

198 阅读7分钟

js的数字存储方式

在js中数字 遵循IEEE754(?)的原则用64位表示一个数字(1+11+52)

  1. 0符号位 0表示负 1表示正数
  2. 1-11 代表指数部分e
  3. 12-63 尾数 也就是小数部分,有效数字部分f 最大安全数字:Number.MAX_SAFE_INTIGER = MATH.pow(2,53)-1, 因为二进制数的第一位总是1,尾数在默认形式下第一位默认为1剩下的52位 转换成整数就是16位 所以0.1===0.1 在通过toPrecision(16)之后是成立的

在两个数字相加是 计算机会先将他们转化成二进制数字 juejin原贴 JS的number存储

冒泡流和捕获流

addeventlistener(methods, function, isbubble) 默认fasle 表示事件在冒泡流处理 (true捕获流)

w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = truee.stopPropagation() 阻止冒泡

先进行捕获再进行冒泡

new

function P(name) { this.name = name }
let p1 = new P('parent1')
function _new() {
    let obj = {}
    let constructorFun = Array.prototype.shift.call(arguments)
    constructorFun.call(obj, ...arguments)
    obj.__proto__ = constructorFun
    return obj
}
let _p1 = _new(P, '_parent1')

变量之间的加减

如果有一个是字符串,相加就是进行拼凑; 相减会转换成数字进行相减,如果结果不是numner就是NAN,true false 会转换成1,0 进行相减 null 会转化为 0 ,undefined转化NaN

bind apply call

改变this指向

fun.bind(thisArg, [argsArray]) // bind后不会执行
fun.apply(thisArg, [argsArray])
fun.call(thisArg[, arg1[, arg2[, ...]]])
  • thisArg:在 fun 函数运行时指定的 this 值。需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。
let obj = { name: '123', age:1 }
function say(name, age) {
    console.log(name, age)
}
say.call(this, obj.name, obj.age)
say.apply(this, [obj.name, obj.age])
say.bind(this, obj.name, obj.age)()

new 和 bind

先定义一个构造函数, 然后使用bind 创造这个构造函数的继承函数

这个继承函数的实例对象的原型是最原始的构造函数


function f(p1, p2) {
    this.v = p1 + p2;
}

const g = f.bind(null, 'x');

const obj = new g('y');
// 下面的结果都是true 因为 o instanceof target会判断target[Symbol.hasInstance](o), 
然后再判断target.prototype 是否在o的原型上
console.log(obj instanceof f, obj instanceof g)
// obj的原型为f
console.log(obj.v, obj.__proto__, Object.getPrototypeOf(obj));

es6 Class 继承

class Humen {
    constructor() {
        this.eyes = 2
        this.legs = 2
        this.skill = ['run', 'eat']
    }
    say(word) {
        console.log(word, this.skill)
    }
}
class solder extends Humen {
    constructor() {
        super() // 继承父类的构造属性
        this.haveGun = true
        this.attack = 100
    }
    attacking() {
        console.log('attack', this.attack, this.eyes)
    }
}
let solder1 = new solder()

JS 脚本加载

<script src="script.js"></script>
  1. 如果没有defer async 浏览器会立即执行指定脚本,立即是指在这个script 标签下的DOM元素要等待这个script标签加载完成之后再进行载入
<script async src="script.js"></script>
  1. async 会在和渲染后续文档元素的过程将和JS文件异步进行
  2. defer 在加载后续文档元素的过程将和JS文件异步,但是JS执行要在所有的元素解析之后 DOMContentLoaded事件之前完成

es6 module 跟 commonjs的区别

  1. commonJS
     // function sum(a,b) {
     //     return a+b
     // }
     // exports.sum = sum
    
     // const sum = require('./math').sum
    

同步加载 随用随引

  1. AMD
define
require

异步加载 需要引用支持库才可使用

  1. CMD
/** AMD写法 **/
define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) { 
   // 等于在最前面声明并初始化了要用到的所有模块
   a.doSomething();
   if (false) {
      // 即便没用到某个模块 b,但 b 还是提前执行了
      b.doSomething()
   } 
});

/** CMD写法 **/
define(function(require, exports, module) {
   var a = require('./a'); //在需要时申明
   a.doSomething();
   if (false) {
      var b = require('./b');
      b.doSomething();
   }
});

AMD 加载前置 提前加载, CMD 加载后置,按需加载

  1. requireJs

为了避免出现多和sprit标签引入使用requireJs 进行统筹

/** 网页中引入require.js及main.js **/
<script src="js/require.js" data-main="js/main"></script>

/** main.js 入口文件/主模块 **/
// 首先用config()指定各模块路径和引用名
require.config({
   baseUrl: "js/lib",
   paths: {
      "jquery": "jquery.min",  //实际路径为js/lib/jquery.min.js
      "underscore": "underscore.min",
   }
});
// 执行基本操作
require(["jquery","underscore"],function($,_){
   // some code here
});``

// 定义math.js模块
define(function () {
   var basicNum = 0;
   var add = function (x, y) {
      return x + y;
   };
   return {
      add: add,
      basicNum :basicNum
   };
});
// 定义一个依赖underscore.js的模块
define(['underscore'],function(_){
   var classify = function(list){
      _.countBy(list,function(num){
         return num > 30 ? 'old' : 'young';
      })
   };
   return {
      classify :classify
   };
})

// 引用模块,将模块放在[]内
require(['jquery', 'math'],function($, math){
   var sum = math.add(10,20);
   $("#sum").html(sum);
});

在index.js 下使用require统一引用多个module, require的配置项根据文档来配置 5. ES6模块化写法

import {} from xxx

export function xx () {

}
  1. ES6 module模块(import) 与 CommonJS(require) 模块的差异
  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。

    CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。 ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的import有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。

  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。

    运行时加载: CommonJS 模块就是对象;即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为“运行时加载”。

    编译时加载: ES6 模块不是对象,而是通过 export 命令显式指定输出的代码,import时采用静态命令的形式。即在import时可以指定加载某个输出值,而不是加载整个模块,这种加载称为“编译时加载”。

    CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。

http和https相关

这方面知识比较多,仅简单总结

  • http 是无状态的超文本传输的应用层协议,它基于TCP/IP传输层协议,
  • https 是将http协议添加了ssl安全认证
  • http 对称加密 https既有对称加密也有非对称加密。
  • https 加密过程
  1. 建立连接时浏览器发出请求,服务器接受请求后将证书和非对称的加密方法发给客户端
  2. 浏览器校验证书,若通过,用收到的非对称加密的方法将公钥加密
  3. 服务器收到加密后的公钥,进行解密(仅自己能够解密这个非对称加密的公钥)
  4. 此时双方都有加密公钥并且保证这个公钥仅双方使用,这就是建立了一个安全的https链接

前端性能优化

  • 静态图片资源的处理
  • 代码优化,使用异步懒加载
  • 服务端渲染
  • 加载异步 async defer
  • 与服务器进行协商缓存判断

for + setTimeout

下列代码在1秒后输出0-9

for (var i = 0; i < 10; i++) { 
    (function (j) { 
        setTimeout(() => { console.log(j) }, 1000) 
    })(i) 
}

立即执行函数形成闭包 (也可以使用let 定义i 形成块级作用域),否则每次循环后将settimeout放入异步执行站中,在循环完成后打印i所有的结果10

数组扁平化

使用ES6中的Array.prototype.flat方法 arr.flat(Infinity)
function flat(arr) {
    return arr.reduce((total, item)=> {
        return total.concat(Array.isArray(item)? flat(item) : item)
    }, [])
}
function flat(arr) {
    let result = []
    return arr.map((item => {
        if(Array.isArray(item)) {
            result.concat(flat(item))
        } else {
            result.push(item)
        }
    })
}

一组数据类型比较

//字符串连接符 
console.log(1 + 'true')// +是字符串连接符, String(1) + 'true',打印出'1true' 
//算术运算符 
console.log(1 + true) // +是算术运算符,true被Number(true)->1,打印出2 
console.log(1 + undefined) // 1 + Number(undefined) -> 1 + NaN, 打印NaN 
console.log(1 + null) // 1 + Number(null) -> 1 + 0,打印出1 

//关系运算符 
// 一边数字一边字符串,Number("2") // 2 > 5,打印false 
console.log("2" > 5) // 两边字符串,调用"2".charCodeAt() -> 50 
console.log("2" > "5") 

// 多个字符串从左往右匹配,也是调用charCodeAt方法进行比较 
// 比较"a".charCodeAt() < "b".charCodeAt(),打印false 
console.log("abc" > "b") 
// 左边第一个"a"和右边第一个"a"的unicode编码相等 
// 继续比较两边第二个字符, "b" > "a",打印true 
console.log("abc" > "aaa") 

//无视上述规则自成体系 
console.log(NaN == NaN) // NaN和任何数据比较都是 false 
console.log(undefined == undefined) //true 
console.log(undefined === undefined) //true 
console.log(undefined == null) //true 
console.log(undefined === null) //false

在es5环境下实现const定义

// 定义了一个name变量 不可以被修改(const)
Object.defineProperty('window', 'name', {value: 'nameValue', writeable: false})

call

eg 
function p(name) {
   console.log(this.name, name)
}
let obj = {
    name: 'guo'
}
p.call(obj, 'hua') // 常规用法
Function.prototype.myCall = function(thisArg, ...arg) {
    let fn = Symbol('fn')
    let thisArg = thisArg || window
    thisArg[fn] = this
    let result = thisArg[fn](...args)
    delete thisArg[fn]
    return result
}
console.log(1); 
setTimeout(() => { 
    console.log(2); 
    new Promise((resolve) => { 
        console.log(3); 
        resolve();
    }).then(() => { 
        console.log(4); 
    }); 
}); 
new Promise((resolve) => { 
    console.log(5); 
    resolve();
}).then(() => { 
    console.log(6);
}); 
setTimeout(() => { 
    console.log(7); 
    new Promise((resolve) => { 
        console.log(8); 
        resolve(); 
    }).then(() => { 
    console.log(9); 
    });
 }); 
 console.log(10)