当执⾏ JS 代码时,会⽣成执⾏环境,只要代码不是写在函数中的,就是在全局执⾏环境中,函数中的代码会产⽣函数执⾏环
境,只此两种执⾏环境
b() // call b
console.log(a) // undefined
var a = 'Hello world'
function b() {
console.log('call b')
}
这是因为函数和变量提升的原因。通常提升的解释是说将声明的代码移动到了顶部,这其实没有什么错误,便于⼤家理解。但是更准确
的解释应该是:在⽣成执⾏环境时,会有两个阶段。第⼀个阶段是创建的阶段,JS 解释器会找出需要提升的变量和函
数,并且给他们提前在内存中开辟好空间,函数的话会将整个函数存⼊内存中,变量只声明并且赋值为 undefined ,所以在第⼆个阶
段,也就是代码执⾏阶段,我们可以直接提前使⽤
在提升的过程中,相同的函数会覆盖上⼀个函数,并且函数优先于变量提升
b() // call b second
function b() {
console.log('call b fist')
}
function b() {
console.log('call b second')
}
var b = 'Hello world'
复制代码 var 会产⽣很多错误,所以在 ES6 中引⼊了 let 。 let 不能在声明前使⽤,但是这并不是常说的 let 不会提升,
let 提升了,在第⼀阶段内存也已经为他开辟好了空间,但是因为这个声明的特性导致了并不能在声明前使⽤
单线程 - 只有⼀个线程,只能做⼀件事
原因 - 避免 DOM 渲染的冲突
解决⽅案 - 异步
const box = document.getElementById('box');
function isIcon(target) {
return target.className.includes('icon');
}
box.onClick = function(e) {
e.stopPropagation();
const target = e.target;
if (isIcon(target)) {
target.style.border = '1px solid red';
}
}
const doc = document;
doc.onclick = function(e) {
const children = box.children;
for(let i; i < children.length; i++) {
if (isIcon(children[i])) {
children[i].style.border = 'none';
}
}
}
<input id="input"/>
const data = {};
const input = document.getElementById('input');
Object.defineProperty(data, 'text', {
set(value) {
input.value = value;
this.value = value;
}
});
input.onChange = function(e) {
data.text = e.target.value;
}
var instance = null;
class Storage {
static getInstance() {
if (!instance) {
instance = new Storage();
}
return instance;
⾸先, js 是单线程的,主要的任务是处理⽤户的交互,⽽⽤户的交互⽆⾮就是响应 DOM 的增删改,使⽤事件队列的形式,⼀次事件
循环只处理⼀个事件响应,使得脚本执⾏相对连续,所以有了事件队列,⽤来储存待执⾏的事件,那么事件队列的事件从哪⾥被 push
进来的呢。那就是另外⼀个线程叫事件触发线程做的事情了,他的作⽤主要是在定时触发器线程、异步 HTTP 请求线程满⾜特定条件
下的回调函数 push 到事件队列中,等待 js 引擎空闲的时候去执⾏,当然js引擎执⾏过程中有优先级之分,⾸先js引擎在⼀次事
件循环中,会先执⾏js线程的主任务,然后会去查找是否有微任务microtask(promise) ,如果有那就优先执⾏微任务,如果没有
,在去查找宏任务 macrotask(setTimeout、setInterval) 进⾏执⾏
捕获事件流从根节点开始执⾏,⼀直往⼦节点查找执⾏,直到查找执⾏到⽬标节点
冒泡事件流从⽬标节点开始执⾏,⼀直往⽗节点冒泡查找执⾏,直到查到到根节点
事件流分为三个阶段,⼀个是捕获节点,⼀个是处于⽬标节点阶段,⼀个是冒泡阶段
this ,函数执⾏的上下⽂,可以通过 apply , call , bind 改变 this的指向。对于匿名函数或者直接调⽤的函数来说,
this指向全局上下⽂(浏览器为window,NodeJS为 global ),剩下的函数调⽤,那就是谁调⽤它,this 就指向谁。当然还
有es6的箭头函数,箭头函数的指向取决于该箭头函数声明的位置,在哪⾥声明, this 就指向哪⾥
浏览器缓存机制有两种,⼀种为强缓存,⼀种为协商缓存
caller 返回⼀个函数的引⽤,这个函数调⽤了当前的函数。
这个属性只有当函数在执⾏时才有⽤
如果在 javascript 程序中,函数是由顶层调⽤的,则返回 null
functionName.caller: functionName 是当前正在执⾏的函数。
function a() {
console.log(a.caller)
}
callee 放回正在执⾏的函数本身的引⽤,它是 arguments 的⼀个属性
function a() {
console.log(arguments.callee)
}
$.ajax({
type: 'POST',
url: url,
data: data,
dataType: dataType,
success: function () {},
error: function () {}
});
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
try {
let response = await fetch(url);
let data = response.json();
console.log(data);
} catch(e) {
console.log("Oops, error", e)
}