1.对象
1.1 分类
- 基本(值)数据类型 -----赋值的时候是直接在栈中将值赋予了
- Number
- String
- Boolean
- undefined
- null
- 对象(引用)类型 ------------从堆中创建对象,然后将地址给予栈中的变量.
- Object 任意对象
- Function 函数一种特别的对象可以执行
- Array 数值
…
1.2 判断
- typeof 返回的是字符串
- 基本数据类型 (null 为 Object) / Function为function /其余的对象类型会判断成Object
- instanceof 判断对象(引用)类型
- Object 、Array、Function
- ===
- 可以判断undefined 、null
// typeof: 返回的是数据类型的字符串表达形式
//1. 基本类型
var a
console.log(a, typeof a, a===undefined) // undefined 'undefined' true
console.log(a===typeof a) // false
a = 3
console.log(typeof a === 'number')
a = 'atguigu'
console.log(typeof a === 'string')
a = true
console.log(typeof a === 'boolean')
a = null
console.log(a===null) // true
console.log(typeof a) // 'object'
console.log('--------------------------------')
//2. 对象类型
var b1 = {
b2: [2, 'abc', console.log],
b3: function () {
console.log('b3()')
}
}
console.log(b1 instanceof Object, typeof b1) // true 'object'
console.log(b1.b2 instanceof Array, typeof b1.b2) // true 'object'
console.log(b1.b3 instanceof Function, typeof b1.b3) // true 'function'
console.log(typeof b1.b2[2]) // 'function'
console.log(b1.b2[2]('abc')) // 'abc' undefined
1.3 常见问题
- undefined与null的区别?
- 1.undefined是指变量未赋值 var a;
- 2.null是指定义了变量但是值未null
- 什么时候给变量赋值为null呢?
- 1.指当前变量指向一个对象,但是对象还没有确定
- 2.对于不要再使用的变量,将其赋值为null,便于垃圾回收器将其回收.
- 严格区别变量类型与数据类型?
- 1.变量类型
- 1.基本类型:保存基本类型数据的变量
- 2.引用类型:保存的是对象地址值的变量
- 2.数据类型
- 1.基本类型
- 2.对象(引用)类型
- 1.变量类型
1.4 访问对象的内部数据或添加属性
-
- .属性名 编码简单,
但是有一些场景不能用
------ xxx.属性名
- 1.属性名包含-的这种情况.例如:context-type
- 2.属性名不确定时,例如 propName=‘myage’; …propName=value --错误.
- .属性名 编码简单,
-
- [‘属性名’]都能用 ,但是编码比较麻烦. ----------- xxx[‘属性名’]
var p = {}
//1. 给p对象添加一个属性: content type: text/json
// p.content-type = 'text/json' //不能用
p['content-type'] = 'text/json'
console.log(p['content-type'])
//2. 属性名不确定
var propName = 'myAge'
var value = 18
// p.propName = value //不能用
p[propName] = value
console.log(p[propName])
2.函数
2.1 函数的调用方式
- 1.直接调用 test()
- 2.通过对象调用 obj.test()
- 3.直接new test() 调用
- 4.test.call() / apply(obj) 让test成为obj对象的临时方法进行调用
function test(){
this.xxx ="wangxxxxx;
}
var obj={};
test.call(obj);
console.log(obj.xxx);
区别call 和 apply的区别
--call一个或者多个参数
--apply 大于一个参数
2.2 回调函数
-
定义:
1.定义了
2.但是没有调用
3.最终执行了 -
常见的回调函数
1.dom事件回调函数==>发生事件的dom元素
2.定时器回调函数=>window.
3.ajax回调函数.
4.生命周期回调函数.
2.3 IIFE 立即调用函数表达式
全称: Immediately-Invoked Function Expression
作用:
- 隐藏实现
- 不会污染外部(全局 )命名空间
- 用来编码js代码
(function () { //匿名函数自调用
var a = 3
console.log(a + 3)
})()
var a = 4
console.log(a)
;(function () {
var a = 1
function test () {
console.log(++a)
}
window.$ = function () { // 向外暴露一个全局函数
return {
test: test
}
}
})()
$().test() // 1. $是一个函数 2. $执行后返回的是一个对象
2.4 函数中的this
-
- this是什么:
1.任何函数本质上都是通过某个对象调用的,如果没有直接指定就是window
2.所有函数的内部都有一个this.
3.他的值是调用函数的当前对象.
- this是什么:
-
- 确定this的值
1.test() -----window
2.new person() -----新创建的对象
3.p.test() ------p
4.p.call(obj) -----obj
- 确定this的值
function Person(color) {
console.log(this)
this.color = color;
this.getColor = function () {
console.log(this)
return this.color;
};
this.setColor = function (color) {
console.log(this)
this.color = color;
};
}
Person("red"); //this是谁? window
var p = new Person("yello"); //this是谁? p
p.getColor(); //this是谁? p
var obj = {};
p.setColor.call(obj, "black"); //this是谁? obj
var test = p.setColor;
test(); //this是谁? window
function fun1() {
function fun2() {
console.log(this);
}
fun2(); //this是谁? window
}
fun1();
2.函数高级
1.原型与原型链
1.1 原型
-
- 函数的prototype属性
- 每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
- 原型对象中有一个属性constructor, 它指向函数对象
-
- 给原型对象添加属性(一般都是方法)
- 作用: 函数的所有实例对象自动拥有原型中的属性(方法)
// console.log(Date.prototype.constructor); // ---指向Date函数
// console.log(Date.prototype);
function Fun() {
}
console.log(Fun.prototype);
Fun.prototype.test=function () {
alert('测试数据')
}
var fun = new Fun();
fun.test();
1.2 显示原型(prototype)与隐式原型(__proto __)
每个函数对象中的prototype对应的空对象
都是实例对象
每个实例对象中都有一个属性__proto__,对应的是函数对象中的prototype中的实例对象.
-
- 每个函数function都有一个prototype,即显式原型(属性)
-
- 每个实例对象都有一个__proto__,可称为隐式原型(属性)
-
- 对象的隐式原型的值为其对应构造函数的显式原型的值
-
- 内存结构(图)
-
- 总结:
- 函数的prototype属性: 在定义函数时自动添加的, 默认值是一个空Object对象
- 对象的__proto__属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值
- 程序员能直接操作显式原型, 但不能直接操作隐式原型(ES6之前)
1.3 原型链
原型链(图解)
- 访问一个对象的属性时,
- 先在自身属性中查找,找到返回
- 如果没有, 再沿着__proto__这条链向上查找, 找到返回
- 如果最终没找到, 返回undefined
- 别名: 隐式原型链
- 作用: 查找对象的属性(方法)
1.4 instanceof
- instanceof是如何判断的
- 表达式: A instanceof B
- 如果B函数的显式原型对象在A对象的原型链上, 返回true, 否则返回false
2.执行上下文与执行上下文栈
2.1 变量提升和函数提升
-
- 变量提升
- 通过var定义(声明)的变量 ,在定义之前就能访问到.
- 值为undefined
-
- 函数提升
- 通过function声明的函数,在之前就能够调用
- 函数定义(对象)
var a = 3 //undefine
function fn () {
console.log(a) //var a=undefine
var a = 4
}
fn() 输出为 undefine
-------------------------------------
console.log(b) //undefined 变量提升
fn2() //可调用 函数提升
// fn3() //不能 变量提升
var b = 3
function fn2() {
console.log('fn2()')
}
var fn3 = function () {
console.log('fn3()')
}
注意:函数提升只能用声明的方式才可以 ,变量式的函数不行.
2.2 执行上下文
-
分为全局代码和函数代码
-
- 全局执行上下文
- 在执行全局代码前将window确定为全局执行上下文对象
- 对全局变量数据进行预处理
- var定义的全局变量===>undefined , 添加为window属性
- function声明的全局函数==>赋值(fun) ,添加为window的方法
- this赋值为 window
- 开始执行全局代码
-
2.函数执行上下文
- 在调用函数,准备执行函数体之前,
创建对应的函数执行上下文对象
(栈中的对象) - 对局部数据进行预处理
- 形参变量=====>赋值(实参)===>添加执行上下文的属性
- argument====>赋值(实参) ====>添加为执行上下文的属性
- var 定义为局部变量 ====>undefined,添加为执行上下文的属性
- function声明的函数====>赋值为(fun) ,添加为执行上下文的方法
- this====调用函数的对象
- 开始执行函数体的代码.
- 在调用函数,准备执行函数体之前,
2.23 执行上下文栈
- 在全局代码执行前, JS引擎就会创建一个栈来存储管理所有的执行上下文对象
- 在全局执行上下文(window)确定后, 将其添加到栈中(压栈)
- 在函数执行上下文创建后, 将其添加到栈中(压栈)
- 在当前函数执行完后,将栈顶的对象移除(出栈)
- 当所有的代码执行完后, 栈中只剩下window
3.作用域和作用域链
3.1 作用域与作用域链
- 全局作用域
- 函数作用域
作用:不同作用域下同名变量不会冲突
/*
问题: 结果输出多少?
*/
var x = 10;
function fn() {
console.log(x);
}
function show(f) {
var x = 20;
f();
}
show(fn); --10
3.2 作用域与执行上下文
- 区别
-
- 全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了。而不是在函数调用时
-
- 全局执行上下文环境是在全局作用域
确定之后
, js代码马上执行之前创建
- 全局执行上下文环境是在全局作用域
-
- 函数执行上下文环境是在调用函数时 , 函数体代码执行之前创建
- 区别2
- 1.作用域是静态的, 只要函数定义好了就一直存在, 且不会再变化
- 2.上下文环境是动态的, 调用函数时创建, 函数调用结束时上下文环境就会被释放
- 联系
-
- 上下文环境(对象)是从属于所在的作用域
-
- 全局上下文环境==>全局作用域
-
- 函数上下文环境==>对应的函数使用域
3.3 作用域链
- 理解
- 多个上下级关系的作用域形成的链, 它的方向是从下向上的(从内到外)
- 查找变量时就是沿着作用域链来查找的
- 查找一个变量的查找规则
- 在当前作用域下的执行上下文中查找对应的属性, 如果有直接返回, 否则进入2
- 在上一级作用域的执行上下文中查找对应的属性, 如果有直接返回, 否则进入3
- 再次执行2的相同操作, 直到全局作用域, 如果还找不到就抛出找不到的异常
4.闭包
4.1 闭包的条件
- 当一个嵌套的内部(子)函数引用了外部(父)函数的变量(函数)时,就产生了闭包。
- 闭包
- 闭包是嵌套的内部函数
- 包含被引用变量(函数)的对象(极少数人)
function fn1 () {
var a = 2
var b = 'abc'
function fn2 () { //执行函数定义就会产生闭包(不用调用内部函数)
console.log(a)
}
// fn2()
}
fn1()
4.2 常见的的闭包
1.将函数作为另外一个函数的返回值
function f1(){
var a=3;
function f2(){
a++ //产生闭包
console.log(a)
}
return f2
}
var t=f1() //函数执行完后,进行释放,但是函数内部的变量依然存在可以进行使用
t(); 4
t(); 5
2.将参数作为实参传递给另外函数调用
function showDelog(msg,time){
setTimeout(function () {
alert(msg);
},time)
}
showDelog('显示数据',2000);
4.3 闭包的作用
- 可以让函数内部的局部变量在函数执行完后,依然存活在内存中(延迟局部变量的声明周期)
- 可以让函数外部操作函数内部的数据.
1.函数执行完后,函数内部声明的局部变量是否还存在? 一般不存在,存在于函数内部的闭包可能存在
2.函数外部能够访问到函数的局部变量吗? 不能,但是我们可以通过闭包去访问.
4.4 闭包的生命周期
- 产生: 在嵌套内部函数定义执行时,闭包就产生了.
- 死亡:在嵌套的内部函数为垃圾对象被回收时,闭包就死亡了(其实就是闭包所在的函数为垃圾对象)
function f1(){ //执行函数时,闭包产生
var a=3;
function f2(){
a++ //产生闭包
console.log(a)
}
return f2
}
var t=f1()
t(); 4
t(); 5
t=null //当调用函数对象没人调用时,变为垃圾对象时闭包就死亡了.
4.5 闭包的应用-自定义JS模块
- JS模块其实具有特定功能的js文件
- 将所有的数据和功能封装到一个函数内部(私有的)
- 向外暴漏一个(多个方法)对象 或者 函数.
- 模块的使用者只需要执行暴漏出来的相应方法进行执行.
第一种方式:
(function () {
var msg='mybatis';
function f1() {
console.log(msg)
}
window.moudle={
f1:f1
}
})()
第二种方式:
function f1() {
var msg='mybatis';
function f2() {
console.log(msg)
}
return f2
}
var t=f1()
t(); //执行闭包
4.6 闭包的缺点
- 内存溢出:
- 指的是程序运行所需要的内存超过了系统所拥有的内存.
- 当程序运行需要的内存超过了剩余的内存时, 就出抛出内存溢出的错误
- 内存泄漏:指的是一段内存
- 占用的内存没有来的及释放
- 占用的内存太多容易导致内存溢出
- 常见的内存泄漏: 1.意外的全局变量. 2.没有及时清除计时器或者回调函数 3.闭包
function f1(){
a=3 //1.意外的全局变量
}
f1();
var intervalId= setInterval(function(){
console.log('--------')
},1000) //2.计时器没来得及清除
clearInterval(intervalId);
function fn1() {
var a = 4
function fn2() {
console.log(++a) // 3. 闭包
}
return fn2
}
var f = fn1()
f()
4.对象高级
1.对象创建模式
1.1 Object构造函数模式
- 套路: 先创建空Object对象, 再动态添加属性/方法
- 适用场景: 起始时不确定对象内部数据
- 问题: 语句太多
var t=new Object()
t.name='xxx'
t.age=12
t.setName=function (name) {
this.name=name
}
console.log(t.name,t.age)
t.setName('bob')
console.log(t.name,t.age)
1.2 对象字面量
- 套路: 使用{}创建对象, 同时指定属性/方法
- 适用场景: 起始时对象内部数据是确定的
- 问题: 如果创建多个对象, 有重复代码
var obj={
name:'xxxx',
age:12,
setName :function (name) {
this.name=name
}
}
console.log(obj.name,obj.age)
obj.setName('wx')
console.log(obj.name,obj.age)
1.3 工厂模式
- 套路: 通过工厂函数动态创建对象并返回
- 适用场景: 需要创建多个对象
- 问题: 对象没有一个具体的类型, 都是Object类型
function createPerson(name ,age){
var obj={
name:name,
age:age,
setName:function (name) {
this.name=name
}
}
return obj;
}
var person1=createPerson('xxxx',12);
var person2=createPerson('bbbb',18);
1.4 自定义构造函数
- 套路: 自定义构造函数, 通过new创建对象
- 适用场景: 需要创建多个类型确定的对象
- 问题: 每个对象都有相同的数据, 浪费内存
function Person(name,age) {
this.name=name;
this.age=age;
this.setName=function (name) {
this.name=name
}
}
var p1=new Person('wx',18);
p1.setName('bob')
console.log(p1.name,p1.age);
console.log(p1 instanceof Person)
1.5 构造函数+原型的组合模式
- 套路: 自定义构造函数, 属性在函数中初始化, 方法添加到原型上
- 适用场景: 需要创建多个类型确定的对象
function Person(name ,age){
this.name=name
this.age=age
}
Person.prototype.setName= function (name) {
this.name =name
}
var p1 =new Person('xxx',18);
p1.setName('xxx1')
var p2=new Person('bob',20);
p2.setName('bob1')
console.log(p1.name,p1.age)
console.log(p2.name,p2.age)
2.继承模式
2.1 原型链继承
其实关键在于子类型的显示原型是父对象的实例对象.
//父类型
function Supper() {
this.supProp = 'Supper property'
}
Supper.prototype.showSupperProp = function () {
console.log(this.supProp)
}
//子类型
function Sub() {
this.subProp = 'Sub property'
}
//子类型的显示原型为父类的实例对象 --
Sub.prototype = new Supper()
// 让子类型的原型的constructor指向子类型
Sub.prototype.constructor=Sub
2.2 借用构造函数继承
其实就是调用call
function Supper(name ,age){
this.name =name
this.age =age
}
function Sub(name,age,price){
Supper.call(this,name,age) //相当于 创建对象的t t.Supper(name ,age) ----t.name ,t.age
this.price=price
}
var t=new Sub('wwd',18,120)
console.log(t.name,t.age,t.price);
2.3 组合继承
继承分为两种 ,一种是原型链继承,一种是借用构造函数继承。原型链主要是用来继承prototype的方法,而借用构造函数主要继承的是属性。所有需要结合两种方式的去实现继承。
function Person(name ,age){
this.name =name
this.age=age
}
Person.prototype.setName =function (name) {
this.name=name
}
//借用构造函数继承
function Student(name ,age, price) {
Person.call(this,name,age)
this.price=price
}
//原型链继承
Student.prototype =new Person()
Student.prototype.constructor=Student
var t=new Student('wwd',18,1000)
t.setName('wwd1')
console.log(t.name,t.age,t.price);
5.线程机制与事件机制
1.1 进程与线程
1.2 浏览器内核
1.3 定时器
1.4 JS是单线程
1.5 进程与线程
1.6 事件循环模型
1.7 Web Workers
语句括号问题
- 小括号开头的前一句语句
- 中方括号开头的前一条语句