基本(值)类型css
String,Number,boolean,undefined,null
html
对象(引用)类型vue
Object
:任意对象程序员
Function
:一种特别的对象(能够执行)es6
Array
:一种特别的对象(数值下标,内部数据是有序的)ajax
typeof
返回数据类型的字符串表达跨域
能够判断undefine
d / 数值 / 字符串/布尔值浏览器
不能判断null
与object
缓存
instanceof
返回布尔值markdown
===
能够判断undefined
,null
undefined
与null
的区别?
undefined
表明定义未赋值
null
定义并赋值了,只是值为null
何时给变量赋值为null
呢?
初始赋值,代表将要赋值为对象。
结束前,被垃圾回收器回收
严格区别变量类型与数据类型?
数据的类型
基本类型
对象类型
变量的类型(变量内存值的类型)
基本类型:保存基本类型的数据
引用类型:保存的是地址值
什么是数据?
存储在内存中表明特定信息的,本质上是0101...
数据的特色:可传递,可运算
一切皆数据
内存中全部操做的目标:
数据
算术运算
逻辑运算
赋值
运行函数
什么是内存?
内存条通电之后产生的可存储数据的空间。(临时的)
内存的产生和死亡:内存条(电路板)-->产生内存空间-->存储数据-->断电-->内存空间和数据都消失
一块小内存的两个数据
内部存储的数据
地址值
内存分类
栈:全局变量和局部变量(空间较小)
堆:对象(空间较大)
什么是变量?
可变化的量,由变量名和变量值组成
每一个变量都对应的一块小内存,变量名用来查找对应的内存,变量值就是内存中保存的数据。
内存,数据,变量三者之间的关系
内存用来存储数据的空间
变量是内存的标识
问题:var a = xxx
,a
内存中保存的是什么?
xxx是基本数据,保存的是这个数据
xxx是对象,保存的是对象的地址值
xxx是一个变量,保存xxx的内存内容(多是基本数据,也多是地址值)
关于引用变量赋值问题
n个引用变量指向同一个对象,经过一个变量修改对象内部数据,另外一个变量看到的是修改以后的数据。
n个引用变量指向同一个对象,让其中一个引用变量指向另外一个对象,另外一个引用变量依然指向前一个对象。
问题:在js调用函数时传递变量参数时,是值传递仍是引用传递?
理解1:都是值(基本值/地址值)传递
理解2:多是值传递,也多是引用传递(地址值)
问题:js引擎如何管理内存?
内存生命周期
分配小内存空间,获得它的使用权
存储数据,能够反复进行操做
释放小内存空间
释放内存
局部变量:函数执行完自动释放(栈空间)
对象:成为垃圾对象-->垃圾回收器回收(堆空间)
什么是对象?
多个数据的封装体
用来保存多个数据的容器
一个对象表明现实世界中的一个事物
为何要用对象?
对象的组成
属性:属性名(字符串)和属性值(任意类型)组成。
方法:一种特别的属性(属性值是函数)
如何访问对象内部数据?
.属性名:编码简单,有时不能用
['属性名']:编码麻烦,能通用
问题:何时必须使用['属性名']的方式?
属性名包含特殊字符:-,空格
变量名不肯定
什么是函数?
实现特定功能的n条语句的封装体
只有函数是能够执行的,其余类型的数据不能执行
为何要用函数?
提升代码复用
便于阅读交流
如何定义函数?
函数声明
表达式
如何调用(执行)函数?
test()
:直接调用
obj.test()
:经过对象调用
new test()
:new调用
test.call/apply(obj)
:临时让test
成为obj
的方法进行调用
什么函数才是回调函数?
本身定义的
本身没有调用
但最终执行了(在某个时刻或某个条件下)
常见的回调函数?
dom事件回调函数 this ==>发生事件的dom元素
定时器回调函数 this==>window
ajax请求回调函数
声明周期回调函数
IIFE
的理解
全称:Immediately-Invoked Function Expression 当即调用函数表达式
也能够叫:匿名函数自调用
IIFE
的做用
隐藏实现
不会污染外部(全局)命名空间
用它来编码js模块
this
是什么?
任何函数本质上都是经过某个对象来调用的,若是没有直接指定的就是window
全部函数内部都有一个变量this
它的值是调用函数的当前对象
如何肯定this
的值?
test():window
p.test():p
new test():新建立的对象
p.call(obj):obj
js一条语句的后面能够不加分号
是否加分号是编码风格问题,没有应不该该,只有喜不喜欢
在下面2种状况下不加分号会有问题
小括号开头的前一条语句
中方括号开头的前一条语句
解决办法:在行首加分号
例子:vue.js库
每一个函数都有一个prototype
属性,他默认指向一个Object
空对象(称为:原型对象)
原型对象中有一个属性constructor
,他指向函数对象
给原型对象添加属性(通常都是方法)
做用:函数的全部实例对象自动拥有原型中的属性(方法)
每一个函数function
都有一个prototype
,即显式原型
每一个实例对象都有一个__proto__
,可称为隐式原型
对象的隐式原型的值为其对应构造函数的显式原型的值
总结:
函数的prototype
属性:在定义函数时自动添加的,默认值是一个空Object
对象。
对象的__proto__
属性:建立对象时自动添加的,默认值为构造函数的prototype
属性值。
程序员能直接操做显式原型,但不能直接操做隐式原型(es6以前)
访问一个对象的属性时,
访问一个对象的属性时,如今自身属性中查找,找到返回。若是没有,再沿着__proto__这条链向上查找,找到返回。若是最终没有找到,返回undefined
别名:隐式原型链
做用:查找对象的属性(方法)
__proto__
都是同样的函数的显式原型指向的对象默认是空Object
实例对象(但Object
不知足)
全部函数都是Function
的实例(包括Function
)
Object
的原型对象是原型链的尽头,Object.__proto__ =null
读取对象的属性值时:会自动到原型链中查找
设置对象的属性值时:不会查找原型链,若是当前对象中没有此属性,直接天界此属性并设置其值。
方法通常定义在原型中,属性通常经过构造函数定义在对象自己上。
表达式“A instanceof B
若是B函数的显式原型对象在A对象的原型链上,返回true
,不然返回false
经过var定义(声明)的变量,在定义语句以前就能够访问到
值:undefined
经过function
声明的函数,在以前就能够直接调用(var定义的不行)
值:函数定义(对象)
全局代码
函数(局部)代码
在执行全局代码前将window肯定为全局执行上下文
对全局数据进行预处理
var定义的全局变量==>undefined
,添加为window
的属性
function
声明的全局函数==>赋值(fun),添加为window
的方法
this==>赋值(window)
开始执行全局代码
在调用函数,准备执行函数体以前,建立对应的函数执行上下文对象(虚拟的,存在于栈中)
对局部数据进行预处理
形参变量==>赋值(实参)==>添加为执行上下文的属性
arguments
==>赋值(实参列表),添加为执行上下文的属性
var
定义的局部变量==>undefined
,添加为执行上下文的属性
function
声明的函数==>赋值(fun),添加为执行上下文的方法
this==>赋值(调用函数的对象)
开始执行函数体代码
在全局代码执行前,js引擎就会建立一个栈来存储管理全部的执行上下文对象
在全局执行上下文(window)肯定后,将其添加到栈中(压栈)
在函数执行上下文建立后,将其添加到栈中(压栈)
在当前函数执行完后,将栈顶的对象移除(出栈)
当全部的代码执行完后,栈中只剩下为window
先执行变量提高,再执行函数提高
递归调用:在函数内部调用本身
就是一块“地盘”,一个代码段所在的区域
它是静态的(相对于上下文对象),在编写代码时就肯定了
分类
全局做用域
函数做用域
没有块做用域(es6有了)
做用
全局做用域以外,每一个函数都会建立本身的做用域,做用域在函数定义时就已经肯定了,而不是在函数调用时。
全局执行上下文环境是在全局做用域肯定以后,js代码立刻执行前建立。
函数执行上下文环境是在调用函数时,函数体代码执行以前建立。
做用域是静态的,只要函数定义好了就一直存在,且不会变化。
上下文环境是动态的,调用函数时建立,函数调用结束时上下文环境就会自动释放。
联系
上下文环境(对象)是从属于所在的做用域
全局上下文环境==>全局做用域
函数上下文环境==>对应的函数使用域
多个上下级关系的做用域造成的链,它的方向是从下向上的(从内向外)
查找变量时就是沿着做用域链来查找的
在当前做用域下的执行上下文中查找对应的属性,若是还找不到就抛出找不到的异常。
如何产生闭包?
当一个嵌套的内部(子)函数引用了嵌套的外部(子)函数的变量(函数)时,就产生了闭包
闭包究竟是什么?
使用Chrome调试查看
理解一:闭包是嵌套的内部函数(绝大多部分人)
理解二:包含被引用变量(函数)的对象(极少数人)
注意:闭包存在于嵌套的内部函数中
产生闭包的条件?
函数嵌套
内部函数引用了外部函数的数据(变量/函数)
常见的闭包
将函数做为另外一个函数的返回值
将函数做为实参传递给另外一个函数调用
闭包的做用
使用函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的生命周期)
让函数外部均可以操做(读写)到函数内部的数据(变量/函数)
问题:
通常是不存在,存在于闭包中的变量才可能存在
不能,可是能够经过闭包让外部操做它。
闭包的生命周期
产生:在嵌套内部函数定义执行完时就产生了(不是在调用)
死亡:在嵌套的内部函数成为垃圾对象时
闭包的应用:定义js模块
具备特定功能的js文件
将全部的数据和功能都封装在一个函数内部(私有的)
只向外暴露一个包含n个方法的对象或函数
模块的使用者,只须要经过模块暴露的对象调用方法来实现对应的功能。
9. 闭包的缺点及解决
缺点
函数执行完后,函数内的局部变量没有释放,占用内存时间会变长
容易形成内存泄露
解决
能不用闭包就不用闭包
及时释放
一种程序运行出现的错误
当程序运行须要的内存超过了剩余的内存时,就会抛出内存溢出的错误
占用的内存没有及时释放
内存泄露积累多了就会容易致使内存溢出
常见的内存泄漏:
意外的全局变量
没有及时清理的计时器或回调函数
闭包
Object
构造函数模式
套路:先建立空Object
对象,再动态添加属性/方法
适用场景:起始时不肯定对象内部数据
问题:语句太多
对象字面量模式
套路:使用{ }建立对象,同时指定属性/方法
适用场景:起始时对象内部数据时肯定的
问题:若是建立多个对象,有重复代码
工厂模式
套路:经过工厂函数动态建立对象并返回
适用场景:须要建立多个对象
问题:对象没有一个具体的类型,都是Object类型
自定义构造函数模式
套路:自定义构造函数,经过new建立对象
适用场景:须要建立多个类型肯定的对象
问题:每一个对象都有相同的数据,浪费内存
构造函数+原型的组合模式
套路:自定义构造函数,属性在函数中初始化,方法添加到原型上
适用场景:须要建立多个类型肯定的对象
套路
定义父类型构造函数
给父类型的原型添加方法
定义子类型的构造函数
建立父类型的对象赋值给子类型的原型
将子类型原型的构造属性设置为子类型
给子类型原型添加方法
建立子类型的对象:能够调用父类型的方法
关键
function Parent(){ }
Parent.prototype.test = function(){ };
function Child( ){ }
Child.prototype = new Parent( );//子类型的原型指向父类型实例
Child.prototype.constructor = Child
var child = new Child( );
借用构造函数继承(假的):获得属性
复制代码
套路:
定义父类型构造函数
定义子类型构造函数
在子类型构造函数中调用父类型构造
关键:
function Parent(xxx){ this.xxx = xxx}
Parent.prototype.test = function( ){ };
function Child(xxx,yyy){
Parent.call(this,xxx)// 借用构造函数 this.Parent(xxx)
}
var child =new Child('a','b'); //child.xxx为'a',但child没有test()
复制代码
原型链+借用构造函数的组合继承
利用原型链实现对父类型对象的方法继承
利用super()借用父类型构建函数初始化相同属性
function Parent(xxx){this.xxx=xxx}
Parent.prototype.test = function(){};
function Child(xxx,yyy){
Parent.call(this,xxx);//借用构造函数 this.Parent(xxx)
}
Child.prototype = new Parent();//获得test()
var child = new Child();//child.xxx为'a',也有test()
复制代码
建立一个空对象
给对象设置__proto__
,值为构造函数对象的prototype
属性值,this.__proto__=Fn.prototype
执行构造函数体(给对象添加属性/方法)
线程池:保存多个线程对象的容器,实现线程对象的反复利用
多线程
优势:能有效提高CPU的利用率,建立多线程开销
缺点:线程间切换开销,死锁与状态同步问题
js是单线程仍是多线程?
js是单线程运行的
但使用H5中的Web Workers
能够多线程运行
浏览器内核由不少模块组成
主线程
js引擎模块:负责js程序的编译与运行
html
,css文档解析模块:负责页面文本的解析
DOM/CSS
模块:负责dom/ css
在内存中的相关处理
布局和渲染模块:负责页面的布局和效果的绘制(内存中的对象)
分线程
定时器模块:负责定时器的管理
事件响应模块:负责事件的管理
网络请求模块:负责ajax
请求
定时器真是定时执行的吗?
定时器并不能保证真正定时执行
通常会延迟一丁点(能够接受),也有可能延迟很长时间(不能接受)
定时器回调函数是在分线程执行的吗?
定时器是如何实现的?
alert
会暂停当前的主线程的执行,同时暂停计时,点击肯定后,恢复程序执行和计时
alert
是window
的方法,在分线程不能调用
如何证实js执行时单线程的?
setTimeout()
的回调函数是在主线程执行的
定时器回调函数只有在运行栈中的代码所有执行完后才有可能执行
为何js要用单线程模式,而不用多线程模式?
js的单线程和它的用途有关
做为浏览器脚本语言,js的主要用途是鱼用户互动,以及操做dom
这决定了他只能是单线程,不然会带来很复杂的同步问题
代码的分类
初始化代码(同步代码):包含绑定dom
事件监听,设置定时器,发送ajax
请求的代码
回调代码(异步代码):处理回调逻辑
js引擎执行代码的基本流程
先执行初始化代码:包含一些特别的代码 回调函数(异步执行)
设置定时器
绑定监听
发送ajax请求
后面在某个时刻才会执行回调代码
模型的2个重要组成部分:
事件管理模块
回调队列(起到了一个缓存的做用)
模型的运转流程
执行初始化代码,将事件回调函数交给对象模块管理
当事件发生时,管理模块会将回调函数及其数据添加到回调队列中
只有当初始化代码执行完后(可能要必定时间),才会遍历读取回调队列中的回调函数执行
事件轮询(event loop
):从任务队列中循环取出回调函数放入执行栈处理中
H5规范提供了js分线程的实现,取名为:Web Workers
相关API
Worker
:构造函数,加载分线程执行的js文件
Worker.prototype.onmessage
:用于接收另外一个线程的回调函数
Worker.prototype.postMessage
:向另外一个线程发送消息
worker.onMessage=function(event){event.data}
:用来接受另外一个线程发送过来的数据的回调
不足
worker
内代码不能操做DOM
(更新UI)
不能跨域加载js
不是每一个浏览器都支持这个新特性