首页 > 其他分享 >JS杂谈

JS杂谈

时间:2022-12-25 18:11:23浏览次数:63  
标签:函数 对象 NaN undefined 杂谈 JS 模块 属性

微任务(microtasks)

宏任务(macrotask):

  • script(全局任务)
  • setTimeout
  • setInterval
  • setImmediate
  • I/O
  • UI rendering

微任务(microtasks):需要在当前 任务 执行结束后立即执行的任务

  • process.nextTick() 注册的回调 (nextTick task queue)
  • promise.then() 注册的回调 (promise task queue)
  • Object.observer
  • MutationObserver

Node 在执行微任务时, 会优先执行 nextTick task queue 中的任务,执行完之后会接着执行 promise task queue 中的任务。

所以如果 process.nextTick 的回调与 promise.then 的回调都处于主线程或事件循环中的同一阶段, process.nextTick 的回调要优先于 promise.then 的回调执行。

在node事件循环机制中 每次推进一个阶段就要清空当前的promise和nextTick  而清空的顺序就是nextTick优先promise。

Promise 的回调函数不是正常的异步任务,而是微任务(microtask)。它们的区别在于,正常任务追加到下一轮事件循环,微任务追加到本轮事件循环。这意味着,微任务的执行时间一定早于正常任务。

then的回调函数的执行时间,早于setTimeout(fn, 0)。因为then是本轮事件循环执行,setTimeout(fn, 0)在下一轮事件循环开始时执行。


浏览器加载 CommonJS 模块的原理与实现

浏览器不兼容CommonJS的根本原因,在于缺少四个Node.js环境的变量。
  • module

  • exports

  • require

  • global

只要能够提供这四个变量,浏览器就能加载 CommonJS 模块。


ES6模块和CommomJS模块的异同

  • CommonJS

    • 最初为服务端设计,node.js版本。

    • 每个文件即是一个模块,用于独立的作用域。

    • 导出是一个模块向外暴露自己的唯一方式。CommonJS中通过module.exports导出模块中的内容。

    • CommonJS中使用require进行模块的导入。

    • 如果导入的模块是第一次被加载,这时会首先执行该模块,然后导出执行后的内容。 如果模块曾经被加载过,则直接导出第一次加载时执行后的内容。(相当于是一个静态值了)

  • ES6模块

    • 每个文件作为一个模块,每个模块拥有独立的作用域。

    • 通过export导出

      1. 命名导出:exports { a, b }; 2. 默认导出:exports default a; (只能导出一个对象)

    • 通过import导入,默认导出的变量,导入时可以随意命名,命名导出方式,导入时名称必须一致,可以使用as 重命名。

  • CommonJS 与ES6模块的区别

    • CommonJS 对模块依赖的解决是动态的,而ES6模块是静态的。模块导入时:CommonJS是值拷贝,而ES6则是只读的动态映射。

    • CommonJS引入模块时可以动态指定,例如使用if等条件语句引入不同的模块。

    • 动态:模块的依赖关系建立在代码运行阶段

    • 静态:模块的依赖关系建立在代码编译阶段

  • ES6模块相比CommonJS的优势

    • 死代码检测和排除:通过静态分析工具检测出哪些模块没有被调用过。从而在打包时去掉未使用的模块,以减少资源包的体积。

    • 模块变量类型检查:JS是动态类型语言,不会在代码执行前检查类型错误,ES6模块属于静态类型模块,有助于确保模块之间的传递的值或者接口类型是正确的。

    • 编译器优化:CommonJS无论采用哪种方式,导入的都是一个对象,而ES6模块直接导入变量,减少应用层级,程序效率更高。 

 


 CommonJS 与 ES6 模块化基础语法


prototype和__proto__区别​

1.关于prototype

每个函数都有一个prototype属性,该属性是一个指针,指向一个原型对象,这个对象包含所有实例共享的属性和方法。原型对象都有一个constructor属性,这个属性指向所关联的构造函数。使用这个对象的好处就是可以让所有实例对象共享它所拥有的属性和方法。这个属性只用js中的类(或者说能够作为构造函数的对象)才会有。

2.__proto__

每个实例对象都有一个__proto__属性,用于指向构造函数的原型对象(protitype)。proto属性是在调用构造函数创建实例对象时产生的。该属性存在于实例和构造函数的原型对象之间,而不是存在于实例与构造函数之间。

3.instance.constructor = Function

4.instance.__proto__ == Function.prototype

5.Function.prototype.constructor == Function

 

 


关于原型链的几个方法:

  • instanceof 运算符 (object instanceof constructor) 用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上;
  • prototypeObj.isPrototypeOf(object) 用来测试一个对象是否存在于另一个对象的原型链上prototypeObj.isPrototypeOf(object)
  • Object.getPrototypeOf(object) 返回指定对象的原型(内部[[Prototype]]属性的值);
  • obj.hasOwnProperty(prop) 返回一个布尔值,指示对象自身属性中是否具有指定的属性,会忽略掉那些从原型链上继承到的属性;
  • in 运算符 (prop in object)返回一个布尔值,指示指定的属性是否在指定的对象或其原型链中;
  • for ... in   以任意顺序迭代一个对象的除Symbol以外的可枚举属性,包括继承的可枚举属性;
  • Object.keys() 会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致;

备注: isPrototypeOf() 与 instanceof 运算符不同。在表达式 "object instanceof AFunction"中,object 的原型链是针对 AFunction.prototype 进行检查的,而不是针对 AFunction 本身。

 


 关于XMLHttpRequest对象的readyState与status的几种状态码:

  • readyState的五种状态
    • 0 (未初始化): (XMLHttpRequest)对象已经创建,但还没有调用open()方法;

    • 1 (载入):已经调用open() 方法,但尚未发送请求;

    • 2 (载入完成): 请求已经发送完成;

    • 3 (交互):可以接收到部分响应数据;

    • 4 (完成):已经接收到了全部数据,并且连接已经关闭。

  • status的状态
    • 1xx——信息类,表示收到Web浏览器请求,正在进一步的处理中。如,100:客户必须继续发出请求;101:客户要求服务器根据请求转换HTTP协议版本

    • 2xx——成功,表示用户请求被正确接收,理解和处理。例如,200:OK;201:提示知道新文件的URL

    • 3xx——重定向,表示请求没有成功,客户必须采取进一步的动作。如,300:请求的资源可在多处得到;301:删除请求数据

    • 4xx——客户端错误,表示客户端提交的请求有错误。如,404:NOT Found,意味着请求中所引用的文档不存在。

    • 5xx——服务器错误,表示服务器不能完成对请求的处理。如,500,服务器产生内部错误


 几种特殊的运算符

运算符 描述 例子 等同于 结果 十进制  
& 5 & 1 0101 & 0001 0001 1 如果两位都是 1 则设置每位为 1
| 5 | 1 0101 | 0001 0101 5 如果两位之一为 1 则设置每位为 1
~ ~ 5 ~0101 1010 10 反转所有位
^ 异或 5 ^ 1 0101 ^ 0001 0100 4 如果两位只有一位为 1 则设置每位为 1
<< 左移位运算 5 << 1 0101 << 1 1010 10 在移位运算过程中,符号位始终保持不变。如果右侧空出位置,则自动填充为 0;超出 32 位的值,则自动丢弃。
>> 有符号右位移 5 >> 1 0101 >> 1 0010 2 与左移运算操作相反,它把 32 位数字中的所有有效位整体右移,再使用符号位的值填充空位。移动过程中超出的值将被丢弃。
>>> 无符号右移位运算 5 >>> 1 0101 >>> 1 0010 2

它把无符号的 32 位整数所有数位整体右移。

对于无符号数或正数右移运算,无符号右移与有符号右移运算的结果是相同的。

对于负数来说,无符号右移将使用 0 来填充所有的空位,同时会把负数作为正数来处理,所得结果会非常大所以,使用无符号右移运算符时要特别小心,避免意外错误。

 


JS的基本数据类型

  • string(字符串)
  • boolean(布尔值)
  • number(数字)
  • symbol(符号)
  • null(空值)
  • undefined(未定义)

引用类型

  • object(对象)
  • array(数组)
  • function(函数)

关于闭包

闭包函数:
  1. 函数内部定义函数
  2. 内部函数使用了非它作用域的变量。
闭包函数作用:
  1. 延长变量的生命周期,局部变量会常驻在内存中
  2. 变量私有化,每次外部函数执行的时候,外部函数的引用地址不同,都会重新创建一个新的地址

JavaScript的可迭代/可遍历(iterable)对象

Iterator 接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即for...of循环。当使用for...of循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口。

一种数据结构只要部署了 Iterator 接口,我们就称这种数据结构是“可遍历的”(iterable)。

ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。

Symbol.iterator属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。至于属性名Symbol.iterator,它是一个表达式,返回Symbol对象的iterator属性,这是一个预定义好的、类型为 Symbol 的特殊值,所以要放在方括号内

Object的原型没有实现 Symbol.iterator 所以不算做可迭代对象。

原生具备 Iterator 接口的数据结构如下:

  • Array 数组
  • String 字符串
  • Map
  • Set
  • arguments 
  • TypedArray 如 Int8Array、BigInt64Array
  • NodeList 
  • Generators ES6新增

关于隐式类型转换

  • 任意的数据类型 + "" 即转成string字符串类型(+号是字符串拼接)
  • 任意数据类型 -*/ 0 即转成Number数据类型(-*/是算法)

关于函数传参

  • 当传入参数的为基本类型(number, string, boolean)时,通过拷贝值进行传递,不会对传参产生影响;
  • 当传入参数为引用类型时, 传入内存地址,对形参的修改,相当于对原值的修改;

关于函数内置参数arguments

  • 函数的内置对象;
  • 有length,可以被遍历;
  • 无pop、push等数组方法,arguments 本质上是对象,不是Array,是伪数组;
  • 可以结合...解构赋值语法生成数组;

关于变量提示和函数提升

通常JS引擎会在正式执行之前先进行一次预编译,在这个过程中,首先将变量声明及函数声明提升至当前作用域的顶端,然后进行接下来的处理。

变量和函数都存在提升,但是函数提升的优先级大于变量提升

关于let声明的变量

使用let声明的变量,既不会发生变量提升,同时又存在“暂时性死区”。所以在块级作用域内,如果使用let声明一个变量,那么该变量在声明之前是不可用的,否则会抛出ReferenceError异常。


关于页面的性能指标详解

  • 白屏时间(first Paint Time)——用户从打开页面开始到页面开始有东西呈现为止
  • 首屏时间——用户浏览器首屏内所有内容都呈现出来所花费的时间
  • 用户可操作时间(dom Interactive)——用户可以进行正常的点击、输入等操作,默认可以统计domready时间,因为通常会在这时候绑定事件操作
  • 总下载时间——页面所有资源都加载完成并呈现出来所花的时间,即页面 onl oad 的时间

“==”运算符(两个操作数的类型不相同时)(“==”运算符比较“喜欢”Number类型)

  • 如果一个值是null,另一个值是undefined,则它们相等
  • 如果一个值是数字,另一个值是字符串,先将字符串转换为数学,然后使用转换后的值进行比较。
  • 如果其中一个值是true,则将其转换为1再进行比较。如果其中的一个值是false,则将其转换为0再进行比较。
  • 如果一个值是对象,另一个值是数字或字符串,则将对象转换为原始值,再进行比较。

对象到数字的转换

  • 如果对象具有valueOf()方法,后者返回一个原始值,则JavaScript将这个原始值转换为数字(如果需要的话)并返回一个数字。
  • 否则,如果对象具有toString()方法,后者返回一个原始值,则JavaScript将其转换并返回。(对象的toString()方法返回一个字符串直接量(作者所说的原始值),JavaScript将这个字符串转换为数字类型,并返回这个数字)。
  • 否则,JavaScript抛出一个类型错误异常。

空数组转换为数字0

  • 数组继承了默认的valueOf()方法,这个方法返回一个对象而不是一个原始值。
  • 数组到数学的转换则调用toString()方法。空数组转换为空字符串,空字符串转换为数字0。

几个常见的事件的方法

  • preventDefault()    取消事件默认行为,如阻止点击提交按钮时对表单的提交(本题中click并没有什么默认行为)
  • stopImmediatePropagation()   取消事件冒泡同时阻止当前节点上的事件处理程序被调用,影响当前的事件***
  • stopPropagation()   取消事件冒泡,不影响事件***
  • cancelBubbe()     取消事件冒泡
  • returnValue()      取消事件默认行为

关于事件捕获和事件冒泡

  • 事件监听会产生冒泡或者捕捉事件
  • addEventListener 的第三个参数是用来设置回调函数是在捕获时触发,还是在冒泡时触发,默认为false,即冒泡时触发

关于String 字符串字面量和对象的关系

  • JS 中值的类型分为原始值类型和对象类型。原始值类型包括 number, string, boolean, null 和 undefined;对象类型即 object。首先原始值类型它就不是对象
  • 另外,要注意 'hello' 和 new String('hello') 的区别,前者是字符串字面值,属于原始类型,而后者是对象。用 typeof 运算符返回的值也是完全不一样的:
typeof 'hello';  // 'string'
typeof new String('hello');  // 'object'
  • 之所以很多人分不清字符串字面值和 String 对象,归根结底就是 JS 的语法对你们太过纵容了。当执行 'hello'.length 时,发现可以意料之中的返回 5,你们就觉得 'hello' 就是 String 对象,不然它怎么会有 String 对象的属性。其实,这是由于 JS 在执行到这条语句的时候,内部将 'hello' 包装成了一个 String 对象,执行完后,再把这个对象丢弃了,这种语法叫做 “装箱”,在其他面向对象语言里也有(如 C#)。

关于call、apply、bind

  • call和apply的作用都是改变this作用域;
  • call和apply使用方法基本相同,唯一不同之处就是它们的参数规则:call方法接受一个参数列表,而apply方法接受一个包含多个参数的数组;
  • bind 传参方式与call相同,返回改变this作用域之后的函数;

关于JS 声明变量

  • 在严格模式下,变量必须先声明,然后才能使用。

  • 在非严格模式下,JavaScript 允许不声明变量就直接为其赋值,这是因为 JavaScript 解释器能够自动隐式声明变量。隐式声明的变量总是作为全局变量使用。


关于JS 数据类型占位

  • 基本类型变量用八字节内存,存储基本数据类型(数值、布尔值、null和未定义)的值
  • 引用类型变量则只保存对对象、数组和函数等引用类型的值的引用(即内存地址);
  • 中文字符占2个字节(byte) 
  • 英文字符占1个字节(byte)

1字节(byte)=8位(bits)

js 中所有数字都是以双精度浮点数来存储的。即64位;但当任何数字在进行位运算时js 内部会将其转换成32位有符号整型。


关于前置自增和后置自增

  • 前置递增效率更高,后置式递增要拷贝一个临时对象;
  • 前置自增先自加再返回原值;
  • 后置自增先返回原值后自加;

Array的一些方法

  • push() 向数组的末尾添加一个或更多元素,并返回新的长度;
  • pop() 移除最后一个数组元素;
  • unshift() 向数组的开头添加一个或更多元素,并返回新的长度;
  • shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值;
  • splice() 从数组中添加或删除元素;
  • slice() 选取数组的一部分,并返回一个新数组;
  • concat()方法数组拼接,返回新数组。可以扁平化一个数组,但不会递归扁平化数组的数组

关于跨域

CORS(Corss-Origin Resource Sharing,跨资源共享),基本思想是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应的成功或失败。即给请求附加一个额外的Origin头部,其中包含请求页面的源信息(协议、域名和端口),以便服务器根据这个头部决定是否给予响应。

  1. document.domain:解决浏览器中不同域的框架之间是不能进行js的交互操作的问题;
  2. window.name:利用在一个窗口的生命周期内,窗口载入的所有的页面都是共享一个window.name的特性;
  3. window.postMessage:向其它的window对象发送消息;
  4. 图像Ping
  5. Jsonp:利用页面可以引入不同域上的js脚本文件这个特性;
  6. Comet(如sse)
  7. WebSocket

关于运算符的优先级

  • 算数操作符 > 比较操作符 > 逻辑操作符(&& > ||) > “=”赋值符号

关于null、undefined、NaN的一些知识

  • null == null
  • null === null
  • undefined == undefined
  • undefined === undefined
  • null == undefined
  • null !== undefined
  • NaN != NaN
  • Number(undefined) => NaN
  • Number(null) => 0
  • +0 === -0
  • Object.is(),其行为与===基本一致,不过有两处不同 +0不等于-0NaN等于自身。
  • ES7中新增的数组实例方法,includes()方法认为NaN等于自身
  • 向 Set 数据结构中加入值时认为NaN等于自身
  • indexOf方法无法识别数组的NaN成员

关于delete方法

  • 任何使用 var 声明的属性不能从全局作用域或函数的作用域中删除。
    • 这样的话,delete操作不能删除任何在全局作用域中的函数(无论这个函数是来自于函数声明或函数表达式)
    • 除了在全局作用域中的函数不能被删除,在对象(object)中的函数是能够用delete操作删除的。
  • 任何用letconst声明的属性不能够从它被声明的作用域中删除。
  • 不可设置的(Non-configurable)属性不能被移除。这意味着像MathArrayObject内置对象的属性以及使用Object.defineProperty()方法设置为不可设置的属性不能被删除。
  • 隐式全局变量 和 eval中定义的变量 是可以删除的
var a = b =10;// 此处的b就是隐式的全局变量,是可以通过delete删除的
delete b;//true
delete a;//false

eval('var aa=10'); // eval中定义的变量
Object.getOwnPropertyDescriptor(window,'aa');//value: 10, writable: true, enumerable: true, configurable: true}
delete aa;//true

关于函数声明和表达式

函数声明语法:

  • function sum(num1,num2){return num1+num2}
  • 函数声明可以被提前;

函数表达式定义:

  • var sum = function(num1,num2){return num1+num2};
  • var sum = new Function("num1","num2","return num1+num2"); // Function构造函数可以接受任意数量的参数,但最后一个参数始终被看成函数体,注意函数表达式定义函数的方法与声明其他变量时一样需要加分号。
  • 表达式方式定义函数,会使得函数式定义的名字失效
  • 函数表达式不能被提前;

 关于严格模式

  • 不允许未声明赋值;
  • 严格模式下的this在函数体内不会默认指向window,而是指向undefined;
  • 立即执行函数的this取决于上下文,不再指向window;
  • 严格模式下,setTimeout中函数的this指向的window(与普通函数不同);
  • 函数不允许重名参数;

常用的正则表达式特殊字符

字符 描述
\n 匹配一个换行符
\r 匹配一个回车符
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
* 匹配前面的子表达式零次或多次
+ 匹配前面的子表达式一次或多次
? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符
{n} n 是一个非负整数。匹配确定的 n 次。
{n,} n 是一个非负整数。至少匹配n 次。
{n,m} m 和 n 均为非负整数,其中 n <= m。最少匹配 n 次且最多匹配 m 次。
\b 匹配一个单词边界,即字与空格间的位置。
\B 非单词边界匹配
\d 匹配一个数字字符。等价于 [0-9]。
\D 匹配一个非数字字符。等价于 [^0-9]。
\w 匹配字母、数字、下划线。等价于'[A-Za-z0-9_]'。
\W 匹配非字母、数字、下划线。等价于 '[^A-Za-z0-9_]'。
\1 指向第一个分组

关于数组内的空位

  • ES5 的 forEach(), filter(), reduce(), every() 和some()都会跳过空位
  • map()会跳过空位,但会保留这个值
  • join()和toString()会将空位视为undefined,而undefined和null会被处理成空字符串。
  • ES6 中都会将空位当做undefined

变量命名规则

  • 变量命名必须以字母、下划线”_”或者”$”为开头。其他字符可以是字母、_、美元符号或数字。
  • 变量名中不允许使用空格和其他标点符号,首个字不能为数字。
  • 变量名长度不能超过255个字符。
  • 变量名区分大小写。(javascript是区分大小写的语言)
  • 变量名必须放在同一行中
  • 不能使用脚本语言中保留的关键字、保留字、true、false 和 null 作为标识符。

关于赋值操作

重点:赋值操作先定义变量(从左到右),再进行赋值(从右到左) 

let obj = { num1: 117 }    把obj放在栈里,把 { num1:117} 放在堆里,让obj指向堆里的 { num1:117 }    let res = obj;   把res放在栈里,把res也指向堆里的 { num1:117 }        obj.child  =  obj  =  { num2: 935 };   重点:赋值操作先定义变量(从左到右),再进行赋值(从右到左)        定义变量    obj.child,给堆里的{ num1:117 }加一个child属性,得{num1:117,child:undefined}      定义变量    obj,之前在栈里的obj     
赋值    obj = { num2: 935 },把{ num2: 935 }放在堆里,把栈里的obj指向堆里的{ num2: 935 }     
赋值    obj.child = obj,把堆里的 {num1:117,child:undefined} 的child指向  {num2: 935}     
     从最后一张图可看出此时:              obj = { num2: 935 }              res = { num1: 117,child:{ num2: 935 }  }

关于构造函数和new运算符

使用new运算符调用函数时,会返回一个对象

  • 如果构造函数没有return语句,则默认返回原型为Func.prototype的对象;
  • 如果构造函数return返回了一个对象,将该对象作为new的结果返回;

关于parseInt

  • parseInt(string,raix)函数有两个参数,第二个参数指的就是进制,这个参数小于2或者大于36的时候,都会返回NaN ;
    • 一般都是省略这个参数的,这个时候就是默认为10进制
    • 第二个参数使用0的时候也是使用十进制
    • 如果第一个参数前缀使用0x/0X则表示使用16进制,如果第一个参数使用了0x表示十六进制,那么第二个参数设置了值也无效
  • parseInt解析string字符串,只会解析从第一个字符开始知道不是数字的字符部分;
    • 当字符串中间存在非数字,那么就只解析前面是数字的部分字符
    • 如果字符串中第一个字符就不是数字,那么返回NaN

关于NaN

  • NaN == NaN // false
  • NaN === NaN // false
  • indexOf方法无法识别数组的NaN成员
    [NaN].indexOf(NaN) // -1
  •  Set 数据结构中加入值时认为NaN等于自身
    let set = new Set();
    set.add(NaN);
    set.add(NaN);
    console.log(set); // Set {NaN}
  • Object.is()方法认为NaN等于NaN
    Object.is(NaN, NaN) // true
    +0 === -0 //true
    Object.is(+0, -0) // false
  • ES7中新增的数组实例方法,includes()方法认为NaN等于自身
    [1, 2, NaN].includes(NaN) // true

关于正则修饰符

修饰符 含义 描述
i ignore - 不区分大小写 将匹配设置为不区分大小写,搜索时不区分大小写: A 和 a 没有区别。
g global - 全局匹配 查找所有的匹配项。
m multi line - 多行匹配 使边界字符 ^ 和 $ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾。
s 特殊字符圆点 . 中包含换行符 \n 默认情况下的圆点 . 是匹配除换行符 \n 之外的任何字符,加上 s 修饰符之后, . 中包含换行符 \n。

关于es6 export import 语句

export {name1,name2, …,nameN};
export {variable1asname1,variable2asname2, …,nameN};
export let name1,name2, …,nameN; // also var
export let name1= …,name2= …, …,nameN; // also var, const
export expression;
export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export {name1as default, … };
export * from …;
export {name1,name2, …,nameN} from …;
export {import1asname1,import2asname2, …,nameN} from …;

import defaultMember from "module-name";
import * as name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import defaultMember, { member [ , [...] ] } from "module-name";
import defaultMember, * as name from "module-name";
import "module-name";

关于JS 模块化

主流的模块化包括CommonJS,AMD,CMD等

  • Nodejs使用CommonJS模块化规范,CommonJS用同步方式加载模块。
  • AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。 AMD也采用require()语句加载模块,但是不同于CommonJS。 主要有两个Javascript库实现了AMD规范:require.js和curl.js。
  • CMD 与AMD类似,是 SeaJS 在推广过程中对模块定义的规范化产出。 
  • ES6 Module 

AMD和CMD的区别:
1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行
2. CMD 推崇依赖就近,AMD 推崇依赖前置

// CMD
define(function(require, exports, module) {
    var a = require('./a')
    a.doSomething()
    // 此处略去 100 行
    var b = require('./b') // 依赖可以就近书写
    b.doSomething()
    // ...
})

// AMD 默认推荐的是
define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
    a.doSomething()
    // 此处略去 100 行
    b.doSomething()
    ...
})

ES6 模块的特征:

  • 严格模式:ES6 的模块自动采用严格模式;
  • import read-only特性: import的属性是只读的,不能赋值,类似于const的特性
  • export/import提升: import/export必须位于模块顶级,不能位于作用域内;其次对于模块内的import/export会提升到模块顶部,这是在编译阶段完成的
  • import命令会被 JavaScript 引擎静态分析,在编译时就引入模块代码,而不是在代码运行时加载,所以无法实现条件加载。也正因为这个,使得静态分析成为可能。

ES6 Module 与 CommonJS模块的区别:

  • CommonJS输出的是一个值的拷贝,ES6 Module输出的是值的引用
  • CommonJS是运行时加载,ES6 Module是编译时输出接口;

总结:

  1. AMD/CMD/CommonJs 是js模块化开发的规范,对应的实现是require.js/sea.js/Node.js

  2. CommonJs 主要针对服务端,AMD/CMD/ES Module主要针对浏览器端,容易混淆的是AMD/CMD。(顺便提一下,针对服务器端和针对浏览器端有什么本质的区别呢?服务器端一般采用同步加载文件,也就是说需要某个模块,服务器端便停下来,等待它加载再执行。这里如果有其他后端语言,如java。而浏览器端要保证效率,需要采用异步加载,这就需要一个预处理,提前将所需要的模块文件并行加载好。)

  3. AMD/CMD区别,虽然都是并行加载js文件,但还是有所区别,AMD是预加载,在并行加载js文件同时,还会解析执行该模块(因为还需要执行,所以在加载某个模块前,这个模块的依赖模块需要先加载完成);而CMD是懒加载,虽然会一开始就并行加载js文件,但是不会执行,而是在需要的时候才执行。

  4. AMD/CMD的优缺点.一个的优点就是另一个的缺点, 可以对照浏览。
    AMD优点:加载快速,尤其遇到多个大文件,因为并行解析,所以同一时间可以解析多个文件。
    AMD缺点:并行加载,异步处理,加载顺序不一定,可能会造成一些困扰,甚至为程序埋下大坑。

    CMD优点:因为只有在使用的时候才会解析执行js文件,因此,每个JS文件的执行顺序在代码中是有体现的,是可控的。

    CMD缺点:执行等待时间会叠加。因为每个文件执行时是同步执行(串行执行),因此时间是所有文件解析执行时间之和,尤其在文件较多较大时,这种缺点尤为明显。(PS:重新看这篇文章,发现这里写的不是很准确。确切来说,JS是单线程,所有JS文件执行时间叠加在AMD和CMD中是一样的。但是CMD是使用时执行,没法利用空闲时间,而AMD是文件加载好就执行,往往可以利用一些空闲时间。这么来看,CMD比AMD的优点还是很明显的,毕竟AMD加载好的时候也未必就是JS引擎的空闲时间!)

  5. CommonJS 和 ES Module 区别:CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用

  6. 如何使用?CommonJs 的话,因为 NodeJS 就是它的实现,所以使用 node 就行,也不用引入其他包。AMD则是通过<script>标签引入require.js,CMD则是引入sea.js


关于Math.round() 四舍五入规则(原来的数字加上0.5,再向下取整)

  • 如果参数的小数部分大于0.5,四舍五入到相邻的绝对值更大的整数
  • 如果参数的小数部分小于0.5,四舍五入到相邻的绝对值更小的整数
  • 如果参数的小数部分等于0.5,四舍五入到相邻的在正无穷(+∞)方向上的整数

注意调用数字的toString方法

数字后面.会被解析为小数点

2..toString()
2 .toString()
(2).toString()

关于Symbol

Symbol为ES6新增的基本数据类型,表示独一无二的值。

Symbol内部没有construtor构造器,不能使用new关键字创建

Symbol()函数会返回symbol类型的值,每个从Symbol()返回的symbol值都是唯一的。

Symbol.for() 返回由给定的 key 找到的 symbol,否则就是返回新创建的 symbol


ECMAScript标准下的全局函数

编码相关:     escape()、unescape()、encodeURI()、decodeURI()、     encodeURIComponent()、decodeURIComponent() 数据处理:     Number()、String() 数字相关:     isFinite()、isNaN()、parseFloat()、parseInt() 特殊:     eval()

关于对象的属性描述符

defineProperty为对象设置属性后,该属性的描述符writable、configurable以及enumberable默认为false。

  • value:设置该属性的属性值,默认值为undefined
  • writable:表示能否修改属性的值,也就是说该属性是可写的还是只读的,默认为true(可写)
  • enumerable:表示改属性是否可遍历,默认为true(可遍历)
  • configurable:表示能否通过 delete 删除属性、能否修改属性的特性,或者修改属性的访问器属性,默认为true(可配置)
  • get:get是一个函数,表示该属性的取值函数(getter),默认为undefined
  • set:get是一个函数,表示该属性的存值函数(setter),默认为undefined  如果只有get而没有对应的set,该属性是无法进行赋值的

JS Array Sort排序原理

arr.sort((a, b) => a - b) 递增排序

arr.sort((a, b) => b - a) 递减排序


关于void运算符

void是一元运算符,它出现在操作数之前,操作数可以是任意类型,操作数会照常计算,但忽略计算结果并返回undefined。由于void会忽略操作数的值,因此在操作数具有副作用的时候使用void来让程序更具语义

常见用法:

1.替代undefined

由于undefined并不是一个关键字,其在IE8-浏览器中会被重写,在高版本函数作用域中也会被重写;所以可以用void 0 来替换undefined

2.客户端URL

这个运算符最常用在客户端URL——javascript:URL中,在URL中可以写带有副作用的表达式,而void则让浏览器不必显示这个表达式的计算结果。例如,经常在HTML代码中的<a>标签里使用void运算符

<a href="javascript:void window.open();">打开一个新窗口</a>

3.阻止默认事件 

阻止默认事件的方式是给事件置返回值false // 一般写法 <a href="http://example.com" onclick="f();return false;">文字</a> // 使用void运算符可以取代上面写法 <a href="javascript:void(f())">文字</a>

Request Header 和 Response Header

1.请求头

  • GET(请求的方式) /hello.html(请求的目标资源) HTTP/1.1(请求采用的协议和版本号)
  • Accept: */*(客户端能接收的资源类型)
  • Accept-Language: en-us(客户端接收的语言类型)
  • Connection: Keep-Alive(维护客户端和服务端的连接关系)
  • Host: localhost:8080(连接的目标主机和端口号)
  • Referer: http://localhost/links.asp(告诉服务器我来自于哪里)
  • User-Agent: Mozilla/4.0(客户端版本号的名字)
  • Accept-Encoding: gzip, deflate(客户端能接收的压缩数据的类型)
  • If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT(缓存时间) 
  • Cookie(客户端暂存服务端的信息)
  • Date: Tue, 11 Jul 2000 18:23:51 GMT(客户端请求服务端的时间)

2.响应头

  • HTTP/1.1(响应采用的协议和版本号) 200(状态码) OK(描述信息)
  • Access-Control-Allow-Origin: * 解决跨域
  • Location: http://www.baidu.com(服务端需要客户端访问的页面路径)
  • Server:apache tomcat(服务端的Web服务端名)
  • Content-Encoding: gzip(服务端能够发送压缩编码类型)
  • Content-Length: 80(服务端发送的压缩数据的长度)
  • Content-Language: zh-cn(服务端发送的语言类型)
  • Content-Type: text/html; charset=GB2312(服务端发送的类型及采用的编码方式)
  • Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT(服务端对该资源最后修改的时间)
  • Refresh: 1;url=http://www.it315.org(服务端要求客户端1秒钟后,刷新,然后访问指定的页面路径)
  • Content-Disposition: attachment; filename=aaa.zip(服务端要求客户端以下载文件的方式打开该文件)
  • Transfer-Encoding: chunked(分块传递数据到客户端)  
  • Set-Cookie:SS=Q0=5Lb_nQ; path=/search(服务端发送到客户端的暂存数据)
  • Expires: -1//3种(服务端禁止客户端缓存页面数据)
  • Cache-Control: no-***(服务端禁止客户端缓存页面数据)  
  • Pragma: no-***(服务端禁止客户端缓存页面数据)   
  • Connection: close(1.0)/(1.1)Keep-Alive(维护客户端和服务端的连接关系)  
  • Date: Tue, 11 Jul 2000 18:23:51 GMT(服务端响应客户端的时间)

关于Class类

  • 静态方法本身不能使用实例对象来调用
  • 静态方法只能由类进行调用,实例方法只能由实例对象进行调用
  • 由于类内部的静态方法和实例方法调用者不通,允许重名

关于箭头函数

  1. 箭头函数没有自己的this对象;
    • 对于普通函数来说,内部的this指向函数运行时所在的对象;
    • 箭头函数内部的this就是定义时上层作用域中的this;因为对象不构成单独的作用域,导致对象的方法箭头函数定义时的作用域就是全局作用域。
    • 箭头函数内部的this指向是固定的,相比之下,普通函数的this指向是可变的。
  2. 不可以当作构造函数,也就是说,不可以对箭头函数使用new命令,否则会抛出一个错误;
  3. 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替;
  4. 不可以使用yield命令,因此箭头函数不能用作 Generator 函数;

JS常见的继承方式:

  • 包括原型链继承
  • 借用构造函数继承
  • 组合继承
  • 原型式继承
  • 寄生式继承
  • 寄生组合式继承
  • 以及ES6新增的class继承

null 和 undefined 测试相等性

  • null  == undefined
  • 在测试相等性前,不能将null和undefined转换成其他任何值
  • 因此null和undefined与其他任何类型测试相等性都为false

常见的不支持冒泡的事件

  ①focus        ②blur        ③mouseenter        ④mouseleave        ⑤load        ⑥unload        ⑦resize

妈(mouseenter)妈(mouseleave)不(blur)让(resize)你(unload)浪(load)费(foucus)


关于 || 和 && 判断符

  • 对于 || 来说,如果第一个条件判断结果为 true 就返回该操作数的值,如果为 false 就判断下一个操作数,迭代下去,直到存在条件判断结果为真的,如果最后一个都不是真,就返回最后一个。
  • 对于 && 来说,如果“第一个(或者当前)”条件判断结果为 true 就去判断下一个操作数,一旦“第一个(或者当前)”为false,就返回该操作数。如果所有条件都为真,就返回最后一个操作数的值。
  • || 和 && 返回它们其中一个操作数的值,而非条件判断的结果。

 

标签:函数,对象,NaN,undefined,杂谈,JS,模块,属性
From: https://www.cnblogs.com/ligd2022/p/16996119.html

相关文章