基础总结深入
一、数据类型
基本值类型:
String:任意字符串、Number:任意的数字、boolean:true/false、undefined:undefined、null:null
对象引用类型:
Object:任意对象、Function:一种特别的对象(可以执行)、Array:一种特别的对象(内部数据是有序的)
判断:
typeof:返回数据类型的字符串表达,可以判断:undefined / 数值 / 字符串 / 布尔值
instanceof:判断对象的具体类型,返回的是boolean值
===:判断值和类型全等,可以判断:undefined,null
<script>
var a;
console.log(typeof a === "undefined"); //返回的是true typeof返回的是'undefined'
var b = {}
console.log(b instanceof Object) //true
</script>
二、数据类型相关问题
1、undefined与null的区别?
答:undefined代表定义未赋值。null定义了并赋值了,只是值为null
2、什么时候给变量赋值为null呢?
答:初始赋值,表明将要赋值为对象。结束前,让对象称为垃圾对象(被垃圾回收器回收)
3、基本类型:存储就是基本类型的数据、引用类型:保存的是地址值
三、数据_变量_内存
数据:存储在内存中代表特定的信息。本质是010101010...
内存:可存储数据的空间(临时的)。栈:全局变量\局部变量。堆:对象
变量:可变化的量,变量名 变量值组成。
四、数据_变量_内存相关问题
1、var a = xxx,a内存中到底保存的是什么
答:xxx是基本数据,保存的就是这个数据。xxx是对象,保存的是这个数据。xxx是一个变量,保存的可能是(基本类型,也可能是地址值)
2、引用变量转递的是什么?
答:传递的是一个地址值,一个对象赋值一个新对象地址就不一样了
3、在js调用时传递变量参数,是值传递还是引用传递?
答:传递的时候就可以看他类型,判断他传递得类型
4、JS引擎如何管理内存
内存生命周期:分配最小内存空间,得到他的使用权,存储数据,可以反复操作。释放小内存空间
释放内存:局部变量函数执行完自动释放。对象成为垃圾对象,垃圾回收器回收
五、对象
对象:多个数据的封装体,用来保存多个数据的容器,一个对象代表现实的一个事物
为什么要使用对象:统一管理多个数据
对象的组成:属性名(本质上是字符串)和属性值(任意类型)组成
访问对象内部数据
.属性名:编码简单,有时不能用
["属性名"]:编码麻烦,能通用:属性名包含特殊字符 - 空格 属性名不确定时用
<script>
var a = {}
a["context-type"] = "html/text"
</script>
六、函数
1、什么是函数:实现特定功能的封装体。只有函数可以执行,其余的不行
2、为什么要使用函数:提高代码的复用性,便于阅读交流
3、如何定义函数:
<script>
function fn1(){ //函数生命式
console.log(123);
}
var fn2 = function(){ //表达式
console.log(123);
}
</script>
4、如何执行函数:test():直接调用、obj.test():通过对象调用、new test():new调用
test.apply(obj):临时让test成为obj的方法进行调用。类式obj.test
test.call(obj):可以让一个函数成为指定任意对象的方法进行调用
<script>
var obj = {}
function fn1(){
console.log(123);
}
fn1.call(obj)
fn1.apply(obj)
</script>
七、回调函数
生命函数才是回调函数:你定义的、你没有调、但他最终执行了
常见的回调函数:dom事件回调函数,定时器回调函数、ajax请求回调函数、生命周期回调函数
<script>setTimeout(()=>{console.log(123);},3000)</script>
八、IIFE
1、理解:全程Immediately-Invoked Function Expression 立即执行函数
2、作用:不会污染外部命名
<script>(function(){console.log(123);})()</script>
九、函数中的this
this是什么:所有函数本质上都是通过某个对象调用的,如果没有直接指定就是window、所有函数内部都有一个this,他的值是调用函数的当前对象
如何确定this的值:test():window p.test():p new test():新创建的对象 p.call(obj,test):obj
函数高级
一、函数的prototype属性
每个属性都有一个prototype属性,它默认指向一个Object空对象(即称为:原型对象),原型对象中有一个属性constructor,她指向函数对象
给原型对象添加属性(一般都是方法):作用函数的所有实例对象自动拥有原型中的属性(方法)
<script>
function Fun(){}
Fun.prototype.test = function(){
console.log(123);
}
var fn = new Fun()
fn.test()
console.log(fn);
</script>
二、显式原型与隐式原型
每个函数function都有一个prototype,即显式原型(属性)
每个实例对象都有一个__proto__,可称为隐式原型(属性)
对象的隐式原型的值为其对应构造函数的显示原型的值
函数的prototype属性:在定义函数时自动添加的,默认值是一个空的Object对象
对象的__proto__属性:创建对象时自动添加的,默认值为构造函数的protope属性值
程序员能直接操作显示原型,但不能直接操作隐式原型(ES6之前)
三、原型链
访问一个对象属性时:
现在自身属性中查找,找到返回
如果没有,再沿着__proto__这条链向上查找,找到返回
如果最终没有找到,返回undefined
读取对象的属性值时:会自动到原型链中查找
设置对象的属性值时:不会查找原型链,如果当前对象没有此属性,直接添加属性并设置其值
方法一般定义在原型中属性一般通过构造函数定义在对象本身上
如果指定的属性在指定的对象或其原型链中,则 in
运算符返回 true
<script>
var obj = {name:"张三"}
console.log("name" in obj); //true
</script>
四、instanceof是如何判断的
表达式:A instanceof B 如果B函数的显示原型对象在A对象的原型链上,返回true,否则返回false
五、变量提升与函数提升
变量提升:通过var定义的变量在语句之间就可以访问到,但是值为undefind
函数声明提升:通过function声明的函数,在之前就可以调用
先执行变脸提升,在执行函数提升
//执行顺序
var a;
function a(a){}
a=2
a(1)//报错
六、执行上下文
全局执行上下文:window a = 3 相当于 window.a
函数执行上下文:function(){ } 一个函数算一个上下文
七、作用域和作用域链
上下文环境(对象)是从属于所在的作用域、全局上下文环境====》全局作用域、函数上下文环境===》函数作用域
作用域是静态的,并不会说放在其他函数里执行而改变作用域的位置
<script>
var x = 10
function fn(){
console.log(x);
}
function show(f){
var x = 20
f()
}
show(fn) //输出的是10
</script>
八、闭包
小知识:for(var a = 0,length = array.length; a < length;a ++) 这样能提升效率
如何产生闭包:当一个嵌套内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包
使用函数内部的变量在函数执行完后,任然存活在内存中(延长了局部变量的生命周期)
让函数外部可以操作(读写)到函数内部的数据(变量/函数)
<script>
function fn(){
var a = 10
function add(){
a++
console.log(a);
}
function reduce(){
a--
console.log(a);
}
return {add,reduce}
}
var obj = fn()
obj.add() //11
obj.reduce() //10
</script>
闭包的缺点:
函数执行后,函数内的局部变量没有释放,占用内存时间会变长,容易造成内存泄漏
解决:能不用闭包就不用,及时释放