变量
基本类型与引用类型
JS中的基本类型有:number、string、boolean、undefined、null
引用类型有:[]数组、{}对象
区别1:基本类型的值不可以修改,引用类型的值可以修改
var num = 3;
num = 2;//覆盖
var str = "string";
newStr = str.replace('s','');//只是新建了一个变量存储改变后的值,并没有改变原来的字符串
var person = {};
person.name = 'mm';
person.name = 'gg';//对象中的属性发生了改变
delete person.name;//删除了对象中的属性,对象变为空
区别2:基本类型没有且无法添加属性,引用类型可以添加属性
既然基本类型无法添加属性,那在'string'.replace
中,为什么replace
成为了字符串的方法?
基本类型在调用方法时会找到对应的包装对象,例如'str'->String
1->Number
,包装对象把自己有的方法会借给基本类型使用,所以这些方法并不是基本类型自身的方法。
区别3:基本类型存储在栈内存中,引用类型存储在堆内存中
先简单介绍堆栈,栈在内存中是有序排列的,并且每个栈的大小是固定无法扩建;堆在内存中无序排列,并且大小不固定。
基本类型无法修改,所以其大小固定可以放在栈中保存,外部使用其变量名就可以调用到该数字/字符串。
引用类型可以修改所以把他放在堆中,但是堆内存是无序的,很难定位到指定位置,这就需要把堆中的地址保存在栈中便于查找。
变量相等比较
基本类型之间的比较
var num1 = 2;
var num2 = 2;
console.log(num1 == num2);//true
console.log(num1 === num2);//true
var str = '1';
var num = 1;
console.log(str == num);//true
console.log(str === num);//false
当两个基本类型相同时,==与===结果一致,不相同时==只比较值忽略类型,===既比较值也比较类型。
引用类型之间的比较
var mm ={
age:18,
class:1
}
var gg ={
age:18,
class:1
}
console.log(mm === gg);//false
两个对象中虽然内容相同,但是地址却不同指向不同的引用,所以不相等。
var mm ={
age:18,
class:1
}
var gg = mm;
console.log(mm === gg);//true
把mm的地址赋给gg,这样两个地址相同指向同一块内容。
function equalObjs(a,b){
for(var p in a){
if(a[p] !== b[p]) return false;
}
return true;
}
console.log(mm,gg);
在对象方法的比较中,使用for in依次遍历对象中所有的属性方法。
function equalArr(a,b){
if(a.length !== b.length) return false;
for(var i;i < a.length;i++){
if(a[i] !== b[i]) return false;
}
return true;
}
console.log(mm,gg);
在数组的比较中,使用for依次遍历数组中所有数据。
变量值的复制
基本类型的复制
var mm = 4;
var gg = mm;
gg++;
console.log(mm);//4
console.log(gg);//5
基本类型的值复制后两个变量互不干涉。
引用类型的复制
var mm ={
age:18,
class:1
}
var gg = mm;
gg.age++;
console.log(gg.age);//19
console.log(mm.age);//19
引用类型的地址复制后指向同一块内存,一个修改了内容另外一个也会改变。
var mm = {
age:10,
class:1
}
function copyObj(obj){
var newObj = {};
for(var p in obj){
newObj[p] = obj[p];
}
return newObj;
}
gg = copyObj(mm);
引用类型内容的复制,上面程序属于浅拷贝,无法拷贝对象中的引用类型变量,浅拷贝与深拷贝以后单独写一篇。
参数传递
基本类型参数传递
function addScore(num){
return num+1;
}
var score = 10;
console.log(addScore(score));//11
基本类型的参数传递本质是按值传递,形参复制实参的值num == score
引用类型参数传递
function setName(obj){
return obj.name = 'qq';
}
var person = {};
setName(person);
console.log(person.name);//qq
引用类型的参数传递本质也是按值传递,形参获得实参的地址,在函数中形参执行属性变化,实参的属性也同样被改变。
类型检测
typeof 1;//number
typeof '1';//string
typeof true;//boolean
typeof undefined;//undefined
typeof null;//object
typeof {};//object
typeof [];//object
typeof只能判断基本类型,对于引用类型全部认为是object,可以使用instanceof判断引用类型。
[] instanceof Array;//true
[] instanceof Object;//true
{} instanceof Object;//true
1 instanceof Number;//false
instanceof只能检测引用类型,无法检测基本类型(返回false)。
作用域
var name = 'mm';//全局作用域
function fn(){//局部作用域
var sex = 'male';
}
全局作用域:生命周期为整个代码执行过程,在全局作用域中无法使用局部变量。
局部作用域:生命周期为当前函数执行过程,在局部作用域中可以使用全局变量。
console.log(name);//报错
console.log(window.name);//undefined
在作用域中,调用没有定义的变量会报错,如果调用没有定义的属性会返回undefined
作用域链
var name = 'mm';
function fn(){
var name = 'gg';
var sex = 'male';
function fn2(){
var name = 'pp';
var age = 20;
}
}

JS解析机制
JS的解析过程:预解析->逐行解读代码
预解析步骤:先在全局作用域中查找所有的var
并把变量赋值undefined
,再查找函数,直接获取函数整体(在预解析中函数已经声明);然后在局部作用域中重复上述步骤。
逐行解读代码步骤:按照代码中对变量的赋值,把undefined
替换成相应的值。
console.log(name);//undefined
var name = 'mm';
console.log(name);//mm
var age = '20'
function fn(arg){
var sex = 'male';
}
如果出现变量名之间重复,不会影响预解析;如果变量名与函数名重复,只保留函数;如果函数名之间重复,保留后面的函数。函数中的形参算作局部作用域中的变量。不要在if(){}
for(){}
中定义变量和函数。
问题一:
console.log(a);//undefined
var a = 1;
console.log(a);//报错
a = 1;
问题二:
console.log(a);//a()
var a = 1;
console.log(a);//1
function a(){
console.log(2);
}
console.log(a);//1
var a = 3;
console.log(a);//3
function a(){
console.log(4);
}
console.log(a);//3
a();//a=3 不是函数 所以报错
预解析:function a(){}
问题三:
<script>
console.log(a);//报错
</script>
<script>
var a = 1;
</script>
预解析是分标签进行的
<script>
var a = 1;
</script>
<script>
console.log(a);//1
</script>
问题四:
var a = 1;
function fn(){
console.log(a);//undefined
var a = 2;//定义了局部变量
}
fn();
console.log(a);//1
var a = 1;
function fn(){
console.log(a);//1
a = 2;//没有var,修改了全局变量
}
fn();
console.log(a);//2
var a = 1;
function fn(a){
console.log(a);//undefined
a = 2;//形参中定义了a,此处修改了局部变量
}
fn();
console.log(a);//1
var a = 1;
function fn(a){
console.log(a);//1
a = 2;
}
fn(a);//a作为参数传递进来
console.log(a);//1
这是一个前端小白的学习笔记,如果有错误请指正,谢谢大家!!