写在文章的开头,好记性不如烂笔头,干什么事情都是贵在坚持,为了提升自己的前端水平,我也看了不少文章和知识,可是到头来总是转头忘,这段时间看了些文章,也分享了很多知识,但是总是感觉不足,虽然自己为了生活的事情很烦恼,但是也不能停下来学习的脚步,从现在开始坚持一个星期写三篇文章,完成文章最终目的是坚持自己的学习之路,学会总结,无论文章是初级还是高级,也是一个坚持的理由## js学习
执行上下文
1.什么是执行上下文,一般有两类包括全局执行上下文,函数执行上下文
2.全局执行上下文由浏览器创建,一般指window
3.执行上下文栈,也叫做调用栈,相当于一个数组,执行先进后出的特性,也就是执行上下文栈中最后一个都是全局执行上下文
4.执行上下文的创建分为创建和执行阶段
创建阶段分为三件事情:
-
创建Scope chain
-
创建VO/AO(variables, functions and arguments)
-
设置this的值
创建 VO的时候,变量,函数参数,函数申明
function foo(a) { var b = 2; function c() {} var d = function() {}; b = 3; } foo(1);vo
vo = { arguments:{ 0:1 length:1 }, a:1, b:undefined, c:functin c(){}, d:undefined }
变量对象会包括:
- 函数的所有形参 (如果是函数上下文)
- 由名称和对应值组成的一个变量对象的属性被创建
- 没有实参,属性值设为 undefined
- 函数声明
- 由名称和对应值(函数对象(function-object))组成一个变量对象的属性被创建
- 如果变量对象已经存在相同名称的属性,则完全替换这个属性
- 变量声明
- 由名称和对应值(undefined)组成一个变量对象的属性被创建;
- 如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性
作用域链
函数的作用域在函数定义的时候就决定了
查找变量的时候会先从当前执行上下文变量对象中寻找,如果没有就会在父级的执行上下文变量对象中寻找,一直到全局执行上下文,由多个执行上下文的变量对象构成的链表就叫做作用域链
闭包函数
MDN 对闭包的定义为:
闭包是指那些能够访问自由变量的函数。
那什么是自由变量呢?
自由变量是指在函数中使用的,但既不是函数参数也不是函数的局部变量的变量。
由此,我们可以看出闭包共有两部分组成:
闭包 = 函数 + 函数能够访问的自由变量
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f;
}
var foo = checkscope();
foo();
分析此文件运行流程
1.执行代码,创建全局执行上下文,全局执行上下文压入执行上下文栈
ECStack = [
globalContext
]
2.全局执行上下文(初始化)(创建变量对象,创建作用域链,指定this)
globalContext = {
VO:[global],
Scope:[globalContext.VO],
this:globalContext.VO
}
创建变量对象:
vo = {
scope:undefined,
checkscope:function f(){}
foo:undefined
}
3.初始化的同时,checkscope函数被创建,保存作用域链到函数内部属性[[scope]]
checkscope.[[scope]] = [globalContext.VO]
4.执行checkscope函数,创建checkscope函数执行上下文,压入执行上下文栈
(1)复制函数属性[[scope]]属性创建作用域链
(2) 创建VO,使用arguments创建活动对象
(3)初始化活动对象,加入形参,函数申明,变量申明
(4) 将活动对象压入checkscope的作用域链
5.在创建变量对象的时候,函数申明的时候,checkscope的作用域链保存给f函数内部属性[[scope]]
f.[[scope]] = [checkscopeContext.VO,global.VO]
6.执行f函数,创建f的函数上下文,推入执行上下文栈
7.f的函数上下文初始化,创建变量对象,将变量对象压入f的作用域链
fcontext={
VO:{
arguments:{
lenght:0
}
c:function(){}
d:undefined
},
scope:[fContext.VO,checkscopeContext.VO,global.VO]
this:fcontext.VO
}
原型
函数中有prototype属性,就是其函数原型对象,
function Person() {
}
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true
person实例的_ _proto__指向的是Person.prototype
Person.prototype.constructor 指的是Person
手写call
call实际就是指定this,和若干值来调用函数方法
var obj = {
value:"测试"
}
function bar(){
console.log(this.value)
}
bar.call(obj)
//call的正常使用
/*var obj = {
value:测试
function fn(){
console.log(this.value)
}
}
obj.bar()*/
//实际上是为了这个实现,思路就是给这个对象一个bar属性上有这个方法
Function.prototype.copyCall = function(obj){
obj.fn = this//此时这个指的前面引用方法
obj.fn(argument[1])
delete foo.fn
}
bar.copyCall(obj)
防抖
事件触发后多少秒才能触发下一次事件,如果在规定时间再次触发,则会重置时间,才能触发事件
function debounce(fn,timeout){
let task
return function(){
let context = this
clearTimeout(task)
task = setTimeout(()=>{
fn.apply(context,arguments)
//fn() 这样写,this指向不是事件绑定的节点 所以使用fn.apply调用
},timeout)
}
}
function debounceAtTime(fn,timeout,immediately){
let task
return function(){
clearTimeout(task)
!task && fn()
task = setTimeOut(()=>{
task = null
},timeout)
}
}
节流
function throttle(fn,wait){
let prev = 0
return function(){
now = new Date()
if(now - prev > wait){
fn()
prev = now
}
}
}