2021-01-02
JS的数据类型
基本数据类型(原始值类型)
- number
- NaN
- Infinity
- string
- boolean
- null
- undefined
- symbol
- 可以做为对象的属性(属性的类型不是传统的String了)
- 创建唯一值的
- bigint
引用数据类型(对象类型)
- object
- 普通对象
- 数组对象
- 正则对象
- 日期对象
- Math数学函数对象
- function
数据类型检测(js中有且只有四种)
- typeof 检测数据类型的逻辑运算符
- instanceof 检测是否为某个类的实例
- constructor 检测构造函数
- Object.prototype.toString.call 检测数据类型
/* * 数据类型检测 * typeof 返回字符串 * typeof null ->"object" * typeof 实现CALL的对象「函数、箭头函数、生成器函数、构造函数」 ->"function" * typeof 剩下未实现CALL的对象 ->"object" * * ECMAScript提供的内置类型在计算机底层都是按照二进制数据存储的 * 以对应的数字开始代表不同的类型 * 1:数字 010:浮点数 * 100:字符串 * 110:布尔 * -2^30:undefined * 000000:null * 000:对象 * 设计上的缺陷 */ // console.log(typeof typeof []); //->”string“ // 数据类型转换 // 对象转换为数字/字符串「字符串拼接、数学运算、特殊方法处理、==比较(隐式转换、显式转换)...」 // + 首先检测对象的 Symbol.toPrimitive 这个属性,获取其原始值 // + 如果没有这个属性,则继续调用它的valueOf,也是获取原始值 // + 如果值不是原始值,则继续调用toString转换为字符串 // + 再把字符串基于Number转换为数字 /* let obj = { name: 'xxx' }; console.log(obj - 10); //数学运算:先把obj隐式转换为数字,再进行运算 */ /* let obj = { name: 'xxx', [Symbol.toPrimitive](hint) { // hint检测到浏览器隐式规定的转换类型:'number'/'string'/'default' return 10; } }; console.log(obj - 10); */
详解typeof
- 返回的结果都是字符串(引申:alter方法返回的结果也是字符串)
- 局限性:
- typeof null => "object" 是一个bug因为所有的值在内存中都是按照二进制存储的,typeof检测时认为前几位都是000的是object而null的前几位正好是000,但其实null是一个基本数据类型
- typeof 不能细分对象类型(检测普通对象或数组对象等都是"object")
let a=typeof typeof typeof[12,23]; console.log(a); //"string" /* typeof [12,23] => "object" typeof "object" => "string" */
详解number:NaN/isNaN/Infinity/parseInt/Number()
数字类型:
- 普通数字
- NaN not a number NaN!=NaN
- Infinity,-Infinity
let res=parseFloat('left:200px'); if(res===200){ alter(200); }else if(res ===NaN){ alrer(NaN) }else if(typeof res==='number'){ alter('number') }else{ alter('Invalid Number') }
把其他数据类型转化为数字的方法:
- 强转换(利用底层机制转换) Number([value])
- 一些隐式转换都是基于Number完成的
- isNaN('12px')先把其他类型值转为数字再检测
- 数学运算 '12px'-13
- 字符串==数字 两个等于号比较多时候也是要把其他值转为数字
- ...
- 一些隐式转换都是基于Number完成的
- 弱转换(基于一些额外的方法)parseInt([value]) parseFloat([value])
//parseInt处理的值是字符串,从字符串左侧开始查找有效数字字符(遇到非有效数字字符停止查找)->如果处理的值不是字符串,需要先转化为字符串然后开始查找 //Number 直接调用浏览器最底层的数据类型检测机制完成 //Number中 true 1 false 0 //Number中 null 0 undifined NaN 空字符串0 //Number中 字符串中必须保证都是有效数字才会转化成数字,否则都是NaN // 0 NaN null undefined 空字符串转为布尔都为假 parseInt("") //NaN Number("") //0 isNaN("") //隐式转换先把“”转完数字(Number) isNaN(0) false parseInt(null) //NaN Number(null) //0 isNaN(null) //false parseInt("12px) //12 Number("12px") //NaN isNaN("12px") //true parseFloat("1.6px")+parseInt("1.2px")+typeof parseInt(null) //2.6number isNaN(Number(!!Number(parseInt("0.8")))) //true typeof !parseInt(null)+!isNaN(null)//booleantrue
let result =10 +false +undefined+[]+'tencent'+null+true+{};
console.lof(result)
//10+0=>10
//10+NaN=>NaN
//NaN+[]=>NaN+""=>"NaN"
//"NaNtencentnulltrue[object Object]
Number({})=>Number("[object Object]")=>NaN
Number([])=>Number("")=>0
({}).toString()它调用Object上的toString
([]).toString() 它调用Array上的toString
==号的一些比较规则:
规律:
1.对象=字符串 对象转为字符串
2.null==undefined 但是和其他值不相等
3.剩下两边都不同都转为数字
//对象==布尔 都转为数字再比较 []==true //number([]) =>number("")=>0 0==1 false
2021-01-06
数据类型转换规则及Symbol.toPrimitive
18.2.5 parseInt (string , radix)
20.1 Number Objects
let result = 100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false; console.log(result); var a = ?; if (a == 1 && a == 2 && a == 3) { console.log('OK'); } let arr = [27.2,0,'0013','14px',123]; arr = arr.map(parseInt); console.log(arr);
var a = 12; var b = a; b = 13; console.log(a); ----------------- var a = {n: 12}; var b = a; b['n'] = 13; console.log(a.n); ----------------- var a = {n: 12}; var b = a; b = {n: 13}; console.log(a.n); var a = {n: 1}; var b = a; a.x = a = {n: 2}; console.log(a.x); console.log(b); var x = [12, 23]; function fn(y) { y[0] = 100; y = [100]; y[1] = 200; console.log(y); } fn(x); console.log(x);
/* * 对象转换为数字或者字符串 * 1.查找对象的 Symbol.toPrimitive * 2.对象.valueOf() 原始值:numberstringoolean ullundefinedsymboligint * 3.对象.toString() 变为字符串 * 4.字符串转换数字 Number(str) * * ==相等 ===绝对相等 * ==在比较的时候,如果两边类型不一致,则转换为相同的数据类型 * NaN==NaN false Object.is(NaN,NaN)->true * null==undefined -> true null===undefined -> false null&undefined和其他任何值比较都是不相等的 * 对象==字符串 对象转换为字符串 * 剩余的情况都是转换为数字 * * ===类型不一致,不会转换,直接false */ // 第一类:隐式进行数据类型转换的时候进行处理的 /* var a = { i: 0 }; // valueOf / toString a[Symbol.toPrimitive] = function () { // this->a return ++this.i; }; // a[Symbol.toPrimitive]() if (a == 1 && a == 2 && a == 3) { console.log('OK'); } */ /* var a = { i: 0, [Symbol.toPrimitive]() { return ++this.i; } }; if (a == 1 && a == 2 && a == 3) { console.log('OK'); } */ /* var a = [1, 2, 3]; // a.shift() ->1 a.toString = a.shift; if (a == 1 && a == 2 && a == 3) { console.log('OK'); } */ // 第二类:ES6 数据劫持 /* let obj = {}; Object.defineProperty(obj, 'name', { // 以后当我们操作对象的name属性的时候(获取或者设置),触发getter/setter get() { return '逗你玩'; }, set(value) { console.log(value); } }); */ /* // var a = 12; //全局上下文中,基于var/function声明变量,也相当于给window设置了属性 window.a=12 var i = 0; Object.defineProperty(window, 'a', { get() { return ++i; } }); if (a == 1 && a == 2 && a == 3) { console.log('OK'); } */ //============JS中的数据类型转换 /* * 把其它的数据类型转换为number类型 * 例如:==比较、数学运算(+不仅仅是数学运算,还有字符串拼接)... * * 显式转换方案: * Number([val]) -> 隐式转换一般调取的都是这个方法 「浏览器有自己的特殊处理,针对于每一种情况都有详细的规则」 * parsetInt/parseFloat([val]) * parsetInt([val],[radix])处理机制 * [val] 必须是一个字符串,如果不是,则也要默认转换为字符串 * [radix]不设置(或者写的是零):正常都是按照10处理的,如果字符串是以”0x“开始的,默认值是16... * 先在[val]中,找到所有符合[radix]进制的内容(从左到右查找,直到遇到不符合的为止「不论后面是否还有符合进制的,都不在查找了」),然后再把找到的内容看做[radix]进制,转换为十进制 * [radix]范围 2~36,除了0以外(0->10/16),不在这个范围内,结果都是NaN */ // parseInt('12px') -> parseInt('12px',10) -> 在字符串中找到所有符合10进制的内容 ‘12’ -> 最后把'12'当做看做10进制,转换为10进制 -> 12 // parseInt('12px',1) -> NaN // console.log(parseInt(null)); //->parseInt('null',10) -> NaN // 把其它进制转换为10进制? // '10101' 2机制 -> 10进制 // 1*2^0 + 0*2^1 + 1*2^2 + 0*2^3 + 1*2^4 // 4^-1 -> 1/4 4^-3 -> 1/(4^3) // 把一个函数作为值传递给另外一个函数执行(实参):回调函数 // parseInt(27.2,0) // parseInt('27.2') -> 27 // parseInt(0,1) // NaN // parseInt('0013',2) // '001' 看做2进制 转换为10进制 // 1*2^0 -> 1 // parseInt('14px',3) // '1' 看做3进制 转换为10进制 // 1*3^0 -> 1 // parseInt(123,4) // parseInt('123',4) // '123' 看做4进制 转换为10进制 // 3*4^0 + 2*4^1 + 1*4^2 -> 3+8+16 -> 27 /* let arr = [27.2, 0, '0013', '14px', 123]; arr = arr.map(parseInt); console.log(arr); */ // 数据中有多少项,就迭代多少次,每一次执行回调函数(item当前迭代项 index索引),支持回调函数返回值,返回啥就把当前项替换成啥,原始数组不变,以新数组返回!! /* let arrNew = arr.map(function (item, index) { return '@'; }); */ /* * 把其它数据类型转换为布尔: * 只有”0/NaN/null/undefined/空字符串“ 转换为false,其余都是true * 例如: * if(1){} * ! 取反 * !! 转换为布尔 * ... */ /* * ”+“还存在字符串拼接 * +两边都有值,有一边出现字符串或者对象,则为字符拼接 * 特殊:{}+10 -> 10 {}看做代码块(ES6 块级上下文),真正运算的只有 +10 ->10 * ({}+10) -> '[object Object]10' * +只有一边或者++x再或者x++,都是数学运算 * +'10' -> 10 * 10+(++x) -> 先把x累加1,然后和10运算 * 10+(x++) -> 先拿x的值和10运算,最后再x累加1 * * x++ !== (x+=1 == x=x+1) */ /* let result = 100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false; console.log(result); */ // 10+{} -> "10[object Object]" 原本是想把{}变为数字,但是Symbol.toPrimitive/valueOf/toString,调到toString变为字符串,此时符合了有一边变为字符串了,则是字符串拼接 /* let x = '10'; console.log(++x); //->11 x = '10'; x += 1; //->x=x+1 console.log(x); //->'101' */ //=======================
/* * JS运行的环境: * + 浏览器 * + webview WebApp(Hybride混合APP) * + node.js * + ... * * 浏览器能够运行JS代码,是因为提供了代码运行的环境:栈内存(Stack) * + 栈内存也是从计算机的内存分配出来的一块内存 * + 执行环境栈 E(execution)C(context)Stack * * 执行代码的过程中,为了区分是在哪个环境下执行(全局/函数/块...),首先会产生一个执行上下文:EC * + EC(G) 全局上下文,全局代码在这执行 * + EC(X) 某个函数的执行上下文 */ /* var a = 12; var b = a; b = 13; console.log(a); */ /* var a = { n: 12 }; //a -> 0x0001 var b = a; b = { n: 13 }; //b -> 0x0002 console.log(a.n); //=>12 */ // 课后思考: var a = { n: 1 }; var b = a; a.x = a = { n: 2 }; console.log(a.x); console.log(b); // a.x 成员访问,优先级20「优先计算的」 // a.x=a=? 先处理a.x=? // a=a.x=? 先处理a.x=? /* var a = 12, b = 12; // var a=12; var b=12; */ /* var a = b = 12; // var a; b没有var // 1.创建值12 // 2.连等操作是按照从右到左 // b -> 12 // a -> 12 */ // https://developer.mozilla.org/zh-CN/docs/web/javascript/reference/operators/operator_precedence