一、数据类型
JS分两种数据类型:
基本数据类型:**Number、String、Boolean、Null、 Undefined、Symbol(ES6),**这些类型可以直接操作保存在变量中的实际值。
引用数据类型:Object(在JS中除了基本数据类型以外的都是对象,数据是对象,函数是对象,正则表达式是对象)
1、基本数据类型(六种)存放在栈中
基本数据类型是指存放在栈中的简单数据段,数据大小确定,内存空间大小可以分配,它们是直接按值存放的,所以可以直接按值访问
- 1、
Number
数值类型
Number
类型包含整数和浮点数(浮点数数值必须包含一个小数点,且小数点后面至少有一个数字)两种值
注意:在js中浮点数的精度是17位,计算是二进制的计算数 据,所以得到的不是整数
var num1 = 0.1;
var num2 = 0.2;
console.log(num1 + num2); //0.30000000000000004
NaN
:非数字类型,属于数值型基本数据类型
特点:
1):设计任何的NaN操纵都会返回NaN
console.log('ab'/10);
// NaN
2) NaN不等于自身。
console.log(NaN == NaN);// false;
判断是否是Number
类型
1、
isNaN
:判断是否是一个非数字类型,传入的非数字类型,返回true
,否则返回false
注意:传入的参数首先会被转化为数值,如果参数类型为对象类型,先调用valueOf()
方法,再确定该方法返回的值是否可以转换为数值类型,如果不能,再调用toString()
方法,再确定返回值
2、typeof
console.log(typeof 12)
//Number
数值类型的转换:
Number()
:可以用于任何的数据类型
parseInt
:提取 整数数值
paseFloat
:提取浮点数值
- 2、
String
字符串类型
特点:
1、字符串的单引号和双引号作用效果一样
2、字符串有length
属性,可以取得字符串的长度
3、字符串的值是不可变的,所以很多的字符串的api
不会改变原字符串值
字符串转换:
String()
:适用于任何的数据类型(null -> null undefined -> undefined)
toString()
:null
和undefined
没有这个功能
console.log(null.toString()); //error 报错
- 3、
Boolean
布尔类型
该类型只有两个值:true
、false
转换为`boolean`: `Boolean()`
Boolean(undefined):false
Boolean(null):false
Boolean(非空对象包括空数组[]和空对象{}):true
Boolean(非0): true || Boolean(0和NaN):false
Boolean(非空包括空格字符串):true || Boolean(''):false
[注意]true不一定等于1,false也不一定等于0
出现场景:
(1)条件语句导致执行的隐士类转换
(2)字面量或变量定义
类型转换:
Number(true): 1 || Number(false) : 0
String(true):'true' || String(false):'false'
- 4、
Null
空对象指针类型
如果定了一个对象,初始化可以为null,因为null的基本类型是Null
,在if
语句中默认转化为false
,在和数值计算默认为0
出现场景:对象不存在
类型转换:
Booleam(null) false
Number(num) 0
String(null) 'null'
Number(null) // 0
- 5、
Undefined
申明了变量但是没有初始化,默认为undefined
,在if
语句中默认转化为false
,
undefined
:表示‘缺少值’,就是应该有一个值,但是没有定义,以下用法是典型的出现undefined
情况
(1)变量被申明,等于undefined
(2)调用函数时,应该提供的参数没有提供,该参数等于undefined
(3)对象没有赋值的属性,该属性值为undefined
(4)函数没有返回值,默认返回undefined
类型转换:
Boolean(undefined): false
Number(undefined): NaN
String(undefined): 'undefined'
- 6、
Symbol
ES6
新增的一个基本数据类型,表示唯一性
let id1 = Symbol('id');
let id2 = Symbol('id');
console.log(id1 == id2); //false
Symbol
属性类型不支持for...in
和Object.keys()
let id = Symbol("id");
let obj = {
[id]:'symbol'
};
for(let option in obj){
console.log(obj[option]); //空
}
但是也能有方法去访问:Object.getOwnPropertySymbols
方法会返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。
console.log(Object.getOwnPropertySymbols(obj))
// [ Symbol(c) ]
- 介绍两个
Symbol.for
和Symbol.keyFor
(1)、Symbol.for
:方法根据给到的键key
来运行时的symbol
注册表中找到对应的symbol
,如果找到了,则返回它,否则新增一个与该键关联的symbol
,并放入全局的symbol
,这个Symbol值可以是被二次用到的
返回值:
返回由给定的 key 找到的 symbol,否则就是返回新创建的 symbol。
Symbol.for("foo"); // 创建一个 symbol 并放入 symbol 注册表中,键为 "foo"
Symbol.for("foo"); // 从 symbol 注册表中读取键为"foo"的 symbol
Symbol.for("bar") === Symbol.for("bar"); // true,证明了上面说的
Symbol("bar") === Symbol("bar"); // false,Symbol() 函数每次都会返回新的一个 symbol
为了防止冲突,最好给你要放入 symbol 注册表中的 symbol 带上键前缀。
Symbol.for("mdn.foo");
Symbol.for("mdn.bar");
(2)、Symbol.keyFor
方法用来获取 symbol 注册表中与某个 symbol 关联的键。
var globalSym = Symbol.for("foo");
Symbol.keyFor(globalSym); // "foo"
2、引用数据类型
引用数据类型也叫对象数据类型,包括function
,object
,array
,date
,RegExp
等可以可以使用new创建的数据,又叫对象类型,他们是存放在堆(heap)内存中的数据
特点:
- 引用类型的值可以改变
- 引用数据类型可以添加属性和方法
- 引用数据类型的赋值是对象引用
- 引用类型的比较是引用的比较
- 引用类型是同时保存在栈区中和堆区中的,引用类型的存储需要在内存的栈区和堆区中共同完成,栈区保存变量标识符和指向堆内存的地址
注意:在引用类型赋值时对象的引用,所以从一个变量向另一个变量赋值引用类型的值时,同样会将存在在变量中的对象的值赋值一份到新的变量分配的空间,引用类型保存在变量中的时对象在堆存在的地址,所以与基本数据类型的简单赋值不同,这个值的副本实际上时一个指针,而这个指针指向储存在堆内存的一个对象,那么赋值操作后,两个变量都保存了同一个对象的地址,而这个地址都指向同一个对象,因此改变其中任何一个变量,都会影响
在ECMAScript中,Object类型是所有它的实例的基础
Object
的每个实例都具有下列的属性和方法:
- constructor:构造函数
- hasOwnProperty(proertyName)
用于检查给定的属性在当前对象实例(而不是实例的原型)中是否存在。 - isPropertyOf(Object)
用于检查其原型链的对象是否存在于指定对象的实例中,是则返回true,否则返回false。
var a = {} function Person() {}
var p1 = new Person() // 继承自原来的原型,但现在已经无法访问
var Person.prototype = a var p2 = new Person() // 继承a
console.log(a.isPrototypeOf(p1)) // false a是不是p1的原型
console.log(a.isPrototypeOf(p2)) // true a是不是p2的原型
console.log(Object.prototype.isPrototypeOf(p1)) // true
console.log(Object.prototype.isPrototypeOf(p2)) // true
- propertyIsEnumerable(propertyName)
用于检查给定的属性是否可以用 for-in 语句进行枚举。 - toLocaleString()
返回对象的字符串表示,该字符串与执行环境的地区对应。 - toString()
返回对象的字符串表示。 - valueOf()
返回对象的字符串、数值、布尔值表示。通常与toString()方法的返回值相同。
拓展:声明对象的几种方式
<script>
//内置函数
var obj1=new Object();
obj1.name="zhuyu";
obj1.age=21;
obj1.uni=function(){
console.log(this.name+this.age);
}
console.log(obj1);
obj1.uni();
//字面量
var obj2={
name:"zhuyu2",
age:21,
uni2:function(){
console.log(this.name+this.age)
}
}
console.log(obj2);
obj2.uni2();
// 自定义函数
function Obj(name,age){
this.name=name;
this.age=age;
this.uni3=function(){
console.log(this.name+this.age)
}
}
var obj3=new Obj("zhuyu3",21);
console.log(obj3);
obj3.uni3();
// Es6类
class Obj2{
constructor(name,age){
this.name=name;
this.age=age;
}
uni4(){
console.log(this.name+this.age)
}
}
var obj4=new Obj2("zhuyu4",21);
console.log(obj4);
obj4.uni4();
//使用Object.create()
var person={
image:"true",
uni5:function(){
console.log(`名字是${this.name},年龄是${this.age}`);
}
}
var obj5=Object.create(person);
obj5.name="zhuyu5";
obj5.age=21;
obj5.image=false;
obj5.uni5();
console.log(obj5)
</script>
3、基本数据类型和引用数据类型的区别
总结基本数据类型和引用数据类型区别
1、声明变量时内存分配不同
*原始类型:在栈中,因为占据空间是固定的,可以将他们存在较小的内存中-栈中,这样便于迅速查询变量的值
*引用类型:存在堆中,栈中存储的变量,只是用来查找堆中的引用地址。
这是因为:引用值的大小会改变,所以不能把它放在栈中,否则会降低变量查寻的速度。相反,放在变量的栈空间中的值是该对象存储在堆中的地址。地址的大小是固定的,所以把它存储在栈中对变量性能无任何负面影响
2、不同的内存分配带来不同的访问机制
在javascript中是不允许直接访问保存在堆内存中的对象的,所以在访问一个对象时,首先得到的是这个对象在堆内存中的地址,然后再按照这个地址去获得这个对象中的值,这就是传说中的按引用访问。而原始类型的值则是可以直接访问到的。
3、复制变量时的不同
1)原始值:在将一个保存着原始值的变量复制给另一个变量时,会将原始值的副本赋值给新变量,此后这两个变量是完全独立的,他们只是拥有相同的value而已。
2)引用值:在将一个保存着对象内存地址的变量复制给另一个变量时,会把这个内存地址赋值给新变量,也就是说这两个变量都指向了堆内存中的同一个对象,他们中任何一个作出的改变都会反映在另一个身上。(这里要理解的一点就是,复制对象时并不会在堆内存中新生成一个一模一样的对象,只是多了一个保存指向这个对象指针的变量罢了)。多了一个指针
浅拷贝:
深拷贝:
4、参数传递的不同(把实参复制给形参的过程)
首先我们应该明确一点:ECMAScript中所有函数的参数都是按值来传递的。
但是为什么涉及到原始类型与引用类型的值时仍然有区别呢?还不就是因为内存分配时的差别。
1)原始值:只是把变量里的值传递给参数,之后参数和这个变量互不影响。
2)引用值:对象变量它里面的值是这个对象在堆内存中的内存地址,这一点你要时刻铭记在心!
因此它传递的值也就是这个内存地址,这也就是为什么函数内部对这个参数的修改会体现在外部的原因了,因为它们都指向同一个对象。
4、检测类型
- 法一:
typeof
最基本的判断方式,该操作符返回一个表示数据类型的字符串,
number
、string
、boolean
、object
、function
、undefined
、symbol
-
‘undefined’ --未定义的变量或值
-
‘boolean’ --布尔类型的变量或值
-
‘string’ --字符串类型的变量或值
-
‘number’ --数字类型的变量或值
-
‘object’ --对象类型的变量或值,或者null(这个是js历史遗留问题,将null作为object类型处理)
-
‘function’ --函数类型的变量或值
console.log(typeof a); //'undefined'
console.log(typeof(true)); //'boolean'
console.log(typeof '123'); //'string'
console.log(typeof 123); //'number'
console.log(typeof NaN); //'number'
console.log(typeof null); //'object'
var obj = new String();
console.log(typeof(obj)); //'object'
var fn = function(){};
console.log(typeof(fn)); //'function'
console.log(typeof(class c{})); //'function'
- 法二:
instanceof
运算符用来测试一个对象在其原型链中是否存在一个构造函数的
prototype
属性
语法:object instanceof constructor
(1)基础类型
let num = 1
num instanceof Number // false
num = new Number(1)
num instanceof Number // true
这两个都是一样的数值,为什么不一样?
因为instanceof 检测的是:检测目标的__proto__
与构造函数prototype
,相同返回true,不同返回false,对于string
、boolean
是一样的
注意:
new String(1) // String {"1"}
String(1) // "1"
(2) 继承关系的用法
// 判断 foo 是否是 Foo 类的实例 , 并且是否是其父类型的实例
function Aoo(){}
function Foo(){}
Foo.prototype = new Aoo();//JavaScript 原型继承
var foo = new Foo();
console.log(foo instanceof Foo)//true
console.log(foo instanceof Aoo)//true
(3) 复杂类型
let arr = []
arr instanceof Array // true
arr instanceof Object // true
Array.isArray(arr) // true
注意:
(new Number(1)) instanceof Object // true
(4) 其他类型
let reg = new RegExp(//)
reg instanceof RegExp // true
reg instanceof Object // true
let date = new Date()
date instanceof Date // true
date instanceof Object // true
但是Fuction
不一样
function A() {}
let a = new A()
a instanceof Function // false
a instanceof Object // true
A instanceof Function // true
–>分析a
为什么不是?
- a是new出来,所以是经过构造,因此已经是对象,不再是函数,所以false。
- a是经过构造的对象,返回ture没问题。
- 如上所述,A是个函数,因此没什么概念上的问题。但是要知道
A.__proto__
即Function.prototype
是ƒ () { [native code] }
,这是与object以后处于原型链上层的存在,而且与object平级:
let obj = {}
obj.__proto__ // {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
obj.__proto__.prototype // undefined
let A = function() {}
A.__proto__ // ƒ () { [native code] }
A.__proto__.prototype // undefined
本章内容图谱: