本文主要是介绍Tracy JS 小笔记 - 数据类型, typeof,类型转换,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
数据类型: 原始值,引用值
原始值 : 不可改变的原始值,是存储在栈里面 stack, 是个有底儿的箱子结构先进后出。
- 原始值 分为五大类 Number, Boolean, String, undefined, null
var a = 1; 我们数据的类型天生就是浮点型,不是整形。
var a = "aa"; var a = 'aa';
var a = undefined; 它是一个类型; 这段话等于 var a; 表示一个变量只声明没有赋值。
var a = none; 表示站位,a 有值,只不过这个值是空, 相当于占座。 可以用于覆盖一个不需要的变量。 - 原始值坚决不能有属性和方法,属性和方法是对象才可以有的
包装类就是原始值调用属性的时候,隐式的中间系统帮忙转换的过程 - var num = 100; num = 200;
它的值得改变的方式是:先申请一个房间叫 num, 里面的值是 100;
再申请一个房间也叫 num 里面的值是 200
然后抹除 第一个 num 的房间名字(房间里的东西 100 还在),房间名字将恢复成 1011, 变成野房间. -
所以说不可改变的原始值的意思是: 一个房间你已经放了东西,你是无法更改这个东西的, 除非说内存满了被其他东西覆盖了。 所以说你电脑里的东西删除了之后,内存里的东西还在的,你删除的只是把变量和变量里面东西的关联删除了。 所以你想让电脑里的数据不被恢复,你删了,格式化了都能还原,你能做的就是大量的灌没有用的文件。 - var num = 100; var num1 = num; num = 200; 此时 num1=100, num1 的值是不受 num 的改变影响的。 它的过程是这样,在栈内存中, 先给 num 申请房间 里面放 100, 在给 num1 申请房间 里面放 num 房间里 copy 出来的的 100,然后再申请一个房间也叫 num 里面的值是 200,然后抹除 第一个 num 的房间名字(房间里的东西 100 还在),房间名字将恢复成 1011, 变成野房间.
- var a = "abc"; var b = new String ("abc");
都是字符串,但是 b 是字符串对象了
a 是原始值, b 是引用值
b 是可以加属性的 eg: b.Name = "Tracy";
同理 new Number(); new Boolean();
var num = new Number(123);
var bol = new Boolean(true); - var num = 4;// 原始值 num 为 4
num.leg = 3;//原始值是没有属性的,这里系统发现傻了吧唧的你给加属性了,系统没办法 就给隐式新 new 了一个对象 new Number(4).leg = 3; 新建对象后,系统马上将该对象删除
consol.log (num.leg); // undefined
这里系统发现你竟然又给原始值调用属性了,就有 new Number(4).leg 这里又新建了一个对象,和上一个对象已经没有什么关系了,所以这个对象的leg 属性是 undefined; - undefined 和 null 是没有包装类的,它就是普通的原始值,没有任何方法和属性
比如说 undefined.toString() 是会报错的
String
- String 虽然是原始值,但是它的底层是基于数组的
- var a = "123";
a[0] 是 "1";
charAt(0) 也是 "1", 这个方式取值会更好一点
a.length 是 3 - 原始值坚决不能有属性和方法,属性和方法是对象才可以有的
包装类就是原始值调用属性的时候,隐式的中间系统帮忙转换的过程
var arr = [1,2,3,4,5]; arr.length = 2; 此时 arr = [1,2]; 字符串是被截断了
var str = "12345";
str.length = 2;
此时 str 仍然保持原来的值
var str = "12345";
str.length = 2; //系统发现,你是一个原始值,你没有 length 属性啊,就新建对象 new String("12345").length = 2 这个新建的对象确实被截断了, 然后马上删除该对象 //然后你打印,就发现,被改变的对象马上就删除了,和你原始值一毛钱关系都没有啊. console.log(str.length); //仍然是 4 -
- concat() //连接字符串
- "hello".indexOf('l');//2 检索第一次出现 l 的位置
- "hello".lastIndexOf('l');//3 检索最后一次出现 l 的位置
- charAt() //返回在指定位置的字符
- chatCodeAt() //返回指定位置字符的 unicode 编码 (当前字节unicode > 255, 那么为汉字 字节长度为 2; 其余字节长度均为 1;)
- match() //找到一个或多个正则表达式的匹配
- substr() //从起始索引号提取字符串中指定数目的字符
- "hello".substring(2,4) // ll 提取字符串中两个指定的索引号之间的字符
"hello".substr(2) // llo 从做开始取剩余部分 - "hello".slice(1, 3) // el 提取字符串的片断,并在新的字符串中返回被提取的部分
- "Hellp world".replace("world", "mars");
- "abc".toUpperCase(); //ABC
"ABC".toLowerCase(); // abc - "hello".split('e'); //["h", "lo"]
- .trim();//移除收尾空白
- strObj.valueOf(); //返回某个字符串对象的原始值
- let str = "a bc"; str.split(' ').join('');
- 求字符转字节数
当前字节unicode > 255, 那么为汉字 字节长度为 2; 其余字节长度均为 1;
var str = "abcd你"; fuction byteReturn(str){ var count = str.length; for(var i = 0; i < str.length; i++) { if(str.charCodeAt(i)> 255) {count ++;} } } -
toString() 方法
- var a = 123; a.toString(); 是可以的
- 123.toString() 是报错的,因为系统首先认为.代表浮点型,数学运算符优先级最高,然后解析不了了,就报错了
- undefined 和 null 是没有包装类的,它就是普通的原始值,没有任何方法和属性
所以 undefined.toString() 和 null.toString() 是会报错的 - 一个对象调用的 toString 得到的结果是 [Object Object]
-
//字符串去重 var str1 = "aaabbb";var unite = function(str){var len = str.length,obj = {},newStr = "";for (var i = 0; i < len; i++){if(!obj[str.charAt(i)]){obj[str.charAt(i)] = "abc";newStr += str[i];}}return newStr; }//找到 a-z 中第一个出现的不重复的字符 var str1 = "aaabbbcdeeef";var unite = function(str) {var len = str.length,obj = {};for (var i = 0; i < len; i++) {if (!obj[str.charAt(i)]) {obj[str.charAt(i)] = "1"; //第一次发现} else {obj[str.charAt(i)] = "2"; //多次发现}}for (var objItem in obj) { if (obj.hasOwnProperty(objItem) && obj[objItem] == 1) {return objItem;}}return "Null"; }
引用值 : 大致是存在堆里面的 heap, 先进先出。
- 引用值包括: array 数组, Object 对象, function, Date, RegExp (正则表达式)
- Demo1 :
var arr = [1,2]; var arr1 = arr; arr.push("3"); 此时 arr1 也变成了 1,2,3
它的过程是 : 给 arr 在栈里申请房间,然后发现 [1,2] 不是原始数据,于是把他们存放到 堆里, 然后房间 arr 里里面放的是堆的地址;
现在又申请了 arr1, 里面放的东西 copy arr 里的堆地址,此时 arr/arr1 指向同一个地址,一个变另一个也就跟着变了。
Tips: 堆里直接放[1,2]不太科学,我们为了方便理解,暂时这么写; 它其实是一个头尾相连的,找到一个头就可以了,以后再说。 -
- var arr = [1,2]; var arr1 = arr; arr = [1,3]; 此时 arr1 就不和 arr 一起变化了,因为它们房间里已经存放的是不同的地址了。
它的过程是 : 给 arr 在栈里申请房间,然后发现 [1,2] 不是原始数据,于是把他们存放到 堆里, 然后房间 arr 里里面放的是堆的地址;
现在又申请了 arr1, 里面放的东西 copy arr 里的堆地址,此时 arr/arr1 指向同一个地址; 接下来 arr = [1,3] 是在堆里起一个新房间放 [1,3], 然后在栈里起一个新房间叫 arr 里面放新的堆地址,接着把栈里原来 arr 房间的编号还原,变成野房间
数组
- 定义1 new: new Array(length/content); var arr = new Array(1,2,3); var arr = new Array(10);
//这个代表建立一个长度为10的数组,每一位的值是 undefined;
var arr = new Array(10.2); //报错,一个数字的时候会默认你要建立一个长度为 10.2 的数组 - 定义2 字面量: var arr = ["1", true, 0, undefined];
- 数组的读取: arr[100]; 即使没有这么长,也不会报错,打印 undefined, 因为数组的底层是基于对象的
- 数组的赋值: arr[100] = 3; //原来是10位,现在给 100 位赋值的话,也是可以的,数组自动被拉长,用 undefined 填空
- 数组长度: arr.length;
-
可以改变原数组的方法,只有这7个方法可以改变原数组
- arr.push(1,2,3); //向数组的末尾添加一个或更多元素,并返回新的长度
- pop() //删除并返回数组的最后一个元素
- shift() //删除并返回数组的第一个元素
- unshift() //向数组的开头添加一个或更多元素,并返回新的长度。
- reverse() //颠倒数组中元素的顺序。
- sort() //对数组的元素进行排序 -> 数字升序排序
数字升序排序 arr.sort(function(a, b){ return a - b;});
但是它其实是把里面的值的字符 ascii 码排序的
比如排序结束后它的顺序是这样的
arr = [1, 10, 3, 4];
所以 sort() 本身其实能实现的不能满足大部分需求,因此它给我们留了一个自定义功能的接口,可以把一个function 当做参数传进去
里面函数的规则- 函数必须写俩形参 a b
- 当返回值是负数时,那么前面的数在前
- 当返回值是正数,那么后面的数在前
- 当返回值是0时,那么不动
- 第一次执行里面的函数的时候,它会把数组的第一位和第二位来对比,然后看返回值来调换位置,然后接着sort 会将 1,3 位对比 接着 1,4 就是一个冒泡排序
var arr = [1,3,4,5,10,2]; //纯数据 升序排序 降序的话 就是 b - a arr.sort(function(a, b){ return a - b;});var arr1 = [1,2,3,4,5,6,7,8,9];//也用它打乱数组顺序 arr1.sort(function(a, b){ return Math.random() - 0.5;});var arr2 = ["q","qq","q", "qqqqq","q你好啊"];//按照字节长度排序 arr2.sort(function(a, b){return retBytes(a) - retBytes(b);});function retBytes(str) {var num = str.length;for (var i = 0; i < str.length; i ++){if(str.charCodeAt(i) > 255) num ++; }return num; }
- splice()//作用:可以删除/插入/替换 元素
//splice (从第几位开始,截取多少的长度,在切口处添加新的数据-optional这个参数传多少个都行)- 删除元素 : 第二个参数传入你要删除几个元素(如果没有传,就删除后面所有的元素)
var arr = [1,2,3,4,5];arr.splice(1,2); //arr 现在 = [1, 4, 5], 它的 [2, 3] 被切走并返回了
arr = [1,2,3,4,5];arr.splice(1); //arr 现在 = [1], 它的 [2, 3, 4, 5] 被切走并返回了 - 插入元素: 第二个参数传入 0,后面跟上想要插入的 items: var arr1 = [1,2,3,8]; arr1.splice(3,0,4,5,7); // arr = [1,2,3,4,5,6,7,8] 相当于在第三位砍了一刀,不切下肉,直接添东西
- 替换元素: 第二个参数,表示我们要替换几个元素,后面接上相同数量的准备替换的元素
- 删除元素 : 第二个参数传入你要删除几个元素(如果没有传,就删除后面所有的元素)
- 数组一般的方法里,都可以带负数,负数的意思是倒数第几位
eg : var arr =[1,2,3,4]; arr.splice(-1,1); // 返回 [4], arr = [1,2,3] 相当于把最后一位给砍掉了
没有改变原数组的方法
- var arr3 = arr1.concat(arr2); //连接两个或更多的数组,并返回结果。
- var str = arr.join(); //把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。
如果不填默认是逗号分隔 == arr.toString();
var arr = [1,2]; var str = arr.join("你好"); // str = "1你好2";互逆的两个方法
split(); 按照指定元素拆分字符串,返回数组
join(); 按照指定元素连接数组,返回字符串 - slice(一个参数的话就是从第几位开始截取 一直截取到最后)
slice(两个参数是从该位开始截取, 截取到该位) //注意,是截取到,不是截取了 (到该位但不包括该位)
var arr = [0,1,2,3,4,5]; var arr1 = arr.slice(2,4); // arr1 = [2, 3]
数组去重, 在原型链上编程
var arr = [1,1,1,2,2,2,3,4]; /*obj { //数组去重思路 2. 把数组的每一位都当做对象的属性名,这个方法叫作 "1" : "随便一个值" "2" : "随便一个值" }*/ Array.prototype.unique = function(){ var tempObj = {},tempArray = [],len = this.length;for(var i = 0; i < len; i ++){if (!tempObj[this[i]]) {tempObj[this[i]] = "aaa"; //随便一个值tempArray.push(this[i]);}}return tempArray; }arr.unique();//开始去重同理字符串去重 var str1 = "aaabbb";var unite = function(str){var len = str.length,obj = {},newStr = "";for (var i = 0; i < len; i++){if(!obj[str.charAt(i)]){obj[str.charAt(i)] = "abc";newStr += str[i];}}return newStr; }
类数组
- test(){console.log(arguments);}
test(1,2,3,4,5);
arguments 里看着是数组,但是 arguments 不能调用任何数组的属性和方法 比如说 arguments.sort(); 会报错类数组 //下面的属性也可以不加引号 var obj = {"0" : "a","1" : "b","2" : "c","length": 3,"push" : Array.prototype.push,"splice" : Array.prototype.splice, }obj.push ("dd"); //此时你观察 obj 的变化, 它变成了一个数组的样子
- 类数组的特点
- 它其实是一个对象
- 属性要为索引(数字)属性
- 必须要有 length 属性
- 最好加上 push 属性 = Array.prototype.push
- 一旦你给类数组加上 splice 方法之后,它的形式就完全变成数值的样子了,不是对象的样子了,但是它仍然是一个对象,只不过是可以完全当作数组来用的一个对象
-
类数组 //下面的属性也可以不加引号 var obj = {"1" : "b", //如果你没有第0位置"2" : "c","length": 2, //长度值也是对的"push" : Array.prototype.push,"splice" : Array.prototype.splice, }obj.push ("dd"); //此时你观察 obj 的变化 //我们要知道 push 的内部原理 Array.prototype.push = function (newItem){this[this.length] = newItem;this.length ++; }那你就会推理说现在 obj 的样子,obj.push ("dd"); 变成数组后第0位置没有值 是 undefined, 然后 obj[3] = "dd", 然后 length ++;obj = {"0" : undefined,"1" : "b", //如果你没有第0位置"2" : "dd","length": 3, //长度值也是对的"push" : Array.prototype.push,"splice" : Array.prototype.splice }
- 类数组的好处
- 它是一个对象,但是还可以完全当做数组来用,也就是说它两家便宜都占了
类数组 //下面的属性也可以不加引号 var obj = {"0" : "b", "1" : "b", "2" : "c","name" : "Tracy","age" : 33,"length": 3, //类数组必须写 length"push" : Array.prototype.push,"splice" : Array.prototype.splice }
- 我们 Dom 方法生成数来的,所有类似于数组的东西, 全是类数组
- 它是一个对象,但是还可以完全当做数组来用,也就是说它两家便宜都占了
typeof 返回值是 string
- typeof 只能返回6 种值 number, string, boolean, undefined; object(不单单指对象,而是指范范的引用值), function
- typeof(typeof(undefined));(string: 这题考的是 typeof 的 6个返回值都是一个 string,不管里面套了几层 typeof, 都是 string)
- 我们如果使用一个没有声明的变量是会报错的,但是 当且仅当 这个变量 a 在 typeof 中使用时不报错的
typeof(a); (undefined) - typeof(NaN); 返回 number
- typeof("123"); 返回: string
- typeof(123); 返回: number
- var obj ={}; typeof(obj); 返回: object
var arr=[]; typeof(arr); 返回: object
var a = null; typeof(null); 返回: object, 这个比较特殊,历史遗留问题 - typeof(undefined); 返回 undefined;
- var aa = function() {....}; typeof(aa); 返回 function
- typeof 另外一种写法 : typeof 123; 空格代替括号。
-
function type(target) //更加精准的返回对象类型 {var ret = typeof(target);// 如果是原始值,直接打印 : 123 numbervar template = { //引用值区分下"[object Array]" : "array", // []"[object Object]" : "object", //{}"[object Number]" : "number - Object", //new Number()"[object Boolean]" : "boolean - Object","[object String]" : "string - Object", }if (target === null) return "null"; // typeof null = objectif (ret == "object") return template[Object.prototype.toString.call(target)];return ret; //原始值 和 function }
数据类型转换,这是 JS 自己独特的特性
显示类型转换 Number
Number
- num = Number("123"); (num = 123)
- num = Number("-123"); (num = -123)
- num = Number(true); (num = 1)
- num = Number(false); Number(null); Number(""); (num = 0;)
- num = Number(undefined); Number(NaN); Number("123abc"); (num = NaN;)
parseInt();
- 它的第一个目的是把里面的东西转换成整数 它是从数字位开始看,看到非数字位截止: 砍断原则
- 常用像素 num = parseInt("100px"); (num = 100)
- parseInt("--100px") (num = NaN)
- num = parseInt(true); parseInt(false); parseInt(undefined);parseInt(null);parseInt("");parseInt("a"); (num = NaN)
- num = parseInt("123.9"); (num = 123, 并没有四舍五入)
- 它的第二点用途:
把里面的东西看成是一个 radix 进制的整数,然后转成 10 进制返回: num = parseInt(转成整数, radix)
radix 的取值范围是 2 ~ 36 - var demo = 20; num = parseInt(demo, 16); (num = 32; 把 demo 的 20 看成了一个 16位进制的数,转换成 10进制后是 32)
parseFloat()
- 它看到第一个点之后的数字,直接砍断,没有四舍五入,其他的和 parseInt 一样
- num = parseFloat("100.2abc") (num = 100.2)
- num = parseFloat("100.2.2") (num = 100.2)
- 如果想对一个数字四舍五入,就用toFixed(); var num = 123.4567; num.toFixed(3); (num = 123.457;)
- Math.ceil(123.234);向上取整 124
- Math.floor(123.999)向下取整 123
- Math.random() 0 到 1 之间的数 不包括 0,1
Math.floor(Math.random()*100); 生成 1~100之间的随机整数
String()/toString()/或者任何数据 + "" 空串
- 无论写啥都变成字符串 var a = String(undefined); (a = "underfined" 字符串)
- var a = NaN; a.toString(); (null 和 undefined 不能用 toString 方法, 会报错。)
- toString 的第二种用法: 把一个 10进制的数转换成 radix 进制 toString(radix),如果压根不是数,那就不进行进制转换。
radix 的取值范围是 2 ~ 36
var demo = 13; demo.toString(16); (输出 d)
var demo = "123abc"; demo.toString(16); (输出 123abc)
Boolean()
- var a = Boolean ("aa"); (a = true)
- var a = Boolean (null); (a = false) 除了这 6个值,其他都是 true:
undefined, null, NaN, ""(空字符串), 0, false
隐形类型转换
- isNaN() 判断括号里的内容是否是 NaN: 它的原理是,先把括号里的东西放入 Number() 中, 转换出来的东西再和 NaN 比对, 因此 Number 里等于 NaN 的结果在这里都等于 true,其他全是 false;
true 的结果:isNaN("123abc"); isNaN(NaN); isNaN(undefined);
false 的结果: 如isNaN(3); - ++; --; +; -; 这个 "+", "-", 是正副,不是加减
它们的原理是, 先把左右的东西放入 Number() 中, 转换出来的东西再进行计算。
var a = "1"; a ++;(a = 2)
var a="abc"; a ++;(a = NaN)
var a = "abc"; +a; (a = NaN, -a也一样) - + 加号 当加号两侧有一个东西是字符串的时候,就都变成字符串
var num = 1 + "1"; (number = "11";) - -;* ; /; 减号乘除 都是先把两侧的东西隐式转换成 Number(), 然后在进行计算
number = 1 * "1"; (number 等于数字类型的 1)
number = "3" - "1"; (number = 2;)
var num = "a" * 1; (num = NaN) - &&; ||; ! 隐式转换用的是 Boolean()
- >; <;>=; <=; 有数字参与比较的话,就会两边先隐式转换成数字
var a = 1 > "2"; (false 有数字参与比较的话,就会两边先隐式转换成数字)
var a = false > true; (a = false, 用的是 0 和 1 来比)
var a = 1> 2> 3; (a = false, 1>2 = false = 0; 0> 3 = false)
没有数字参与比较的话,就没有隐式转换,比的事 ascii 码
var a = "a" > "b"; (a = false; 字符串比的是 Ascii 码顺序)
var a = "1 刘飞" > "2 呵呵" (a = false 先从第一个开始比 ascii, 如果第一个字符已经分出高下,后面就不用比了);
var a = "10"> 9; (a = true; 隐式类型转换)
var a = "10"> "9"; (a = false; 字符转按位逐一比 ascii 码)
var a = undefined > 0; undefined < 0; undefined==0; NaN> 0; NaN < 0; NaN==0; "123abc">0; "123abc"<0; (a=false; 相当于 先把 undefined 用 Number() 隐式转换成 NaN,它和 0 压根就没法比) - ==; !=;只比值,不比类型
var a = 1 == "1"; (a = true;)
var a = 1 == true (a = true)
var a = 1 != true; (a = false)
undefined == null; (true, 这是系统定义的,没有隐式转换规则)
NaN == NaN; (false, 两边的东西一样的都相等, 除了这个特例, 非数啥都不等于,不等于任何东西包括自己)
不发生类型转换的
===; !== 绝对等于和绝对不等于
这篇关于Tracy JS 小笔记 - 数据类型, typeof,类型转换的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!