js的数字存储方式
在js中数字 遵循IEEE754(?)的原则用64位表示一个数字(1+11+52)
- 0符号位 0表示负 1表示正数
- 1-11 代表指数部分e
- 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>
- 如果没有defer async 浏览器会立即执行指定脚本,立即是指在这个script 标签下的DOM元素要等待这个script标签加载完成之后再进行载入
<script async src="script.js"></script>
- async 会在和渲染后续文档元素的过程将和JS文件异步进行
- defer 在加载后续文档元素的过程将和JS文件异步,但是JS执行要在所有的元素解析之后 DOMContentLoaded事件之前完成
es6 module 跟 commonjs的区别
- commonJS
// function sum(a,b) { // return a+b // } // exports.sum = sum // const sum = require('./math').sum
同步加载 随用随引
- AMD
define
require
异步加载 需要引用支持库才可使用
- 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 加载后置,按需加载
- 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 () {
}
- 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 加密过程
- 建立连接时浏览器发出请求,服务器接受请求后将证书和非对称的加密方法发给客户端
- 浏览器校验证书,若通过,用收到的非对称加密的方法将公钥加密
- 服务器收到加密后的公钥,进行解密(仅自己能够解密这个非对称加密的公钥)
- 此时双方都有加密公钥并且保证这个公钥仅双方使用,这就是建立了一个安全的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)