js高级笔记
null跟undefined
null的类型是null undefined的类型的undefined 搜了一下 我觉得可以理解成null是空对象,一个特殊的对象,先占个位置,期待有一个对象取代它。undefined是未定义。undefined来源于null,两等号返回true,三等号(绝对等)就返回false。
深复制 浅复制
直接复制是浅复制,对于基本数据类型(Number、String、Boolean、Null、undefined、object、symbol、bigInt)直接复制就是复制内容!eg
var a={age:12}//a存的是对象的地址值 是一个数
var b=a//b复制就是复制a中对象的地址值 并不是指向a
a存的是对象的地址值 是一个数,b复制就是复制a中对象的地址值 并不是指向a
!!!!a改变指向对象,b并不会跟着变ok,因为是复制的内容!!!
对象直接赋值的话浅复制就会导致两个变量一起操控同一个堆区域 这样就很不安全 所以复制对象要用深复制 整个函数一个一个复制对象
值传递 引用传递
给函数传东西的时候,传的是对象还是基本数据类型,传基本数据类型的话,函数里面的操作不会对传过去的实参造成影响,传对象的话就会对实参造成影响。很容易搞混的情况 belike
虽然a中保存的是对象的地址值,但是a是作为基本数据类型传进去的,所以function干什么都没用
垃圾回收
对象
.是直接引用 []是动态传入 可以传变量跟字符串
函数
new调用是构造函数调用 函数as构造函数
test.call(obj)是修改了函数对象中的this指针,让this指针指向obj
this
任何函数都是要通过对象去调用的
回调函数
立即执行函数
定义之后马上执行 然后消除定义域内的变量 不浪费空间
语法:
注意 记得打分号
原型
没什么新东西 but 构造函数在实例化新对象时对调用自己的set__proto__函数初始化对象的__proto__属性 直接赋值成自己的prototype指向的地址值
原型链
原型链是隐式原型链
prototype是函数才有的 是原型链上的节点 保存
__proto__是所有对象都有的 是原型链上的链接点!
对象由构造函数实例化 构造函数的prototype指向原型对象 使用set__proto__函数将对象中__proto__属性保存为上一级的地址值 最终指向一个终极原型(Object的原型)(原型链的尽头是Object的原型不是Object) 里面封装好了各种函数 所以实际上是所有对象创建时都默认继承那个终极原型对象
在低级找不到的就往高一级去找 找到就返回 不再往上找了
Function的prototype跟__proto__是一个东西(。)which means 就是Function自己构造了自己
Object居然是一个函数 我震惊 我一直以为belikeJava整个基类那样。。但是其实人家是函数 没想到吧.jpg
补丁:实例对象的constructor就是指向自己的构造函数
改的时候是直接改的构造函数的prototype指向的对象 是不会对之前创建的对象产生影响的
如果是在原型对象上直接加,还是原来那个区域,改变会对原来创建的对象产生影响
a instance of b
->a.proto*n==b.prototype
就是看b在不在a的原型链上
变量提升
js为了提升性能跟容错去预编译 预编译导致变量的声明提升
var会提升至作用域最前 for里面的var i会提升至全局 不过它本来就是在全局里面的(。)不过只提升声明 不提升内容 没有赋值
函数声明 function f(){} 整段进行提升 函数声明和赋值一起提升
预编译的时候其实只是编译了一个函数对象 但是没有执行函数体 对里面的变量都执行一次预编译 然后在作用域里面进行变量提前声明
注意变量提升只是提升声明 但是并没有赋值
function func() {
// 引擎从函数开始就知道局部变量 x,
// 但是变量 x 一直处于“未初始化”(无法使用)的状态,直到结束 let(“死区”)
// 因此答案是 error
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 2;
}
func();
变量提升比函数提升更高
提升的时候编译的cc是变量而不是说cc是一个函数
预编译,是编译,预编译的时候是编译了函数的声明和内容,构造了一个函数对象,但是没有进行形参和实参的结合,没有进行执行,执行的时候进行形参跟实参进行结合,但是声明的时候就有一个原型对象了。
执行上下文
全局执行上下文(window对象)
其实就是执行的时候的window对象 里面存的全局的var变量 函数啥的
函数执行上下文
其实指的应该就是函数的一个自己的执行的时候的一个栈区,自己一个放东西的地方,放自己的变量啥的,还有一个多的arguements(类数组 类型是object),放的给函数的实参(js可以放不对应形参数量的实参。。)
每个函数都有一个。
作用域链
作用域链是静态的,编译的时候就确定了
跟原型链一样 从里面向外找 外部的属性暴露给里面 里面的找不到就去外面找 里面找到就不出去找了(which names覆盖)。。
第一个是当成属性 所以可以输出
直接输出inner的时候 把inner当做一个变量 在obj里面找不到inner这个变量就去外面找 找不到就报错
其实我感觉这题跟作用域没什么关系(。)感觉更像是分辨变量跟属性
闭包
for循环加回调函数
第三行就是将function作为一个参数传进btn.onclick 所以它是一个回调函数 回调函数要在最后执行 所以它要等for循环执行之后才能执行 for循环执行完之后i是3 所以点击的时候才进行调用每一个按钮都是alert3
闭包定义
现在fn2执行才有闭包。。不执行Chrome里面是没有闭包的,可能是优化了。。
function foo() {
var a = 10;
function fn1() {
return a;
}
function fn2() {
return 10;
}
fn2();
}
foo();
但是当注释掉fn1之后 fn2就没有闭包了 我感觉就是
其实可以不可以理解成 外部函数作用域把内部函数包起来了,内部函数可以使用外部函数作用域中的变量,所以是闭包。
但是这个是在函数内部才有这种,如果是在返回了内部函数fn2,就只有用到foo里面的变量才会产生闭包。
return fn2是创建了一个函数对象去返回的。
这里是msg被内部的匿名函数调用了,外部函数的arguement被内部函数调用了
闭包保存了外部函数里面要用到的变量 感觉外部函数是销毁的
我感觉js的模块是在模仿着做一个就是有私有属性的类,暴露接口给外部用,但是不是全部。。
内存泄漏&溢出
原来下面这么写a的作用范围是全局 震惊我妈
原来没有用var会自动提升成全局变量(.)
就是绑定dom事件监听(要等到dom事件发生,后面的代码才会执行,,比如使用for循环绑定btn的onclick)、定时器(等到时间过了,才把任务放进队列里面排队)、ajax(发送请求后等待服务器的回应)这三个都是异步代码
alert会暂停主线程 让定时器的计时结束之后的事件执行不了
事件循环模型
其实就是js先在主线程里面执行初始代码,分出去一些任务给浏览器做,利用浏览器的分线程来执行其他任务 eg ajax 计时器什么的 浏览器的分模块等到事件发生了 就将任务推到callback queue里面 js主线程按照先来先出 一个一个取出来执行(事件轮询)