JavaScript基础(2)—— 类型、值和变量

  本章是JavaScript中较为重要的一章,因此篇幅会较长,请耐心阅读。

  在编程语言中,类型,值和变量是最最基本的概念,所有的的编程语言都包含这三个术语,在详细介绍他们之前,我们由浅入深,用最简单的例子概括一下类型,值和变量分别是什么。

var msg = 'hello world'

   上例中,msg就是我们定义的变量'hello world'就是值,他被赋给变量msg,'hello world'的类型是字符串

   简单了解三者的概念后,就可以进入正题了,再次强调,本文除了是对《javaScript权威指南第6版》的概括和总结,还有许多拓展和舍弃的部分,看不懂得朋友可以翻一下原著,你会发现你更加看不懂。

 

1.数据类型概要

  通常我们将JavaScript中的数据类型分为两大类:原始类型和对象类型。

  原始类型包含数字,字符串,布尔类型和两个特殊的原始值null(空)和undefined(未定义)。

  对象(object)是属性(property)的集合,每个属性由“名称” 和 “值”构成,也就是键值对,普通的JavaScript对象是键值对的无序集合,但JavaScript定义了一种特殊的有序集合,即数组,因此,数组是“键有序”的特殊对象,在后面我们会详细介绍下数组。JavaScript还定义了一种特殊对象——函数,函数是具有可执行代码的对象,他的行为特征和其他对象都不一样,你甚至可以理解为——函数就是函数(暂时不将函数和对象混为一谈),关于函数部分,我会在ES6系列的Class和构造函数的关系一节中详细介绍(其实我还没有写),看完后可以帮助你理解为什么函数可以被称为对象。

   因此,我们可以讲JavaScript的数据类型整合为六大类:数字,字符串,布尔类型,null,undefined和对象。当然现在ES6在基础的数据类型上新增了symbol这一基本数据类型,有兴趣的可以自己了解一下。

 

2.为什么称JavaScript是一种面向对象的语言

  JavaScript是一门面向对象的语言,对大部分人来说这只是一句口号,很多人都不理解这句话的涵义是什么,即:为什么称JavaScript是一门面向对象的语言。

  我们先看原文是怎么说:JavaScript作为一门面向对象的语言,意味着我们不用全局定义函数去做操不同类型的值,数据类型本身可以定义方法(method)来使用值,例如,要对数组a中的元素进行排序,我们不必将a传入sort()函数,而是调用a的一个方法sort()。

a.sort() //sort(a)的面向对象版本

   这是我至少第三遍看这段原文,我已经看懂了,你呢?

   其实要了解面向对象,我们可以从别的方面入手,比如,为什么称C语言是面向过程的语言。在C语言中,当我们需要对某一类型的数据结构做一个常用(如排序)操作时,应该怎么做?

  我们需要先定义一个全局函数sort(),然后将数组作为参数传入sort()函数,经过排序后,return一个结果,如下示例:

//面向过程
function sort(arr){
  ... //将传入的数组进行排序
  return newArr
}
var a = [2,1,3]
a = sort(a)

  因此,可以将面向过程总结为,你想要操作某个值,就必须将该值传入预先定义好的函数中,才能产出你想要的结果。

  明白了面向过程后,再理解面向对象就简单多了。当你需要操作某个对象的时候,你可以直接使用对象内部的方法对这个对象进行操作,并得到你想要的结果,而无需预先定义好一个全局函数。如下示例:

var a = [2,1,3]
a.sort() // [1,2,3]

  

3.原始类型的不可变性

  JavaScript中的五大原始类型(数字,布尔,null,undefined和字符串)均是不可变类型,因此你也可以通过可变不可变将数据类型分为可变类型(对象)和不可变类型。

  需要注意的是,这里的可变不可变针对的是值,而不是变量,当我们输入一段代码

var a = 1

  a作为变量是可变的,a变量可以通过++变成23456,也可以摇身一变变成字符‘1’,或是变成布尔类型true,但1这个值本身是不会变的,你不可能通过任何操作把1变成0。为什么我要如此强调1的不可变性,因为在遇到字符串的时候,我们往往会认为字符串是可变的。来看下面这段代码

var str = 'hello world'
console.log(str.toUpperCase()) //HELLO WORLD
console.log(str) //hello world

  这段代码中的字符串被操作过后返回的是一个新的字符串,字符串本身永远保持不变,当然这段代码的玄机还有很多,如为什么字符串作为原始类型可以调用对象才能调用的方法,这一个疑问我们在后面的包装对象里进行解答,这里你只要知道,无法通过任何方法去改变不可变类型的值即可

4.包装对象是什么?

  JavaScript对象是一种复合值:他是属性或已命名值得集合。通过“.”符号来引用属性值,当属性值是一个函数得时候,我们可以通过obj.fn()来调用

  你在说泥马呐?我真搞不懂他想说什么。

  刚才我们在讲字符串的不可变特性时留下了一个疑问,即:为什么字符串作为原始类型,可以使用对象类型才能够使用的调用?下面我们来分步骤回答这个问题:

  第一步:var str = 'hello world' ;等号左边,我们称之为变量,等号右边,我们称之为值,值的类型,是字符串。

  第二步:值除了叫值,还可以称为:字面量。“字面量”按照字面意思理解就是除了字面意思还更深层的涵义。

  第三步:所以‘hello world’只是一个表面字符串,当他使用‘.’符号引用toUpperCase()函数的时候,他已经不是字符串了,JavaScript偷偷摸摸调用new String(str)把他变成了一个对象,这个对象继承了字符串的方法和属性。一旦引用结束,这个新创建的对象就被就地正法,所以你再打印str,他仍然打印一个字符串,而不是一个对象。(当然书上也说了,JavaScript也只是表面表现得这样,具体哪样,你问我我问谁)

  因此我们可以这么理解包装对象:当不可变类型需要被操作的时候,JavaScript就创建一个临时对象,来支持不可变类型的“常规操作”,当这个临时对象不再被引用的时候就销毁,不可变类型还是不可变类型,就跟啥也没发生一样。

5.深入浅出特殊类型null和undefined

  null和undefined都可以描述“空值”,JavaScript对于null和undefined的解释非常之精妙。

  undefined表示系统级的,出乎预料的或者类似错误的值得空缺。

  null表示程序级得,正常的,意料之中得空缺。

  如果你不能理解这两句话得涵义,说明你跟我之前一样,觉得这两句话跟放屁一样,什么叫出乎意料得空缺,什么又是意料之中的空缺?

  要理解这两句话,我从个人的角度上给予你一些帮助,下面来思考一个问题:

  请你在控制台打印一个null和一个undefined

  这里我提供一万种方法来打印undefined

  var a
  console.log(a)
  function b(c){
  	console.log(c)
  }
  console.log(b())
  var d = {}
  console.log(d.name)

  上述,a,b,c,d均打印undefined,因此undefined表面的是变量没有初始化,或者你要查询的对象的属性或数组元素的值不存在,或者函数的形参没有提供实参,或者函数没有返回值等等等等,均可以打印出undefined。

  那么问题来了,请问怎么打印一个null?

  我只找到一种方法打印null,就是

var a = null
console.log(a)

  没错,就是直接给变量赋值null,因此我们称之为,意料之中的,因为你不赋值,不可能有值等于null,这个null必然是人为的。

  解决了如何在控制台打印null和undefined的问题后,你再回头看看JavaScript的解释,是否和我一样茅塞顿开呐?

5.稍微了解下对象的引用

  what is 对象的引用?

  这里不得不从值的比较开始讲起。来看下面得代码和输出得结果:

var a = 'hello'
var b = 'hello'
console.log(a === b) //true
var c = {name:'hello'}
var d = {name:'hello'}
console.log(c==d) // false
var e = [1]
var f = [1]
console.log(e==f) //false
console.log(e[0]===f[0]) //true

  从上述的例子中可以看出,看起来相等的两个对象,实则是不同的,也就是说对象的比较并非值得比较,即使两个对象包含相同的属性以及相同的值,他们也是不相等的。

  那么对象什么时候才会相等呢?

var a = [1]
var b = a
b[0] = 3
console.log(a) //[3]
console.log(a===b) //true

   我们可以看到,当把a对象赋值给b之后,改变b的值也会影响a的值,此时你可以认为,a,b完全相等,因为他们指向同一片内存地址

  对计算机概念不太了解的童鞋可能不太明白什么叫指向同一片内存地址,下面我们来分解一下JavaScript创建对象的步骤

  第一步:JavaScript发现a变量被赋值为一个数组(特殊的对象),因此JavaScript向计算机申请在内存空间分配一块地给a,这块地可以是连续的(数组),也可以是不连续的(普通对象),但不管他连不连续,每片田只能种一样东西——如果a[0] = '番薯',那么a[0]就不会等于土豆,你可以在a[1]种土豆。

  第二步:a初始化完成之后,这个变量就会得到计算机给他的一个地址,也就是a对象的地的地址是从哪里开始的,注意这里a只需要拿到第一块地的地址就可以了(你可以理解为第一块地连着第二块地,第二块地连着第三块地,以此类推,因此不需要担心后面的地的地址找不到,因为他们是连在一起的)。

  第三步:情况1 —— JavaScript发现b变量也被赋值一个数组,这个数组是一个新的数组,那怎么办呢?JavaScript只好再给b申请一片地,b就在这片地上进行耕作,此时a的第一块地种了土豆,b的第一块地也种土豆,但这两块地终究不是一块地,因为他们的地址不一致,这也就解释了第一个例子中两个属性完全相等的对象为什么不相等,因为他们指向的不是同一个内存空间。情况2——新来的b变量被赋值a,那么b就会获得a的地址,此时你不管让b去种地,还是让a去种地,他们修改的都是同一块内存空间的值,因此a和b完全相等,因为他们指向同一片内存。

  因此对象的引用指的就是当你把对象变量赋值给另一个变量是,实际上这两个变量都指向同一个地址,也就是说他们是完全相等的一个对象。就是一男两女了,你懂我意思吧?

  本章内容是原文第三章的内容,个人认为比较好的还有隐式类型转化和显式类型转换全局对象等概念,关于变量作用域和变量提升,函数作用域等部分也十分重要,但由于ES6打破了函数作用域的规则,这里就不过多讲解已经过时的知识了,有兴趣的自行了解下上面的关键字,喜欢博主(不喜欢前端也可以)的女粉丝可以加官方粉丝群 708637831

发布了109 篇原创文章 · 获赞 196 · 访问量 30万+

猜你喜欢

转载自blog.csdn.net/dkr380205984/article/details/90199432
今日推荐