《JavaScript面向对象精要》之一:基本类型和引用类型

栏目: 后端 · 前端 · 发布时间: 6年前

内容简介:原始类型保存为简单数据值。为了让开发者能够把原始类型和引用类型按相同的方式处理,JavaScript 花费了很大的努力来保证语言的一致性。其他编程语言用栈存原始类型,用对存储引用类型。

原始类型保存为简单数据值。 引用类型 保存为对象,其本质是指向内存位置的引用。

为了让开发者能够把原始类型和引用类型按相同的方式处理,JavaScript 花费了很大的努力来保证语言的一致性。

其他编程语言用栈存原始类型,用对存储引用类型。

而 JavaScript 则完全不同:它使用一个变量对象追踪变量的生存期。

原始值被直接保存在变量对象内,而引用值则作为一个指针保存在变量对象内,该指针指向实际对象在内存中的存储位置。

1.2 原始类型

原始类型代表照原样保存的一些简单数据。

JavaScript 共有5种原始类型:

  • boolean 布尔,值为 true or false
  • number 数字,值为任何整型或浮点数值
  • string 字符串,值为由单引号或双引号括住的单个字符或连续字符
  • null 空类型,仅有一个值:null
  • undefined 未定义,只有一个值:undefined(undefined 会被赋给一个还没有初始化的变量)

JavaScript 和许多其他语言一样,原始类型的变量直接保存原始值(而不是一个指向对象的指针)。

var color1 = "red";
var color2 = color1;

console.log(color1); // "red"
console.log(color2); // "red"

color1 = "blue";

console.log(color1); // "blue"
console.log(color2); // "red"
复制代码

鉴别原始类型

鉴别原始类型的最佳方式是使用 typeof 操作符。

console.log(typeof "Nicholas"); // "string"
console.log(typeof 10);         // "number"
console.log(typeof true);       // "boolean"
console.log(typeof undefined);  // "undefined"
复制代码

至于空类型(null)则有些棘手。

console.log(typeof null); // "object"
复制代码

对于 typeof null,结果是"object"。(其实这已被设计和维护 JavaScript 的委员会 TC39 认定是一个错误。在逻辑上,你可以认为 null 是一个空的对象指针,所以结果为"object",但这还是很令人困惑。)

判断一个值是否为空类型(null)的最佳方式是直接和 null 比较:

console.log(value === null); // true or false
复制代码

注意:以上这段代码使用了三等号(全等 ===),因为三等号(全等)不会将变量强制转换为另一种类型。

console.log("5" == 5); // true
console.log("5" === 5); // false

console.log(undefined == null); // true
console.log(undefined === null); // false
复制代码

原始方法

虽然字符串、数字和布尔值是原始类型,但是它们也拥有方法(null 和 undefined 没有方法)。

var name = "Nicholas";
var lowercaseName = name.toLowerCase(); // 转为小写

var count = 10;
var fixedCount = count.toFixed(2); // 转为10.00

var flag = true;
var stringFlag = flag.toString(); // 转为"true"

console.log("YIBU".charAt(0)); // 输出"Y"
复制代码

尽管原始类型拥有方法,但它们不是对象。JavaScript 使它们看上去像对象一样,以此来提高语言上的一致性体验。

1.3 引用类型

引用类型是指 JavaScript 中的对象,同时也是你在该语言中能找到最接近类的东西。

引用值是引用类型的实例,也是对象的同义词(后面将用对象指代引用值)。

对象是属性的无序列表。属性包含键(始终是字符串)和值。如果一个属性的值是函数,它就被称为方法。

除了函数可以运行以外,一个包含数组的属性和一个包含函数的属性没有什么区别。

创建对象

有时候,把 JavaScript 对象想象成哈希表可以帮助你更好地理解对象结构。

JavaScript 有好几种方法可以创建对象,或者说实例化对象。第一种是使用 new 操作符和构造函数。

构造函数就是通过 new 操作符来创建对象的函数——任何函数都可以是构造函数。根据命名规范,JavaScript 中的构造函数用首字母大写来跟非构造函数进行区分。

var object = new Object();
复制代码

因为引用类型不再变量中直接保存对象,所以本例中的 object 变量实际上并不包含对象的实例,而是一个指向内存中实际对象所在位置的指针(或者说引用)。这是对象和原始值之间的一个基本差别,原始值是直接保存在变量中。

当你将一个对象赋值给变量时,实际是赋值给这个变量一个指针。这意味着,将一个变量赋值给另外一个变量时,两个变量各获得了一份指针的拷贝,指向内存中的同一个对象。

var obj1 = new Object();
var obj2 = obj1;
复制代码

对象引用解除

JavaScript 语言有垃圾收集的功能,因此当你使用引用类型时无需担心内存分配。但最好在不使用对象时将其引用解除,让垃圾收集器对那块内存进行释放。解除引用的最佳手段是将对象变量设置为 null

var obj1 = new Object();
// dosomething
obj1 = null; // dereference
复制代码

添加删除属性

在 JavaScript 中,你可以随时添加和删除其属性。

var obj1 = new Object();
var obj2 = obj1;

obj1.myCustomProperty = "Awsome!";
console.log(obj2.myCustomProperty); // "Awsome!" 因为 obj1 和 obj2 指向同一个对象。
复制代码

1.4 内建类型实例化

内建类型如下:

  • Array 数组类型,以数字为索引的一组值的有序列表
  • Date 日期和时间类型
  • Error 运行期错误类型
  • Function 函数类型
  • Object 通用对象类型
  • RegExp 正则表达式类型

可使用 new 来实例化每一个内建引用类型:

var items = new Array();
var now = new Date();
var error = new Error("Something bad happened.");
var func = new Function("console.log('HI');");
var object = new Object();
var re = new RegExp();
复制代码

字面形式

内建引用类型有字面形式。字面形式允许你在不需要使用 new 操作符和构造函数显示创建对象的情况下生成引用值。属性的 可以是标识符或字符串(若含有空格或其他特殊字符)

var book = {
  name: "Book_name",
  year: 2016
}
复制代码

上面代码与下面这段代码等价:

var book = new Object();
book.name = "Book_name";
book.year = 2016;
复制代码

虽然使用字面形式并没有调用 new Object(),但是 JavaScript 引擎背后做的工作和 new Object() 一样,除了没有调用构造函数。其他引用类型的字面形式也是如此。

1.5 访问属性

可通过 .中括号 访问对象的属性。 中括号 [] 在需要动态决定访问哪个属性时,特别有用。因为你可以用 变量 而不是字符串字面形式来指定访问的属性。

1.6 鉴别引用类型

函数是最容易鉴别的引用类型,因为对函数使用 typeof 操作符时,返回"function"。

function reflect(value){
  return value;
}
console.log(typeof reflect); // "function"
复制代码

对其他引用类型的鉴别则较为棘手,因为对于所有非函数的引用类型, typeof 返回 object 。为了更方便地鉴别引用类型,可以使用 JavaScript 的 instanceof 操作符。

var items = [];
var obj = {};
function reflect(value){
  return value;
}

console.log(items instanceof Array); // true;
console.log(obj instanceof Object); // true;
console.log(reflect instanceof Function); // true;
复制代码

instanceof 操作符可鉴别继承类型。这意味着所有对象都是 Oject 的实例,因为所有引用类型都继承自 Object

虽然 instanceof 可以鉴别对象类型(如数组),但是有一个列外。JavaScript 的值可以在同一个网页的不用框架之间传来传去。由于每个网页拥有它自己的全局上下文—— Object、Array 以及其他内建类型的版本。所以当你把一个对象(如数组)从一个框架传到另外一个框架时,instanceof 就无法识别它。

1.8 原始封装类型

原始封装类型有 3 种:String、Number 和 Boolean。 当读取字符串、数字或布尔值时,原始封装类型将被自动创建。

var name = "Nicholas";
var firstChar = name.charAt(0); // "N"
复制代码

这在背后发生的事情如下:

var name = "Nichola";
var temp = new String(name);
var firstChar = temp.charAt(0);
temp = null;
复制代码

由于第二行把字符串当成对象使用,JavaScript 引擎创建了一个字符串的实体让 charAt(0) 可以工作。字符串对象的存在仅用于该语句并在随后销毁(一种被称为自动打包的过程)。为了测试这一点,试着给字符串添加一个属性看看它是不是对象。

var name = "Nicholas";
name.last = "Zakas";

console.log(name.last); // undefined;
复制代码

下面是在 JavaScript 引擎中实际发生的事情:

var name = "Nicholas";
var temp = new String(name);
temp.last = "Zakas";
temp = null; // temporary object destroyed

var temp = new String(name);
console.log(temp.last);
temp = null;
复制代码

新属性 last 实际上是在一个立刻就被销毁的临时对象上而不是字符串上添加。之后当你试图访问该属性时,另一个不同的临时对象被创建,而新属性并不存在。

虽然原始封装类型会被自动创建,在这些值上进行 instanceof 检查对应类型的返回值却是 false 。 这是因为 临时对象仅在值被读取时创建instanceof 操作符并没有真的读取任何东西,也就没有临时对象的创建。

当然你也可以手动创建原始封装类型。

var str = new String("me");
str.age = 18;

console.log(typeof str); // object
console.log(str.age); // 18
复制代码

如你所见,手动创建原始封装类型实际会创建出一个 object 。这意味着 typeof 无法鉴别出你实际保存的数据的类型。

另外,手动创建原始封装类型和使用原始值是有一定区别的。所以尽量避免使用。

var found = new Boolean(false);
if(found){
  console.log("Found"); // 执行到了,尽管对象的值为 false
}
复制代码

这是因为一个对象(如 {} )在条件判断语句中总被认为是 true ;

1.9 总结

第一章的东西都是我们一些比较熟悉的知识。但是也有一些需要注意的地方:

  • 正确区分原始类型和引用类型
  • 对于 5 种原始类型都可以用 typeof 来鉴别,而空类型必须直接跟 null 进行全等比较。
  • 函数也是对象,可用 typeof 鉴别。其它引用类型,可用 instanceof 和一个构造函数来鉴别。(当然可以用 Object.prototype.toString.call() 鉴别,它会返回 [object Array]之类的)。
  • 为了让原始类型看上去更像引用类型,JavaScript提供了 3 种封装类型。JavaScript会在背后创建这些对象使得你能够像使用普通对象那样使用原始值。但这些临时对象在使用它们的语句结束时就立刻被销毁。虽然可手动创建,但不建议。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

嗨翻C语言

嗨翻C语言

[美]David Griffiths、[美]Dawn Griffiths / 程亦超 / 人民邮电出版社 / 2013-9 / 99.00

你能从这本书中学到什么? 你有没有想过可以轻松学习C语言?《嗨翻C语言》将会带给你一次这样的全新学习 体验。本书贯以有趣的故事情节、生动形象的图片,以及不拘一格、丰富多样的练 习和测试,时刻激励、吸引、启发你在解决问题的同时获取新的知识。你将在快乐 的气氛中学习语言基础、指针和指针运算、动态存储器管理等核心主题,以及多线 程和网络编程这些高级主题。在掌握语言的基本知识......一起来看看 《嗨翻C语言》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具