javascript包含两种不同的数据类型的值:基本类型和引用数据类型。
String、Number、Boolean、null、undefined、Symbol(es6)
Object、data、Array、Set(es6)、Map(es6)等
javascript的变量存储方式 栈内存(stack)和堆内存(heap)
栈:自动分配内存,系统自动释放。里面存放的是基本类型的值和引用类型的地址。
堆:动态分配内存,大小不定,也不会自动释放,里面存的是引用类型的值。
基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值。
引用类型的值是保存在内存中的对象。javascript不允许直接访问内存中的位置,也就是说不能直接
操作对象的内存空间。在操作对象时:实际上是在操作对象的引用而不是实际的对象。
基本类型和引用类型最大的区别实际是 传值与传址的区别
值传递:基本类型采用的是值传递。
地址传递:引用类型则是地址传递,将存放在栈内存中的地址赋值给接受的变量。
在我们进行赋值操作的时候,基本数据类型的赋值(=)是在内存中开辟一段栈内存,然后再将值赋值到新的栈中
var a = 10;
var b = a;
a++;
console.log(a); //11
console.log(b); //10
//基本类型的赋值 两个变量是两个独立互不影响的变量
但是引用类型的赋值是传址。只是改变了指针的指向。
也就是说引用类型的赋值是对象保存在栈中的地址的赋值,这样的话两个变量就指向同一个对象,因此两者之间操作互相有影响。
var a = {};
var b = a;
a.name = "jane";
console.log(a.name,b.name) //jane,jane
b.age =18;
console.log(a.age,b.age)//18,18
console.log(a ===b);//true
占内存中的变量一般都是已经大小或者有范围上限的,算作一种简单存储。
而堆内存存储的对象类型数据对于大小这方面,一般都是未知的。
个人认为,这也就是为什么null作为一个object类型的变量却存储在栈内存中的原因了。
因此当我没定义了一个const对象的时候,我们说的常量其实是指针,就是说const对象对应的堆内存指向是不变的,但是堆内存中的数据本身的大小或者属性是可变的。
对于const定义的基础变量而言,这个值就相当于const对象的指针,是不可变的。
说到这里,有一个十分容易忽略的点,使用new关键字初始化之后是不存在栈内存中的。根据构造函数生成新实例,这个时间生成的是对象,而不是基本类型
var a = new String("123");
var b = String("123");
var c = "123";
console.log(a==b,a==c,b==c); //true,true,true
console.log(a===b,a===c,b===c); //false,false,true
console.log(typeof a ) //"object"
可以看出new一个String,出来的是对象,而直接字面量赋值和工厂模式出来的都是字符串。但是根据我们上面的分析大小相对固定可预期的几遍是对象也可以存储在栈内存的。比如null,为啥这个不是呢
var a = new String("123");
var b = new String("123");
console.log(a==b,a===b); //false false
很明显,如果a,b是存储在栈内存的话,两者明显应该是相等的,就像null === null是true一样,
但结果两者并不相等,说明两者都是存储在堆内存中的,指针指向不一致。
我们常说的值类型和引用类型其实说的就是栈内存和堆内存变量,再想想值传递和引用传递、深拷贝和浅拷贝,都是围绕堆栈内存展开的,一个是处理值,一个是处理指针。
基本类型的值是不可变的,除非重新给他赋值,引用类型的值是可变的
var name = ‘jozo‘;
name.toUpperCase(); //‘JOZO‘
name[0] = "mm";
console.log(name); //‘jozo‘
name = "song";
console.log(name); //"song"
var person = {};
person.name = "jozo";
console.log(person); //{name:"jozo"};
基本类型的比较是 值的比较
var a = 1;
var b = true;
console.log(a == b);// true
引用类型的比较是 引用的比较
var person1 = {};
var person2 = {};
console.log(person1 == person2); //false
基本类型的变量是存放在栈内存的。
引用类型的值是保存在栈内存和堆内存中的对象。
复制时,基本类型是直接复制了一个新的变量,新旧两个变量之间没有关系
引用类型复制了新的变量,但这个变量是一个指针,新旧两个指针指向同一个对象。
var a = 10;
var b = a;
a++;
console.log(a); //11
console.log(b); //10
//基本类型的赋值 两个变量是两个独立互不影响的变量
var a = {};
var b = a;
a.name = "jane";
console.log(a.name,b.name) //jane,jane
b.age =18;
console.log(a.age,b.age)//18,18
console.log(a ===b);//true
一般来说栈内存线性有序存储,容量小,系统分配效率高。而堆内存首先要在堆内存新分配存储区域,之后又要把指向存储到栈内存中,效率相对就要低一些了。
垃圾回收方面,栈内存变量基本上用完就回收了,而堆内存中的变量因为存在很多不确定的引用,只有当所有调用的变量全部销毁之后才能回收。
声明新变量的时,可以使用关键词 new 来声明起类型
var a = new String;
var b = new Number;
var c = new Boolean;
var d = new Object;
var e = new Array;
基本数据类型的检测: 大多使用typeof
console.log(typeof 2); //number
console.log(typeof "2"); //string
console.log(typeof null); //object
console.log(typeof undefined); //undefined
console.log(typeof function(){}); //function
console.log(typeof true); //boolean
引用数据类型检测 instanceof Object.prototype.toString.call();
instanceof并不能完全准确检查数据类型
A instanceof B 只是判断A的原型是不是B
let arr = [];
console.log(arr instanceof Array);//true
console.log(arr instanceof Object); //true
Object.prototype.toSting.call能更精准的区分数据类型
console.log(Object.prototype.toString.call("1")); //"[object String]"
console.log(Object.prototype.toString.call(1)); //"[object Number]"
console.log(Object.prototype.toString.call(true)); //"[object Boolean]"
console.log(Object.prototype.toString.call(undefined)); //"[object undefined]"
console.log(Object.prototype.toString.call(null)); //"[object Null]"
console.log(Object.prototype.toString.call({})); //"[object Object]"
console.log(Object.prototype.toString.call([])); //"[object Array]"
var obj = new Object();
var arr = new Array();
//添加方法
obj.name = "小明";
//添加属性
obj.sleep = function(){
console.log(this.name+"在睡觉")
}
var obj1 = {};
obj1.name = "小红";
var obj2 = {
name:"小兰",
say:function(){
console.log(this.name+"说大家好");
}
}
function createObj(name,age){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.say = function(){
console.log(this.name+"说你好");
}
return obj;
}
var p1 = createObj("小明",20);
var p2 = createObj("小红",18);
构造函数方法 首字母大写
function Person(name,age){
this.name = name;
this.age = age;
this.say = function(){
console.log(this.name+"说你好");
}
}
var p1 = new Person("小明",20);
var p2 = new Person("小红",18);
var p = {name:"小明"};
var obj = Object.create(p)
面向过程 --站在一个执行者的角度去做事情;
面向对象 --站在指挥者的角度,是一种开发思想;
洗衣服作为例子:
面向过程:
1. 找个盆子
2. 收集要洗的衣服
3. 放水放洗衣液
4. 开始洗,洗完了晒
面向对象:
1. 找个对象
2. 让他去洗
3. 检查洗好了没,然后晾晒
原文:https://www.cnblogs.com/cntt/p/13409606.html