// 数组
var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
0 in trees // 返回true
3 in trees // 返回true
6 in trees // 返回false
// -------------------------attention----------------------
"bay" in trees // 返回false (必须使用索引号,而不是数组元素的值)
// -------------------------attention----------------------
"length" in trees // 返回true (length是一个数组属性)
var mycar = {make: "Honda", model: "Accord", year: 1998};
delete mycar.make;
"make" in mycar; // 返回false
var mycar = {make: "Honda", model: "Accord", year: 1998};
mycar.make = undefined;
"make" in mycar; // 返回true
可以不指定任何参数,返回原数组
splice、slice、substr、substring
不太懂为什么???????
isFinite("0"); // true
Number.isFinite("0"); // false
// good
const itemsCopy = [...items];
Array.from
const foo = document.querySelectorAll('.foo');
const nodes = Array.from(foo);
percent code
编码原因: Url中有些字符会引起歧义
编码格式:ASCII码
编码方式: %加上两位十六进制字符
encodeURI作对完整的URI进行编码,encodeURIComponent对URI的一个组件进行编码,所以encodeURI的安全字符更多,编码范围小。
url的三个js编码函数escape(),encodeURI(),encodeURIComponent()简介
网络标准RFC 1738做了硬性规定:
“只有字母和数字[0-9a-zA-Z]、一些特殊符号“$-_.+!*’(),”[不包括双引号]、以及某些保留字,才可以不经过编码直接用于URL。”
escape()不能直接用于URL编码,它的真正作用是返回一个字符的Unicode编码值。比如"春节"的返回结果是%u6625%u8282,escape()不对"+"编码(网页在提交表单的时候,如果有空格,则会被转化为+字符。服务器处理数据的时候,会把+号处理成空格。),主要用于汉字编码,现在已经不提倡使用。
encodeURI()是Javascript中真正用来对URL编码的函数。 编码整个url地址(编码后,它输出符号的utf-8形式,并且在每个字节前加上%),但对特殊含义的符号"; / ? : @ & = + $ , #"以及单引号,不进行编码。对应的解码函数是:decodeURI()。
encodeURIComponent() 能编码"; / ? : @ & = + $ , #"这些特殊字符。对应的解码函数是decodeURIComponent()。
file方式打开无效,而且链接是http协议的无效
save canvas as image
ES6新特性:使用export和import实现模块化
null == "" // false
undefined == "" // false
null == 0 // false
undefined == 0 // false
Number(null) // 0
Number(undefined) // NaN
"" == 0 // true
关于==
和===
绝大多数场合应该使用 === ,只有检测 null/undefined 的时候可以使用 x == null ,因为通常我们不区分 null 和 undefined ,即将 x == null 作为 x === null || x === undefined 的缩写。
input:-webkit-autofill 导致chrome的输入框背景颜色变成黄色
并没有什么卵用box-shadow
吧input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill {
-webkit-box-shadow: 0 0 0 1000px white inset;
}
How JavaScript Timers Work
setTimeout 的执行时间会大于(等待前一个函数执行完)等于设置时间,setInterval 则不一定,两次 interval 之间可能没有间隔,也可能某次被 drop 掉
Promise的队列与setTimeout的队列的有何关联?【优先级问题】
浏览器的内核是多线程的,它们在内核制控下相互配合以保持同步,一个浏览器至少实现三个常驻线程:javascript引擎线程,GUI渲染线程,浏览器事件触发线程。
- javascript引擎是基于事件驱动单线程执行的,JS引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行JS程序。
- GUI渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。但需要注意 GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。
- 事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeOut、也可来自浏览器内核的其他线程如鼠标点击、AJAX异步请求等,但由于JS的单线程关系所有这些事件都得排队等待JS引擎处理。(当线程中没有执行任何同步代码的前提下才会执行异步代码)
// 暴露
module.exports = myModule;
// 引用s
var myModule = require('myModule');
define(['myModule'], function(myModule) {
return something;
});
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['myModule', 'myOtherModule'], factory);
} else if (typeof exports === 'object') {
// CommonJS
module.exports = factory(require('myModule'), require('myOtherModule'));
} else {
// Browser globals (Note: root is window)
root.returnExports = factory(root.myModule, root.myOtherModule);
}
}(this, function (myModule, myOtherModule) {
// Methods
function notHelloOrGoodbye(){}; // A private method
function hello(){}; // A public method because it's returned (see below)
function goodbye(){}; // A public method because it's returned (see below)
// Exposed public methods
return {
hello: hello,
goodbye: goodbye
}
}));
从Chrome源码看浏览器如何构建DOM树
- 怪异模式 会模拟IE,同时CSS解析会比较宽松,例如数字单位可以省略
- 有限怪异模式 和 标准模式 的唯一区别在于在于对inline元素的行高处理不一样。
- 标准模式 将会让页面遵守文档规定
DOM树有一个最大的深度:maximumHTMLParserDOMTreeDepth,超过这个最大深度就会把它子元素当作父无素的同级节点,这个最大值是多少呢?512
总结oninput、onchange与onpropertychange事件的用法和区别
change事件:
事件触发取决于表格元素的类型(type)和用户对标签的操作:
和
的默认选项被修改时(通过点击或者键盘事件)
中的一个选项,从
标签选择了一个日期,通过
标签上传了一个文件,等 );
或者
的值进行编辑后。).input事件(IE9+):
不会触发propertychange 事件:
input 和 propertychange在 IE9 中都有个小BUG:通过右键菜单菜单中的 剪切 和 删除 命令删除内容的时候不会触发
删掉一个DOM结点,不需要手动去释放它的事件,但是DOM结点一旦存在一个引用,即使你把它remove掉了,GC也不会去回收,如下:
执行了window.gc之后并不会去回收p的内存空间以及它的事件。因为还存在一个p的变量指向它,而如果将p置为null,如下:
最后的GC就管用了,或者p离开了作用域:
自动销毁,p结点没有人引用了,能够自动GC回收。
__proto__
与 prototype
的爱恨情仇$.attr()
和$.prop()
jQuery函数attr()和prop()的区别
if (!n || typeof n !== 'number' || !isFinite(n) || n < 0 || Math.floor(n) !== Math.ceil(n)) {
console.warn(`argument n: ${n} is not a natural number`);
}
Object.prototype.toString.call(NaN) => '[object Number]'
Math.min.apply(null, array)
Math.max.apply(null, array)
【数组中不能有无法转化为数字的元素,否则会返回NaN】
Math.max.apply(null, [3,2,5,7,,3,,,9,7,87,78]) => NaN
缘由:原生addEventListener比jq的on慢了60倍, 为什么
参考:
结论:
jQuery.event.on
给元素构造了events
和handle
属性,一次性addEventListener
,事件触发则执行handle
调用jQuery.event.dispatch
调取绑定的事件函数 events[event.type]
进行操作。addEventListener
会去重,所以不断绑定新的函数时会受已绑定的函数数量影响;如果绑定的是相同的函数,addEventListener
效率会高不少。测试代码:
console.time('jq');
for(let i = 0; i < 10000; i++){
$('.food_pic').on('click', function () {
console.log(33333)
});
}
console.timeEnd('jq');
console.time('js');
for(let i = 0; i < 10000; i++){
$('.food_pic')[0].addEventListener('click', function () {
console.log(4444444)
});
}
console.timeEnd('js');
=============================>
// jq: 109.872ms
// js: 260.357ms
// 10000次 33333
// 10000次 4444444
var i;
function test1() {console.log(11111111)};
function test2() {console.log(22222222)};
console.time('jq');
for (i = 0; i < 10000; i += 1) $(document.querySelector('.food_pic')).on('click', test);
console.timeEnd('jq');
console.time('js');
for (i = 0; i < 10000; i += 1) document.querySelector('.food_pic').addEventListener('click', test);
console.timeEnd('js');
=============================>
// jq: 152.260ms
// js: 49.812ms
// 10000次 11111111
// 22222222
不能嵌套,
可以
module.exports 初始值为一个空对象 {}
exports 是指向的 module.exports 的引用
require() 返回的是 module.exports 而不是 exports
避免module.exports 指向新的对象时,exports 断开了与 module.exports 的引用
exports = module.exports = somethings
// 等价于:
module.exports = somethings
exports = module.exports
怎么理解for循环中用let声明的迭代变量每次是新的变量?
for (let x…)的循环在每次迭代时都为x创建新的绑定
for (let i = 0; i < 3; i++) {
setTimeout(() => {console.log("in for block", i)}, 1000);
}
// in for block 0
// in for block 1
// in for block 2
for 的 {}是 for () 的子作用域
for (let i = 0 /* 作用域a */; i < 3; console.log("in for expression", i), i++) {
let i; //这里没有报错,就意味着这里跟作用域a不同,换做k可能更好理解
console.log("in for block", i);
}
// in for block undefined
// in for expression 0
// in for block undefined
// in for expression 1
// in for block undefined
// in for expression 2
HTTP 协议入门
HTTP 1.1 管道机制:同一个TCP连接里,允许浏览器同时发出A请求和B请求,但是服务器还是按照顺序,先回应A请求,完成后再回应B请求
HTTP 1.0 Content-length: 用于区分数据包属于哪一个回应【因为管道机制可以一个TCP传多个回应】
HTTP 1.1 分块传输编码Transfer-Encoding: chunked
: 每个非空的数据块前有一个16进制的数值,表示这个块的长度。最后是一个大小为0的块,就表示本次回应的数据发送完了。
阶段 | 备注 |
---|---|
回调 | 同步、异步 |
Promise | resolve:then 的第一个回调会立即插入 microtask 队列,异步立即执行 reject:那么 then 的第二个回调会立即插入 microtask 队列 抛出的异常和未捕获的 reject 会传到末尾,通过 catch 接住 resolve 决议会被自动展开(reject 不会) 链式流,then 会返回一个新的 Promise,其状态取决于 then 的返回值 macrotask 中 throw 的 error 无法捕获【指setTimeout等】(reject 可以)、microtask 可以 |
Async Await | async await 是 generator 的语法糖 await 不会自动捕获异常,但是会自动中断函数 try catch 进行异常捕获 macrotask 中 throw 的 error 无法捕获【指setTimeout等】(reject 可以)、microtask 可以 |
Decorator 统一异常捕获 | 异常冒泡 |
兜底 | Node.js:监听全局错误 uncaughtException、unhandleRejection 浏览器:监听 window 全局错误 unhandlerejection、onrejectionhandled |
需删除content-type,这样才会正确的结束boundary
问题在于export default会利用babel编译
(function(module, exports) {
exports.A= 674;
}),
(function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "B", function() { return B; });
exports.A= 674;
var B= 1;
}),
Navigation Timing
a === 1 && a === 2 && a === 3
?var val = 0
Object.defineProperty(window, 'a', {
get: () => ++val
})
a === 1 && a === 2 && a === 3 && console.log('perfect?')
handler
如何使得console.log('c' in p, p.c); // false, 37
?
let handler = {
get: function(target, name){
return name in target ? target[name] : 37;
}
};
let p = new Proxy({}, handler);
concat方法创建一个新的数组,原始数组和新数组都引用相同的对象。
var num1 = [[1]];
var num2 = [2, [3]];
var nums = num1.concat(num2);
console.log(nums);
// results in [[1], 2, [3]]
// modify the first element of num1
num1[0].push(4);
console.log(nums);
// results in [[1, 4], 2, [3]]
// 改变数组本身的循环测试
var test = [1]
for (i = 0; i < test.length; i++) {
console.log('--------i', i)
test.push(i + 1)
if (i >= 5) {
break
}
}
// --------i 0
// --------i 1
// --------i 2
// --------i 3
// --------i 4
// --------i 5
var test = [1]
for (i of test) {
console.log('--------i', i)
test.push(i + 1)
if (i >= 5) {
break
}
}
// --------i 1
// --------i 2
// --------i 3
// --------i 4
// --------i 5
var test = [1]
test.forEach(function(i) {
console.log('--------i', i)
test.push(i + 1)
if (i >= 5) {
return
}
})
// --------i 1
decodeURIComponent("%") ----->Uncaught URIError: URI malformed
decodeURIComponent("%25") ----->%
/^(https|http):$/
全匹配http:
或者https:
/^[https:|http:]$/
实际匹配/^[htps:|]$/
Referer: 25
var | let、const |
---|---|
没有块级作用域 | 有块级作用域 |
var c = [3, 6, 2, 8]
c.sort(function(a, b) {console.log(a, b)}) // a为后面一个,b为前面一个
// 6 3
// 2 6
// 8 2
// 去重
[...new Set(array)]
Array.from(new Set(array))
[...new Set('ababbc')].join('') // "abc"
map
weakSet:
// 保证了Foo的实例方法,只能在Foo的实例上调用
const foos = new WeakSet()
class Foo {
constructor() {
foos.add(this)
}
method () {
if (!foos.has(this)) {
throw new TypeError('Foo.prototype.method 只能在Foo的实例上调用!');
}
}
}
var a = new Boolean(false);
var b = a && true;
console.log(b); //true