当前位置: 首页 > Web前端 > HTML5

重学JavaScript前端(一)JavaScript数据类型

时间:2023-04-05 00:29:18 HTML5

JavaScript本系列文章涉及的点不多,但涉及到一些常见的如数据类型、闭包、原型链、属性描述符、ES6模块等,以及冬天提出的一些问题。Winter的JavaScript非常深入。有些部分不是很懂,所以没有记录下来。有兴趣可以看看他的专栏。本文主要讲JavaScript变量命名规则、数据类型、引用类型和基本类型的区别,以及类型检测的一些方法。JavaScript变量1、定义变量:变量是存储数据的容器,可以存储任何类型的数据2、变量命名规则1)变量一般由字母、数字、下划线、$组成,不能以数字开头2)变量名不能使用JavaScript保留字,如var、function、let、for等。3)变量名要遵循“小驼峰命名法”,即把整个名字的首字母小写,然后大写其余单词的第一个字符4)变量名是区分大小写的,所以myAge和myage是两个不同的变量,它可以描述包含的数据。3.声明一个变量/*var会生成一个变量声明提升,也可以在变量声明之前使用。当重复声明同一个变量名的变量时,后一个会覆盖前一个。您可以使用window.variable获取*/vara=1;/*let和const声明的变量只在声明它们的块或子块中可用,会出现暂时的死区。在let和const声明变量之前,这些变量是不可用的;同名变量不能重复声明。无法使用window.variable获取。IE11支持let*/letb=2;常量c=3;/*不使用关键字直接创建变量,无论是在函数内部还是外部,都会成为全局变量;不会有变量提升,可以使用window。变量获取,可以使用delete删除;当重复声明同一个变量名的变量时,后面的会覆盖前面的*/d=4;参考链接:MDN--howtostoretheinformationyouneed—variableMDN--letJavaScriptType1.定义基本类型:1)Undefined:Undefined类型只有一个值,即undefined。它是一个变量,而不是关键字。使用var时,let声明一个变量但不初始化它,这个值是未定义的。未声明变量时使用typeof,返回结果也是“undefined”(varmessage;console.log(message===undefined)//true)2)Null:Null类型只有一个值,即一片空白。从逻辑的角度来看,一个空值代表一个空的对象指针,这就是为什么typeof运算符在检测到一个空值时返回'object'的原因。用于定义一个以后用来保存对象的变量,它的值可以设置为null。3)Boolean:Boolean类型只有两个字面值,true和false。4)String:String类型用于表示由零个或多个16位Unicode字符组成的字符序列,即字符串。字符串可以用双引号(")或者单引号(')来表示。String的意思不是“字符串”,而是字符串的UTF16编码。我们的字符串操作charAt、charCodeAt、length等方法都是针对UTF16编码的.5)Number:Number类型使用IEEE754格式来表示整数和浮点值(浮点值在某些语言中也称为双精度值)。浮点数必须包含小数点在值中,并且小数点后面至少要有一位。由于存储浮点值的内存空间是存储整数值的两倍,ECMAScript会将浮点值转换为整数值不失时机(vara=1.0;console.log(a);//1)。Number中还有几种额外的情况,NaN(转换成Number失败,NaN不等于NaN,不管是==还是===),Infinity(无穷大),-Infinity(负无穷大)。6)Symbol:表示一个唯一的值。可以用于对象的属性名,保证每个属性的名字都是唯一值,从根本上防止属性名冲突。符号值由符号函数生成。(vara=Symbol(1);varb=Symbol(1);a===b;//false)引用类型Object:ECMAScript中的对象实际上是数据和函数的集合。可以通过执行new运算符后接构造函数(构造函数本身是一个函数,但定义该函数是为了创建新对象)或通过对象字面量来创建对象。(varobj=newObject();vararr=newArray;varobj1=[];)在ECMAScript中,如果不向构造函数传递参数,可以省略下面这对括号,但不推荐。注:1)在null和undefined之间使用相等运算符(==)时,总是返回true。2)以上除了Symbole来自ES6的介绍,其他都来自JavaScript高级程序设计(第3版)的基本类型和引用类型1.区别1)基本类型直接在栈中存储内容(大小是固定且位置连续的数据类型的存储空间),记录数据类型的值,即直接访问,基本类型赋值是复制;引用类型存放的是堆中的内容,堆对应的栈记录了指针(堆的地址),外部访问时,先引出地址,再利用地址找到所在位置该值被存储。引用类型分配是地址引用。指向基本数据类型的变量相当于包含数据,而指向非基本类型数据(引用类型)的变量本身不包含数据,它只是记录了一个内存地址。2)基本类型:如果使用基本类型=将一个变量的值赋值给另一个变量,其实就是复制对应的值,然后赋值给一个新的变量,这就是值传递。改动不影响对方。(letx=1;leta=x;)引用类型:如果一个变量绑定了一个非基本数据类型(Array,Function,Object),那么它只记录一个内存地址,里面存放的是具体的数据。如果将一个引用类型的变量赋值给另一个变量,实际上是复制了内存地址。当一个变量的值发生变化时,另一个变量也会发生变化。对象是按引用传递的,不是按值传递的,引用类型的变量赋值只会传递地址。如果一个已经赋值的变量被重新赋值,它将包含新的数据或一个引用地址。如果一个对象没有被任何变量指向,JavaScript引擎的垃圾回收机制将销毁该对象并释放内存。(letx={a:1};letb=x;x.a=2;b.a===2//true)二、相关扩展1.==和===中,引用类型和基本类型如何比较?==和===,对于引用类型的变量,==和===只会判断引用的地址是否相同,而不会判断对象的具体属性和值是否相同。如果两个变量指向同一个对象,则返回true。如果是基本类型,==会在两个变量类型不同的时候判断隐式转换后的值是否相同,如果变量类型相同,则直接判断值是否相同相同的;===会判断两个变量的值类型和值是否完全一致。2.JS中的可变和不可变基本类型是不可变的,比如ECMAScript中的字符串是不可变的,也就是说字符串一旦创建,它们的值就不能再改变了。要改变变量持有的字符串,首先销毁原来的字符串,然后用另一个包含新值的字符串填充变量;引用类型是可变的。conststr='12';str='123'//UncaughtTypeError:Assignmenttoconstantvariableconstobj={a:1}obj.a=2;console.log(obj)//{a:2}3.函数参数按值传递ECMAScript中的所有函数参数都是按值传递的,也就是说,将函数外部的值复制到函数内部的参数与将值从一个变量复制到另一个变量相同。基本类型值的传递和基本类型变量的复制一样,引用类型值的传递和引用类型变量的复制一样。向函数传递参数:1)当参数是基本类型时:传递的值将被复制到一个局部变量中。2)当参数为引用类型时:将对象作为参数传入函数后,即使是传值,函数内部变量也会通过引用访问同一个对象。因此,当函数内部给这个变量加上一个属性时,函数外部的对象也会反映出来。因为person指向的对象在堆内存中只有一个,而且是一个全局对象。许多开发人员错误地认为:在局部范围内修改的对象会反映在全局范围内,这意味着参数是通过引用传递的。但是如果你在函数中重新定义了一个同名的对象,就重新设置它的name属性。调用该函数后,访问person.name时,显示的值仍然是'Nicholas'。这意味着即使在函数内部修改了参数的值,原始引用仍然保持不变。实际上,在函数内部重写obj时,这个变量指的是一个局部对象。而这个局部对象会在函数执行完后立即被销毁。functionsetName(obj){obj.name='尼古拉斯';对象=新对象();obj.name='格雷格';}varperson=newObject();设置名称(人););//我对Nicholas的理解:1)这个很绕,理解这个的关键是什么是按引用传递值。函数addTen(num){num+=10;返回num;}varcount=20;加十(计数);在这个例子中,如果值是通过引用传递的,那么当函数被调用时,count的值应该是30。即按引用传递值是指当函数中的变量发生变化时,全局变量也会发生变化,以反映函数内部的修改。(我还是没仔细看书,没仔细看,书里也提到了这个总结。。。)2)当函数有参数时,函数中会隐式声明一个局部变量body,然后将函数参数中的变量值赋值给这个局部变量。当函数参数为对象时,会将原来的内存地址复制到局部变量中。当局部变量改变时,全局对象也会改变,因为地址是一样的。将局部变量重新赋值给新对象时,内存地址会被替换,这样两者就没有关系了。(leta={name:1};letb={name:1})就像a和b一样,虽然值相同但是内存地址不同,所以一个改变,另一个不会相应改变。3)参数传递策略:a。按值传递:参数的值是调用者传递的对象值的副本(copyofvalue)。value),一般来说就是重新分配新的内存(我们先不关注分配的内存是怎么实现的——也是栈或者动态内存分配),新内存块的值是外部对象,其值在函数内部使用。b.引用传递:引用传递接收的不是值的副本,而是对对象的隐式引用,比如外部对象的直接引用地址。函数内部参数的任何改变都会影响函数外部对象的值,因为两者引用同一个对象,也就是说:此时参数相当于外部对象的别名。C。共享调用:函数接收一个对象的拷贝(copy),引用拷贝与形参及其值相关联。这里出现的引用不能称为“按引用传递”,因为函数接收的参数不是直接的对象别名,而是引用地址的副本。最重要的区别是:##在函数内部给参数重新赋值不会影响外部对象##,但是因为参数是地址拷贝,所以外部访问和内部访问是同一个对象(例如外部对象不是像传值一样的完整拷贝),改变参数对象的属性值会影响到外部对象。pass-by-share策略在很多语言中都有使用:Java、ECMAScript、Python、Ruby、VisualBasic等。另外,Python社区已经在使用这个术语,其他语言也可以使用它,因为其他名称容易混淆人们。大多数时候,例如在Java、ECMAScript或VisualBasic中,这种策略也称为按值传递——意思是:特殊值——引用复制(copy)。参考内容:来自JavaScript高级程序设计(第3版)4.1.3传递参数知乎——JavaScript中的函数都是按值传递的吗?深入理解JavaScript系列(十九):求值策略(Evaluationstrategy)类型检测1.typeoftypeof:使用typeof运算符返回一个字符串,表示未计算操作数的类型。使用typeof操作符的结果一共是7种字符串。typeof:'undefined'的返回结果:如果值为undefinedvarname=void(0);名称类型;//"undefined"'boolean':如果值为布尔值varflag=true;标志类型;//"boolean"'string':如果值为字符串varstr='1';海峡类型;//"string"'number':如果值为数字varnum=1;数字类型;//"number"'symbol':如果值为symbolvarkey=Symbol(1);键类型;//"symbol"'object':如果值为对象或nullvarobj={};vardate=newDate();vararr={};变量reg=/1/;对象类型;日期类型;arr类型;注册类型;//"object"'function':如果这个值是一个函数functionhandle(){};句柄类型;//“函数”注意:typeof运算符对未初始化和未声明的变量执行typeof运算符并返回未定义的值,但是是在变量没有用let或const声明的情况下。如果先用typeof检测一个变量,再用let或const声明变量,就会报错。2.Object.prototype.toString.call()Object.prototype.toString.call():返回表示对象的字符串。Object.prototype.toString.call()的返回结果:Object.prototype.toString.call('字符串');//"[对象字符串]"Object.prototype.toString.call(1);//"[对象编号]"Object.prototype.toString.call(true);//"[对象布尔值]"Object.prototype.toString.call(null);//"[objectNull]"Object.prototype.toString.call(undefined);//"[对象未定义]"Object.prototype.toString.call(Symbol(1));//"[对象符号]"Object.prototype.toString.call(/1/);//"[objectRegExp]"Object.prototype.toString.call(function(){});//"[对象函数]"Object.prototype.toString.call([]);//"[对象数组]"Object.prototype.toString.call({});//"[objectObject]"Object.prototype.toString.call(newDate());//"[objectDate]"以上内容如有不对,希望大家指出,谢谢。