概要介绍
JavaScript 是一种弱类型脚本语言,所谓弱类型指的是定义变量时,不需要什么类型,在程序运行过程中会自动判断类型。
ECMAScript 中定义了 6 种原始类型: Boolean String Number Null Undefined Symbol(ES6 新定义) 注意:原始类型不包含 Object。
题目:类型判断用到哪些方法?
typeof
typeof xxx得到的值有以下几种类型:undefined boolean number string object function、symbol ,比较简单,不再一一演示了。这里需要注意的有三点:
- typeof null结果是object ,实际这是typeof的一个bug,null是原始值,非引用类型
- typeof [1, 2]结果是object,结果中没有array这一项,引用类型除了function其他的全部都是object
- typeof Symbol() 用typeof获取symbol类型的值得到的是symbol,这是 ES6 新增的知识点
instanceof
用于实例和构造函数的对应。例如判断一个变量是否是数组,使用typeof无法判断,但可以使用[1, 2] instanceof Array来判断。因为,[1, 2]是数组,它的构造函数就是Array。同理:
function Foo(name) {
this.name = name
}
var foo = new Foo('bar')
console.log(foo instanceof Foo) // true
题目:值类型和引用类型的区别
除了原始类型,ES 还有引用类型,上文提到的typeof识别出来的类型中,只有object和function是引用类型,其他都是值类型。
根据 JavaScript 中的变量类型传递方式,又分为值类型和引用类型,值类型变量包括 Boolean、String、Number、Undefined、Null,引用类型包括了 Object 类的所有,如 Date、Array、Function 等。在参数传递方式上,值类型是按值传递,引用类型是按共享传递。
// 值类型
var a = 10;
var b = a;
b = 20;
console.log(a); // 10
console.log(b); // 20
上述代码中,a b都是值类型,两者分别修改赋值,相互之间没有任何影响
// 引用类型
var a = {x: 10, y: 20};
var b = a;
b.x = 100;
b.y = 200;
console.log(a); // {x: 100, y: 200}
console.log(b); // {x: 100, y: 200}
上述代码中,a b都是引用类型。在执行了b = a之后,修改b的属性值,a的也跟着变化。因为a和b都是引用类型,指向了同一个内存地址,即两者引用的是同一个值,因此b修改属性时,a的值随之改动。
题目:说出下面代码的执行结果,并分析其原因。
function foo(a){
a = a * 10;
}
function bar(b){
b.value = 'new';
}
var a = 1;
var b = {value: 'old'};
foo(a);
bar(b);
console.log(a); // 1
console.log(b); // value: new
通过代码执行,会发现:
a的值没有发生改变 而b的值发生了改变 这就是因为Number类型的a是按值传递的,而Object类型的b是按共享传递的。
JS 中这种设计的原因是:按值传递的类型,复制一份存入栈内存,这类类型一般不占用太多内存,而且按值传递保证了其访问速度。按共享传递的类型,是复制其引用,而不是整个复制其值(C 语言中的指针),保证过大的对象等不会因为不停复制内容而造成内存的浪费。
再一个例子
var obj = {
a: 1,
b: [1,2,3]
};
var a = obj.a;
var b = obj.b;
a = 2;
b.push(4);
console.log(obj, a, b);
虽然obj本身是个引用类型的变量(对象),但是内部的a和b一个是值类型一个是引用类型,a的赋值不会改变obj.a,但是b的操作却会反映到obj对象上。
存放位置
普通变量和引用变量
引用变量
概要总结
为什么基本数据类型存在栈中,而引用数据类型存在堆中呢?
- 1.基本数据类型比较稳定,大小基本是固定的,占用的内存比较小
- 2.堆比栈大,栈的速度比队快
- 3.堆是无序的,栈的有序的
- 4.引用数据类型的大小的不可控的,动态的,所以储存在堆中