这是一个令我困扰了很久的问题,基本数据类型是哪几种,引用类型到底包括哪些?
我把原来的笔记汇总了一下。
首先,我们要说明的就是js的数据类型有哪些。
根据ECMA的表述,js的数据类型可以分为7类:
number、string、boolean(相信这三类大家都了解,他们也被成为原始类型)
undefined表示未定义、null表示空。
symbol 为es6新增数据类型。
Object对象,其中js内置了Function、Array、Date等对象。这些对象继承自Object对象,这个又可以展开讲一下原型链。但这里我们只说类型。看下去吧。
文章目录
数据类型
null和undefined区别
null
是一个表示“空”的对象,转为数值时为0
;undefined
是一个表示"此处无定义"的原始值,转为数值时为NaN
。
布尔值转化
一下六个值会被转为false,其余均被转为true。
undefined
null
false
0
NaN
""
或''
(空字符串)
其中空数组和空对象对应布尔值为true。
数值
浮点数
javascript内部没有整数,转为浮点数进行。因此在两个浮点数比较的时候,往往会出现差错。
经典面试题:
0.1+0.2==0.3 //false
解决方法1: 通过精度判断
var delta = 1e-5; // 定义精度精确到0.00001
var a = 0.1+0.4;
var b = 0.2+0.3;
// 判断相差小于精度就认为相等
var isEqual = function (a,b,delta) {
let sum = a + b;
if(a + b - sum < delta) {
console.log('a + b == sum');
}};
isEqual(a, b, delta)
解决方法2: toFixed()方法
自带的toFixed方法有问题,重写。
Number.prototype.toFixed=function (d) {
var s=this+"";
if(!d)d=0;
if(s.indexOf(".")==-1)s+=".";
s+=new Array(d+1).join("0");
if(new RegExp("^(-|\\+)?(\\d+(\\.\\d{0,"+(d+1)+"})?)\\d*$").test(s)){
var s="0"+RegExp.$2,pm=RegExp.$1,a=RegExp.$3.length,b=true;
if(a==d+2){
a=s.match(/\d/g);
if(parseInt(a[a.length-1])>4){
for(var i=a.length-2;i>=0;i--){
a[i]=parseInt(a[i])+1;
if(a[i]==10){
a[i]=0;
b=i!=1;
}else break;
}
}
s=a.join("").replace(new RegExp("(\\d+)(\\d{"+d+"})\\d$"),"$1.$2");
}if(b)s=s.substr(1);
return (pm+s).replace(/\.$/,"");
}return this+"";
};
parseInt
当小数点后位数超过5,则自动转化为科学计数
parseInt对字符串转化为整数,如果输入是浮点数,先转成字符串。
Int过程中挨个遍历字符,遇到第一个非数字的字符就返回。
parseInt('123&')
123
parseInt(123+.3)
123
parseInt(123++=.3)
VM1796:1 Uncaught SyntaxError: Invalid left-hand side expression in postfix operation
- 如果第一个字符为非数字,分两种情况:
-
字符为+,若后面跟着数字,则返回数字,如果后面没有数字,则返回NAN
parseInt(+123) 123 parseInt('+') NaN
-
字符为其他,返回NaN
parseInt('&123') NaN
- 如果第一个字符为0:
第二个字符为x或X,则按16进制解析
第二个字符为数字,按10进制解析。
parseInt(023)
19
parseInt(0x23)
35
当小数点后0的连续位数为5,则自动转化为科学计数,自动计数转化为字符串
parseInt(0.000008)
8
parseInt(0.1234568)
0
parseInt(0.000008)
0
parseFloat
将字符串转化为float
可以将科学计数法进行转换
如果第一个字符不能转化为浮点数,则返回NaN。
isNaN
判断一个值是否为NaN. 数值会返回false。
非数值会先Number,再使用isNaN。即
isNaN('Hello') // true
// 相当于
isNaN(Number('Hello')) // true
字符串、对象、数组都返回true。
判断isNaN的方法
唯有NaN不等于自身。
function myIsNaN(value) {
return value !== value;
}
isFinite
返回一个布尔值
除了Infinity
、-Infinity
、NaN
和undefined
这几个值会返回false
,isFinite
对于其他的数值都会返回true
。
字符串
可以通过数组索引的形式访问,但是并不能通过索引改变值。
var s = 'hello';
delete s[0];
s // "hello"
s[1] = 'a';
s // "hello"
s[5] = '!';
s // "hello"
length也不可改变
对象
js中的对象是浅拷贝,指向同一个内存地址。(其中数组、函数都是特殊的对象)
原始类型都是值的拷贝。深拷贝
查看属性方法
var obj = {
key1: 1,
key2: 2
};
Object.keys(obj);
// ['key1', 'key2']
删除属性
delete
只能删除本身的属性,不能删除继承的属性。
是否存在属性
in 判断是否存在属性,但不能判断是否为继承属性
hasOwnProperty判断是否为自身属性
var obj = {};
if ('toString' in obj) {
console.log(obj.hasOwnProperty('toString')) // false
}
函数
一等公民
属性和方法
name属性返回函数的名字
length属性返回函数定义时的参数个数
toString()返回原生代码
作用域
全局作用域
函数作用域
块级作用域
总之,函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域。
正是因为这种特性,形成了闭包。
var a = 1;
var x = function () {
console.log(a);
};
function f() {
var a = 2;
x();
}
f() // 1
上面的代码中,x函数的作用域在全局,是定义时的作用域。
参数传递
如果是基本数据类型,是传值。
如果是复合类型,则是传地址。
在函数内部更改属性值,会改变。
函数内部可以使用arguments获取传递的所有参数。虽然可以通过数组形式传递参数,但是并不具有数组的方法。
两种转化为数组的方法:
var args = Array.prototype.slice.call(arguments);
// 或者
var args = [];
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
闭包
- 读取函数内部的变量
- 让变量始终保持在内存中
- 可以封装对象的私有方法和属性
- 外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题。
立即表达式
https://wangdoc.com/javascript/types/function.html 5.2部分详细讲解
以function开头是语句,
function(){ /* code */ }();
// SyntaxError: Unexpected token (
所以这样写是不行的。
为了避免解析上的歧义,JavaScript 引擎规定,如果function
关键字出现在行首,一律解释成语句。因此,JavaScript 引擎看到行首是function
关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。
解决方法就是不要让function
出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面。
(function(){ /* code */ }());
// 或者
(function(){ /* code */ })();
数组
数组是特殊的对象,键名为数字 0—
length很特殊,其默认值为最大的数字键名+1.如果添加字符串的键名,length的值是不会变的。
length不过滤空位。
如果在数组
方法:
Array.isArray() 返回是否为数组
valueOf
方法是一个所有对象都拥有的方法,表示对该对象求值。不同对象的valueOf
方法不尽一致,数组的valueOf
方法返回数组本身。
toString
方法也是对象的通用方法,数组的toString
方法返回数组的字符串形式。
push() 末尾添加新元素,并返回数组长度
pop() 删除最后一个元素,并返回该元素
shift() 删除第一个元素,~
unshift() 数组第一个位置添加元素,并返回数组长度
join()
方法以指定参数作为分隔符,将所有数组成员连接为一个字符串返回。如果不提供参数,默认用逗号分隔。
通过call
方法,这个方法也可以用于字符串或类似数组的对象。
Array.prototype.join.call('hello', '-')
// "h-e-l-l-o"
var obj = { 0: 'a', 1: 'b', length: 2 };
Array.prototype.join.call(obj, '-')
// 'a-b'
concat
方法用于多个数组的合并。它将新数组的成员,添加到原数组成员的后部,然后返回一个新数组,原数组不变。
如果数组成员包括对象,concat
方法返回当前数组的一个浅拷贝。所谓“浅拷贝”,指的是新数组拷贝的是对象的引用。
var obj = { a: 1 };
var oldArray = [obj];
var newArray = oldArray.concat();
obj.a = 2;
newArray[0].a // 2
上面代码中,原数组包含一个对象,concat
方法生成的新数组包含这个对象的引用。所以,改变原对象以后,新数组跟着改变。
reverse
方法用于颠倒排列数组元素,返回改变后的数组。注意,该方法将改变原数组。
slice()
方法用于提取目标数组的一部分,返回一个新数组,原数组不变。上面代码中,最后一个例子slice()
没有参数,实际上等于返回一个原数组的拷贝。如果slice()
方法的参数是负数,则表示倒数计算的位置。
splice()
方法用于删除原数组的一部分成员,并可以在删除的位置添加新的数组成员,返回值是被删除的元素。注意,该方法会改变原数组。splice
的第一个参数是删除的起始位置(从0开始),第二个参数是被删除的元素个数。如果后面还有更多的参数,则表示这些就是要被插入数组的新元素。
sort
方法对数组成员进行排序,默认是按照字典顺序排序。排序后,原数组将被改变。
如果想让sort
方法按照自定义方式排序,可以传入一个函数作为参数。
map
方法将数组的所有成员依次传入参数函数,然后把每一次的执行结果组成一个新数组返回。
forEach
方法与map
方法很相似,也是对数组的所有成员依次执行参数函数。但是,forEach
方法不返回值,只用来操作数据。这就是说,如果数组遍历的目的是为了得到返回值,那么使用map
方法,否则使用forEach
方法。 forEach
方法不会跳过undefined
和null
,但会跳过空位。
filter
方法用于过滤数组成员,满足条件的成员组成一个新数组返回。
reduce
方法和reduceRight
方法依次处理数组的每个成员,最终累计为一个值。它们的差别是,reduce
是从左到右处理(从第一个成员到最后一个成员),reduceRight
则是从右到左(从最后一个成员到第一个成员),其他完全一样。
indexOf
方法返回给定元素在数组中第一次出现的位置,如果没有出现则返回-1
。
正则表达式
修饰符
i 不区分大小写
g 全局匹配
一个正则表达式可以有多个修饰符吗?
量词
+ 若干个
{n} 正好出现几次
{n, m} n-m次
{n, }最少n次
?=={0,1}
* {0,}任意次尽量不要用
//其中?的使用拿固定电话前缀举例
(0\d{2,3}-)?[1-9]\d{7}(-\d{1,5})?
//邮箱匹配
//一串英文、数字、下划线 @ 一串英文、数字 .一串英文
//当^ 不出现在括号内,表示行首,$表示行尾
(\w+@[a-z0-9]+\.[a-z])
var reg = /^\w+@[a-z0-9]+\.[a-z]$/
var str = '1294343193@qq.com'
var valEmail = function(str){
if(reg.test(str)){
console.log('It\'s a right email address.')
}
else {
console.log('It\'s a wrong email address.')
}
}
valEmail('123444')
表达式
[ab] 查找包含方括号内字符的字符串
[a-f] 查找a-f的字符
^ 除此之外
转义字符
\d ==[0-9] 0-9的任意一个数字
\D ==[^ 0-9 ] 除了0-9之外的所有字符
. 任意字符(尽量不要使用)
\w 英文、数字、下划线 [a-z0-9_]
\W 除了
\s 空白字符
\S 非空白
var str = 'abg abc pcbgbf'
var reg1 = /[ab][c-g]/g
var reg2 = /[ab][cg]/g
str.match(reg1) // ["bg", "bc", "bg", "bf"]
str.match(reg2) // ["bg", "bc", "bg"]
结合字符串方法
search
var regex = new RegExp('xyz', 'i');
var val = 'Xyzdew'
val.search(regex)
match
var reg = /\d/g //\d==[0-9]
var a = '123 3 2 ))))1===='
var result = a.match(reg) // ["1", "2", "3", "3", "2", "1"]
var reg1 = /\d+/g //\d==[0-9]
var result = a.match(reg1) // ["123", "3", "2", "1"]
replace
敏感词过滤
var reg =/淘宝|百度/g
var str = '淘宝是百度待定'
var txt = str.replace(reg,'***'); //"***是***待定"
去除html标签 标签规则:<除了<>之外任意字符>
var reg =/<[^<>]+>/g
var str ='<li><a href="//www.runoob.com/">首页</a></li><li><a href="/html/html-tutorial.html">HTML</a></li>'
txt = str.replace(reg,'') //"首页HTML"
String对象
实例方法
charAt
方法返回指定位置的字符,参数是从0
开始编号的位置。
charCodeAt()
方法返回字符串指定位置的 Unicode 码点(十进制表示),相当于String.fromCharCode()
的逆操作。
concat
方法用于连接两个字符串,返回一个新字符串,不改变原字符串。
slice
方法用于从原字符串取出子字符串并返回,不改变原字符串。它的第一个参数是子字符串的开始位置,第二个参数是子字符串的结束位置(不含该位置)。
类型判断
js作为一种动态类型的语言,虽然没有类型判断会有很多好处,但是往往会造成不必要的麻烦。所以,ts最重要的是提供了类型判断。
那么,js本身又提供了哪些类型判断呢?
首先列出要判断的类型:
Number, String, Boolean,Object,Array, Json, Function, undefined, Null, Date, RegExp, Error
typeof
缺点,只能区分基本数据类型(number string boolean object),剩余的均被检测为object
其中的特殊类型:
null 是 object类型
NaN 是number类型
使用new的时候,new Function返回的类型是function; 其他的返回类型均为object
instanceof
undefined和null检测为object
对于number,string,boolean这三种类型,
只有通过构造函数定义比如:
let num =new Number(1);
let str = new String('abc');
let bool = new Boolean(true);
这样定义才能检测出.
let num = 1; let str = 'abc'; let bool = true;
这样定义是检测不出来的
作用:
1:识别对象类型;
2:判断一个对象是否属于某个构造函数的实例
语法:变量名 instanceof 数据类型 || 实例对象名 instaneof 构造函数
原理: 左边是一个实例对象,右边是一个构造函数,instanceof会检查构造函数的原型对象prototype是否在左边对象的原型链上,有则返回true,否则返回false.
内部代码:
instanceof (A,B) = {
var L = A.__proto__;
var R = B.prototype;
if(L === R) {
//A的内部属性__proto__指向B的原型对象
return true;
}
return false;
}
constructor
判断所有数据类型
语法:变量名.constructor === 数据类型
str.constructor===String //true
num.constructor===Number //true
obj.constructor===Object //true
arr.constructor===Array //true
new Date().constructor===Date //true
f.constructor === Boolean
constructor指向的构造函数可以被修改。
Object.prototype.toString()
https://www.jianshu.com/p/e4237ebb1cf0 看的不是很懂
function *()