js的数据类型到底是怎么划分的?

这是一个令我困扰了很久的问题,基本数据类型是哪几种,引用类型到底包括哪些?
我把原来的笔记汇总了一下。
首先,我们要说明的就是js的数据类型有哪些。

根据ECMA的表述,js的数据类型可以分为7类:

number、string、boolean(相信这三类大家都了解,他们也被成为原始类型)

undefined表示未定义、null表示空。

symbol 为es6新增数据类型。

Object对象,其中js内置了Function、Array、Date等对象。这些对象继承自Object对象,这个又可以展开讲一下原型链。但这里我们只说类型。看下去吧。

数据类型

null和undefined区别

null是一个表示“空”的对象,转为数值时为0undefined是一个表示"此处无定义"的原始值,转为数值时为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
  • 如果第一个字符为非数字,分两种情况:
  1. 字符为+,若后面跟着数字,则返回数字,如果后面没有数字,则返回NAN

    parseInt(+123)
    123
    parseInt('+')
    NaN
    
  2. 字符为其他,返回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-InfinityNaNundefined这几个值会返回falseisFinite对于其他的数值都会返回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]);
}

闭包

  1. 读取函数内部的变量
  2. 让变量始终保持在内存中
  3. 可以封装对象的私有方法和属性
  4. 外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题。

立即表达式

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方法不会跳过undefinednull,但会跳过空位。

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 *()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值