亮个相
大家好,首先我先来个自我介绍。
我的花名叫lotoze(读作谐音老头子),大家可以叫我lotoze、老头子、老头、老头儿等,虽然我很年轻。 起这么个花名是因为我对“老头”有一种莫名的感觉(不要多想0.0),这种感觉是一种敬畏的那种。
我对老头子这个词的一种理解是:人生经验的“老”、资质经历的“老”、技术层次的“老”等,“老”字是我追逐的脚步。 还有一种理解是:夫妻俩人中妻子对丈夫的称谓,“嘿,老头子!”,是多么的温暖和幸福,“老”字是我对生活的向往。 不过这么极具意义的花名,再配上骨子里那“逗”劲悄悄地流露了出来,显得多么可爱、多么的俏皮、多么的“骚”气。
什么?什么?熏着你了?别逗了大哥,我说的是“骚”是独领风骚中意为才能超群出众的“骚”气。
好了,不扯牛了,之所以先开拓一下“逗”的细胞,是因为写文章的时候好办事。写好文章我觉得需要将自己的想法、自己 的认知、自己的理解等要在这么一张纸上去描述清楚,描述清楚了还不够,关键是如何让别人也能懂我想传到的东西。要想 做到这一点,那就得不要脸,我说的是我哈。对,要让我自己不要脸的buff发挥到极致,尽全力去写好每一篇文章。一开始 就奠定了这样的气氛,以后也不会显得太突兀,有可能还挺有趣。现实里咱可是个正经人儿😁😁。
前言
【JS深渊】系列是我用来对前端原生javascript语言相关技术进行的深度探究或者笔记记录,我个人是一个很爱去挖 层的这么一个人,但不幸的是觉悟的太晚,但我不会放弃。决定开始写博客目的有两个,一个是有仪式性的去持续提高 自己的技术能力,另一个就是希望向上再向上。不过自己能力也是有限的,如果写的不好或者出现什么纰漏又或者错误的地 方,脱裤式欢迎大家的建议、指正。没错看着我,对,盯着你的屏幕,别眨眼,请记住我的这句话:
您的反馈是就是我持续进步的动力。
好了,收!biu~
正文
数据结构是任意一类编程语言中都不可缺少的重要组成部分。在JavaScript中有着自己的数据结构,这里lotoze(谐音老头子)我想要用两个字来描述一下我对JavaScript数据结构的感觉,这两个字就是——飘逸
但是对于前端来说,这个确实很基础很基础的东西,我想对于那些工作的人来说,几乎已经忘记当时初学时候的样子。可现在前端更新迭代的速度,让我这个糟老头子怎么跟的上啊😢😢,所以必须重新认识一下。
js中的数据类型都有些什么?
这个我想大家都非常清楚吧。就不多说了,直接写了。
js(javascript)中一共有两种数据类型,分别为原始数据类型、引用数据类型。原始数据类型也叫基本数据类型。
那么这两种下面是否还有具体的类型?当然!
原始值类型
- string
- number
- boolean
- null
- undefined
- symbol(ES6新增)
引用值类型
- Object
- Array
- Function
- ... ...
这些就是javascript中的数据类型结构了,ECMAScript5之前都是5个基本数据类型,ES6之后出现一个新的基本数据类型symbol,一共就6个基本数据类型了。引用数据类型如果不太严谨的来说,几乎全是引用数据类型,也就是一切皆对象。关键是为什么这么说呢?
因为Javascript语言,本就是一个趋于面向对象的脚本语言,可以看出,它受Java的影响很深,借鉴了Java语言的数据结构,将值分为原始值和对象两大类,虽然数据结构上分开了,但是Java中有包装类的概念,可以将原始值包装成对象,也就是引用数据类型。这样更加满足在Java中的一切皆对象的思想,面向对象的思想也就完整了,那么这个思想也被设计者(Brendan Eich-布兰登·艾奇)拿了过来,在JavaScript中同样适用,JavaScript中也具有包装类。
好了,我们已经认识了JavaScript中基础的数据结构是怎么样的,但是知道这些却没法用啊,想要运用起来还需要了解这两种类型的特点。
原始值类型和引用值类型分别有什么特点?
我们先来看几个比较经典的栗子:
栗子来了
123.length; //报错
123.toString() //报错
var a = 123;
a.length; //undefined
a.toString(); //"123"
var a = "123";
a.length; //3
看上方的代码,对比一下,你肯定会在心里问上一问,这都是些什么鬼?:
-
为什么直接使用纯原始值直接去获取属性调用方法会报错?
123.length,123是个值,而且是个原始值类型,这句代码是想要在原始值上获取属性名叫length的属性,但是它报错了,证明了什么?证明如果是纯原始值你绝对不能获取属性,那方法呢?事实上也不行。
-
为什么var了一个变量后,获取属性就不报错了,返回undefined,但是调用方法却正常?
你会发现,当在控制台var了一个a,并赋予原始值123后, a.的时候会出现好多好多方法或属性的提示。
而纯原始值123.的时候什么玩意都没有,那么关键是a.这些方法和属性都是从哪里来的呢?这就需要了解一下一个叫做包装类的概念。
js是一种弱类型语言,var一个变量可以存储不同的数据类型,不需要类型声明,js引擎系统也是宽宏大度的,当你想要使用原始值类型获取属性或者方法的时候,js引擎系统会默认帮你自动包装成一个对象,也就是包装类对象,在构造此对象的构造函数的原型链上有着这些方法。
那么a.length为什么不报错,还是undefined以及a.toString()是正常的返回数据也就能解释的通了。当存储着原始值类型的a变量获取属性或方法时,js引擎系统认为你有可能不是有意在原始值类型上获取属性或方法的,既然是无心之过,就大度原谅你一下吧,就使用包装类将其包装成包装类对象,要是原型链上有属性或者方法,你就用就可以了,如果没有也不会报错,只是返回一个undefined,怎么样?够意思不...
-
为什么原始值string获取属性正常,调用方法也正常?
那么这个就更好理解了,因为什么?因为构造出string类型的包装类对象的构造函数的原型链上的方法多呗,有length和toString()。瞅瞅,这么多😒😒
栗子来了
var a = 123;
var b = a;
b = 456;
b.m = 456;
console.log(a); //123
console.log(b); //456
console.log(b.m) //undefined
console.log(a.m) //undefined
var c = {m: 123};
var d = c;
d.m = 456;
d.n = 789;
console.log(c.m); //456
console.log(d.m); //456
console.log(c.n); //789
console.log(d.n); //789
发现了什么?:
-
为什么给明明给原始值类型新增了属性b.m,访问这个属性返回的是undefined?
这个其实是也是js引擎系统自动搞的事情。上面提到了,原始值类型是不能有属性和方法的,但是因为js是一个弱类型语言,js引擎系统它是大度的,如果你想在原始值类型上去获取属性或者执行方法,js引擎系统会自动对其进行包装成包装类对象,我们在原始值上获取属性或者方法,实质上只在这个包装类对象上或者原型链上获取属性和方法,但这里需要注意的是,这个包装类对象不是一直存在的,而是在你进行操作之后就立即销毁了。
销毁了之后,再console.log(b.m);是又重新包装了一个新的对象,和增加属性时的根本不是同一个对象,当然返回的是undefined了,不得不说真会玩儿😢😢
-
把存储原始值类型变量的复制到新变量中,新的变量中的值发生改变,原来的变量中的值不随之改变,
把存储引用值类型的变量复制到新变量中,新的变量中的值的属性发生变化,原来的变量中的值的属性也随之改变,
为什么会出现这种现象?这种现象出现的本质是数据在内存中存储机制造成的。
在内存中,原始值类型存储在栈(Stack)中,引用值类型则是将地址引用存储在栈里,内容值存储在堆(Heap)里。 内存这一块非常复杂,注意,任何事情都是有个目的所在的,比如老头子我之所以去研究底层原理,是因为这有助于自我技术的提高,可以让我能够在日常的开发或使用中更加灵活多变,但是老头我不是造内存的,所以也要懂得适可而止,只需要明白js的数据结构在内存中如何存储就ok,其他的有兴趣可以在深挖一下。😁😁
原始值类型在内存中的存储引用数据类型在内存的存储
当复制原始值时
只是将栈内存空间中存储的的值拿了过去,空间上还是相互独立,互补干扰。所以新的变量中的值发生改变,原来的变量中的值不随之改变。当复制引用值类型时
也是将栈内存中存储的值拿了过去,只不过这次拿的值是堆内存的地址引用,并不是值本身,所以地址原来的指向并没有变,指向的还是堆内存中的那个存储对象键值对内容的那个对象。所以新的变量中的值的属性发生变化,原来的变量中的值的属性也随之改变。
总结,其实最大特点有两个:
- 从应用角度出发,原始值类型是绝对不能有属性和方法的,引用值类型却可以拥有属性和方法。
- 从底层角度出发,原始值类型存储在栈()中,引用值类型则是将地址引用存储在栈里,内容值存储在堆里。
之后,今后又应该怎么更好的使用?
- 首先要注意的是,js的语言特性,它是一种弱类型语言,相比强类型语言,异常的灵活多变。
- 不要试图通过原始值类型去获取属性或者执行方法,因有包装类的自动包装,但会立即销毁。你可能得不到你想要的的 结果,除非你对其原型链上的属性和方法很熟悉。
- 尽量不要去使用==号去比较两个引用值类型是否相等,因为==号对于原始值来说,比较的是值本身,但是对于引用值比 较其实比较的是地址,如果地址指向相同,那么系统就认为两者是同一个对象,也就相等,反之则不相等。这就有可能就算 看上去对象长得一样,实际上是两个对象并不相等。所以在这一点要格外的注意。
lotoze | 【原创】
着重说明:里面一些表情图片并非原创,只是为了读者读起来不是那么枯燥乏味。但如果原作者觉得有侵犯版权的意思,请使用下方联系方式与我联系,为了尊重原创作者的辛苦创作,我将及时处理!
当然,没事也可以联系啦😘😘欢迎交流!
求赞/求关注
写作不易,
如果您还觉得凑合,就给个赞!
如果觉得确实觉得: “老家伙,有你的啊!”就加个关注!
如果文章有任何的错误,脱裤式欢迎大家来进行批评指正!
每一个鼓励都是lotoze我持续抛头颅,撒鸡血的创作动力!
每一个批评反馈也都是lotoze我持续成长的台阶!