变量和类型
-
1.JavaScript规定了几种语言类型
1.Undefined 2.Null(js中的数据在底层是以二进制存储,如果前三位为0,那么就会判定为object,而null的所有都为0) 3.Boolean 4.String 5.Number 6.Symbol(ECMAScript 6 新定义,实例是唯一且不可改变的) 7.Object
-
2.JavaScript对象的底层数据结构是什么
-
3.Symbol类型在实际开发中的应用、可手动实现一个简单的Symbol
-
应用场景1:使用Symbol来作为对象属性名(key)
const PROP_NAME = Symbol(); const PROP_AGE = Symbol(); let obj = { [PROP_NAME]: "一斤代码" } obj[PROP_AGE] = 18; console.log(obj[PROP_NAME]); // '一斤代码' console.log(obj[PROP_AGE]); // 18
【注意】Symbol类型的key是不能通过
Object.keys()
或者for...in
来枚举的,利用该特性,我们可以把一些不需要对外操作和访问的属性使用Symbol来定义。实现当使用JSON.stringify()
将对象转换成JSON字符串的时候,Symbol属性也会被排除在输出内容之外。获取以Symbol方式定义的对象属性 // 使用Object的API Object.getOwnPropertySymbols(obj); // [Symbol(name)] // 使用新增的反射API Reflect.ownKeys(obj); // [Symbol(name), 'age', 'title']
-
应用场景2:使用Symbol来替代常量
//由于定义const变量的时候需要立即赋值,这样定义,直接就保证了三个常量的值是唯一的了 const TYPE_AUDIO = Symbol(); const TYPE_VIDEO = Symbol(); const TYPE_IMAGE = Symbol();
-
应用场景3:使用Symbol定义类的私有属性/方法
利用Symbol的唯一性以及模块化机制,实现类的私有属性和方法。
//a.js const PASSWORD = Symbol() class Login { constructor(username, password) { this.username = username this[PASSWORD] = password } checkPassword(pwd) { return this[PASSWORD] === pwd } } export default Login
//b.js import Login from './a' const login = new Login('admin', '123456') login.checkPassword('123456') // true login.PASSWORD // oh!no! login[PASSWORD] // oh!no! login["PASSWORD"] // oh!no!
-
-
4.JavaScript中的变量在内存中的具体存储形式
JavaScript中的变量分为基本类型和引用类型
-
基本类型是保存在栈内存中的简单数据段,它们的值都有固定的大小,保存在栈空间,通过按值访问
-
引用类型是保存在堆内存中的对象,值大小不固定,栈内存中存放的该对象的访问地址指向堆内存中的对象,JavaScript不允许直接访问堆内存中的位置,因此操作对象时,实际操作对象的引用。
-
//例子: let a1 = 0; // 栈内存 let a2 = "this is string" // 栈内存 let a3 = null; // 栈内存 let b = { x: 10 }; // 变量b存在于栈中,{ x: 10 }作为对象存在于堆中 let c = [1, 2, 3]; // 变量c存在于栈中,[1, 2, 3]作为对象存在于堆中
复制行为
- 在栈内存中的数据发生复制行为时,系统会自动为新的变量分配一个新值,最后这些变量都是相互独立互不影响的
- 引用类型的复制,为新的变量分配相同的地址指针,保存在栈内存中,该地址指针在堆内存中访问到的具体对象实际上是同一个,因此一改变数值,双方都改。
生存期
- 当一个方法执行时,会建立自己的栈内存,在方法内定义的变量都会放入这块栈内存里,方法执行结束后,这个内存栈也将自然销毁。
- 堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(方法的参数传递时很常见)。只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。
-
-
5.基本类型对应的内置对象,以及他们之间的装箱拆箱操作
-
内置对象
-
数据封装类对象:Object、Array、Boolean、Number 、String
-
其他对象:Function、Math、Date、RegExp、Error
-
Error6种错误类型(前4个较常见)
1.SyntaxError: 语法错误 2.ReferenceError: 引用错误 要用的东西没找到 3.RangeError: 范围错误 专指参数超范围 4.TypeError: 类型错误 错误的调用了对象的方法 5.EvalError: eval()方法错误的使用 6.URIError: url地址错误
-
-
-
特殊的基本包装类型(Boolean、Number 、String)
-
包装类型:专门封装原始类型的数据,并提供对数据常用操作的内置对象方法。
-
生存期:只要用原始类型的数据调用方法或者访问属性时,js引擎都会自动创建对应的包装类型。对象方法调用完,包装类型对象会自动释放。
-
无法直接给基本类型添加属性和方法,但可以在基本包装类型对象的原型下面添加,因为每个对象都有原型。
-
装箱(把基本数据类型转化为对应的引用数据类型的操作)
-
隐式装箱
let a = 'sun'; let b = a.indexof('s'); // 上面代码在后台实际的步骤为: let a = new String('sun') let b = a.indexof('s') a = null
-
显式装箱
let a = new String('sun '); let b = a.indexof('s')
-
-
拆箱(把引用类型转化为对应基本数据类型的操作)
let name = new String('sun') let age = new Number(24) console.log(typeof name) // object console.log(typeof age) // object // 拆箱操作(通常通过引用类型的valueof()和toString()方法实现) console.log(typeof age.valueOf()); // number // 24 基本的数字类型 console.log(typeof name.valueOf()); // string // 'sun' 基本的字符类型 console.log(typeof age.toString()); // string // '24' 基本的字符类型 console.log(typeof name.toString()); // string // 'sun' 基本的字符类型
-
-
-
6.理解值类型和引用类型
-
值类型,即基本类型
-
string、number、boolean、undefined、null、symbol
-
1、占用空间固定,保存在栈中 2、保存与复制的是值本身 3、使用typeof检测数据的类型 4、基本类型数据是值类型
-
-
引用类型
-
Object、Array、Function
-
1、占用空间不固定,保存在堆中 2、保存与复制的是指向对象的一个指针 3、使用instanceof检测数据类型 4、使用new()方法构造出的对象是引用型
-
-
-
7.null和undefined的区别
-
用法不同
null表示 “没有对象”,即该处不应该有值。 (1)作为函数的参数,表示该函数的参数不是对象。 (2)作为对象原型链的终点。 undefined表示“缺少值”,就是此处应该有一个值,但是还没有定义。 (1)变量被声明了,但没有赋值时,就等于undefined。 (2)调用函数时,应该提供的参数没有提供,该参数就等于undefined。 (3)对象没有赋值的属性,该属性的值为undefined。 (4)函数没有返回值时,默认返回undefined。
-
类型转换
Number(undefined) // NaN Number(undefined + 10) //NaN Number(null) // 0 Number(10 + null) // 10
-
数据类型
undefined === null //false undefined与object undefined == null //true js规定
-
-
8.至少可以说出三种判断JavaScript数据类型的方式,以及他们的优缺点,如何准确的判断数组类型
-
typeof
-
优点:使用简单,能判断出所有基本数据类型+object(null是object)+function
-
缺点:不能区分object类型的具体类型,比如 Array 、Date 以及自定义类。
-
var arr = []; console.log(typeof arr);//object
-
-
instanceof
-
优点:能判断出引用类型
-
缺点:只能判断出用对象定义的基本数据类型;不能跨iframe
-
var arr = []; alert(arr instanceof Array);//true
-
-
constructor
-
优点: 基本能检测所有的类型(除了null和undefined,并且会报错。因为null和undefined是无效的对象,因此是不会有constructor存在的)
-
缺点:constructor易被修改导致判断出错,也不能跨iframe
-
var arr = []; alert(arr.constructor == Array);//true
-
-
Object.prototype.toString.call( ) ;
-
优点:能判断出所有的类型
-
缺点:IE6下,undefined和null均为Object
-
var arr = []; console.log(Object.prototype.toString.call(arr));//[object Array]
-
-
-
9.可能发生隐式类型转换的场景以及转换原则,应如何避免或巧妙应用
-
应用场景
-
场景一:算术运算符
-
字符串
+
数字=字符串数字console.log(10+"abc");//10abc
-
非字符串
+
数字=转数字+数字console.log(10+true);//11
-
-
、*
、/
、%
将字符转换成数字,再进行正常的运算,结果必为数值,若字符不是纯数字,则结果为NaN -
(
+
字符串)转数字
-
-
场景二:关系(比较)运算符
-
<
、<=
、>
、>=
、!=
、==
-
任意一边出现数值,就会把另一边转成数值,再进行比较。
console.log([1] == 1);//true,相当于1 == 1 console.log([] == true);//false,相当于0 == 1 console.log({} > true);//false,相当于 NaN > 1 console.log('true' <= 0);//false,相当于NaN <= 0
-
一个值转换为另一个值并不意味着两个值相等
console.log(new Date() == 'Fri Jul 15 2016 22:12:05 GMT+0800 (中国标准时间)');//true console.log(Number(null));//0 console.log(null == 0);//false console.log(Boolean(NaN));//false console.log(NaN == false);//false,NaN与任何值都不等,包括自己
-
两边是对象
console.log({} == {});//false console.log([] == []);//false
-
两边都是字符串,则是按照字符串的按位比较法。
-
-
-
场景三:isNaN()
- 参数转成数值,严格转换,能识别小数点
-
场景四:判断语句if()
- 隐式转换,将其他转成布尔值
-
场景五:逻辑运算符
- 逻辑非 !
- 隐式转换,将其他数据类型转成布尔值
- 优先级高于关系运算符
- 位运算符(&、|、^、&&、||)
- 隐式转换,将其他数据类型转成数字
- 优先级低于关系运算符
- 位运算符(<<等)
- 隐式转换,将其他数据类型转成数字
- 优先级高于关系运算符
- 逻辑非 !
-
避免隐式转换
- 如果两遍的值中有 true 或者 false , 千万不要使用 == (会被转为数字0,1来进行判断,会出现一些意外的情况)
- 如果两遍的值中有[]、''或者0,尽量不要使用 ==
- 使用全等
===
来代替==
-
巧妙应用
使用一个对象,进行隐式类型转换 const a = (function() { let i = 1; return { valueOf: function() { return i++; } } })(); console.log(a == 1 && a == 2 && a == 3); // true
-
-
10.出现小数精度丢失的原因,JavaScript可以存储的最大数字、最大安全数字,JavaScript处理大数字的方法、避免精度丢失的方法
-
小数精度丢失的原因:计算机的二进制实现和位数限制有些数无法有限表示。
-
JS的基础类型Number,遵循 IEEE 754 规范,采用双精度存储(double precision),占用 64 bit。符号位(1bit),指数(11bit),尾数(52bit),因此 JS 中能精准表示的最大整数是 Math.pow(2, 53)-1,十进制即 9007199254740991。
-
最大安全数字
console.log(Number.MAX_SAFE_INTEGER); //9007199254740991 console.log(Number.MIN_SAFE_INTEGER); //-9007199254740991
-
JS 处理大数字的方法
- json-bigint
- bignumber.js:原理是把所有数字当作字符串,重新实现了计算逻辑,缺点是性能比原生的差很多。
- proposal bigint
- 大数运算:化为字符串再运算
-
避免精度丢失的方法
- 小数:小数化整进行运算再化为小数。
- CalcEval.js引擎
-
本文作者:AlubNoBug