这是一个令我困扰了很久的问题,基本数据类型是哪几种,引用类型到底包括哪些? 我把原来的笔记汇总了一下。 首先,我们要说明的就是js的数据类型有哪些。
根据ECMA的表述,js的数据类型可以分为7类:
number、string、boolean(相信这三类大家都了解,他们也被成为原始类型)
undefined表示未定义、null表示空。
symbol 为es6新增数据类型。
Object对象,其中js内置了Function、Array、Date等对象。这些对象继承自Object对象,这个又可以展开讲一下原型链。但这里我们只说类型。看下去吧。
null是一个表示“空”的对象,转为数值时为0;undefined是一个表示"此处无定义"的原始值,转为数值时为NaN。
一下六个值会被转为false,其余均被转为true。
undefinednullfalse0NaN""或''(空字符串)其中空数组和空对象对应布尔值为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+""; };当小数点后位数超过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将字符串转化为float
可以将科学计数法进行转换
如果第一个字符不能转化为浮点数,则返回NaN。
判断一个值是否为NaN. 数值会返回false。
非数值会先Number,再使用isNaN。即
isNaN('Hello') // true // 相当于 isNaN(Number('Hello')) // true字符串、对象、数组都返回true。
判断isNaN的方法
唯有NaN不等于自身。
function myIsNaN(value) { return value !== value; }返回一个布尔值
除了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中的对象是浅拷贝,指向同一个内存地址。(其中数组、函数都是特殊的对象)
原始类型都是值的拷贝。深拷贝
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"实例方法
charAt方法返回指定位置的字符,参数是从0开始编号的位置。
charCodeAt()方法返回字符串指定位置的 Unicode 码点(十进制表示),相当于String.fromCharCode()的逆操作。
concat方法用于连接两个字符串,返回一个新字符串,不改变原字符串。
slice方法用于从原字符串取出子字符串并返回,不改变原字符串。它的第一个参数是子字符串的开始位置,第二个参数是子字符串的结束位置(不含该位置)。
js作为一种动态类型的语言,虽然没有类型判断会有很多好处,但是往往会造成不必要的麻烦。所以,ts最重要的是提供了类型判断。
那么,js本身又提供了哪些类型判断呢?
首先列出要判断的类型:
Number, String, Boolean,Object,Array, Json, Function, undefined, Null, Date, RegExp, Error
缺点,只能区分基本数据类型(number string boolean object),剩余的均被检测为object
其中的特殊类型:
null 是 object类型
NaN 是number类型
使用new的时候,new Function返回的类型是function; 其他的返回类型均为object
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 === 数据类型
str.constructor===String //true num.constructor===Number //true obj.constructor===Object //true arr.constructor===Array //true new Date().constructor===Date //true f.constructor === Booleanconstructor指向的构造函数可以被修改。
https://www.jianshu.com/p/e4237ebb1cf0 看的不是很懂
function *()