JavaScript变量可以用来保存俩种类型的值:基本类型和引用类型值

前言

JS变量可以用来保存两种类型的值:基本类型值和引用类型值。基本类型的值源自一下5种基本数据类型:Underfined、Null、Boolean、Number和String。

基本类型值和引用类型值具有以下特点:

  • 基本类型值在内存中占据固定大小的空间,因此被保存在栈内存中;

  • 从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本;

  • 引用类型的值是对象,保存在堆内存中;

  • 包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针;

  • 从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向同一个对象;

  • 确定一个值是哪种基本类型可以使用Typeof操作符,而确定一个值是哪种引用类型可以使用instanceof操作符。

所有变量(包括基本类型和引用类型)都存在于一个执行环境(也称为作用域)当中,这个执行环境决定了变量的生命周期,以及那一部分代码可以访问其中的变量。

一下是关于执行环境的几点总结:

  • 执行环境有全局执行环境(也称为全局环境)和函数执行环境之分;

  • 每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链;

  • 函数的局部黄金不仅有权访问函数作用域中的变量,而且有权访问其包含(父)环境,乃至全局环境;

  • 全局环境只能访问在全局环境中定义的变量和函数,而不能直接访问局部环境中的任何数据;

  • 变量的执行环境有助于确定应该合适释放内存。

上述是来自JavaScript高级程序设计,先扫盲基本类型和引用类型值,接下来开始说说引用类型值

对于理解和使用引用类型值,我认为下面倆句话很关键

  • 包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针;

  • 从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向同一个对象

 先看一段简单的js

var o = {
    color:'red'
}; var a = o;
a.color = 'black';
console.log(o.color) // black

 为什么上边的 o.color会变成black能,砸门都没有对它进行操作!!它之所以改变时因为我们有一步将它赋值给了a,这个a就变成了引用类型的值再连起上面俩句话,就能理解引用类型的值和o.color变成black的原因了! 

备注:之所以写这个,是因为最近再写vue的学习项目时,用到了组件通信,父组件给子组件通信还好,但子组件给父组件通信就比较麻烦了,所以我就想到引用类型的值的特点(牵一发而动全身)+vue深处数据监听来实现子组件给父组件通信,一试还不错!但水平有限不能彻底搞懂这种方法可以吗?所以记下来,以便以后看到解决!

既然开始写了就吧引用类型的值的检测也总结记一下吧!  

1、常用的数据检测 typeof

typeof 返回一个表示数据类型的字符串,返回结果包括:number、boolean、string、object、undefined、function等6种数据类型。

typeof ''; // string 有效
typeof 1; // number 有效
typeof true; //boolean 有效
typeof undefined; //undefined 有效
typeof null; //object 无效
typeof [] ; //object 无效
typeof new Function(); // function 有效
typeof new Date(); //object 无效
typeof new RegExp(); //object 无效

typeof 可以对JS基础数据类型做出准确的判断,而对于引用类型返回的基本上都是object,这是因为因为所有对象的原型链最终都指向了Object,所以直接pass;

2、instanceof (不完美)

instanceof 是用来判断 A 是否为 B 的实例对,表达式为:A instanceof B,如果A是B的实例,则返回true,否则返回false。

注意的是:instanceof检测的是原型

instanceof (A,B) = {
var L = A.__proto__;
var R = B.prototype;
if(L === R) {
//A的内部属性__proto__指向B的原型对象
return true;
}
return false;
}

  该代码模拟instanceof内部执行过程从上述过程可以看出,当 A 的 __proto__ 指向 B 的 prototype 时,就认为A就是B的实例!

  但是还有问题就是,虽然 instanceof 能够判断出 [] 是Array的实例,但它认为 [] 也是Object的实例,如下

[] instanceof Array; //true
{} instanceof Object;//true
new Date() instanceof Date;//true function Person(){};
new Person() instanceof Person; [] instanceof Object; //true
new Date() instanceof Object;//true
new Person instanceof Object;//true

  这是因为:[]、Array、Object就形成了如下图所示的一条原型链:

  从原型链可以看出,[] 的 __proto__  直接指向Array.prototype, 间接指向Object.prototype, 所以按照 instanceof 的判断规则,[] 就是Object的实例。当然,类似的new Date()、new Person() 也会形成这样一条原型链,因此,instanceof 只能用来判断两个对象是否属于原型链的关系, 而不能获取对象的具体类型。

3、constructor(属性返回对创建此对象的数组函数的引用。)也有问题

当一个函数F被定义时,JS引擎会为F添加prototype原型,然后再在prototype上添加一个constructor属性,并让其指向F的引用。如下所示:

function F () {
  //定义函数
}
console.log('---F.prototype')
console.log(F.prototype) var f=new F(); console.log('---f.constructor === F')
console.log(f.constructor === F)

上面代码会在控制台输出以下内容

 

当一个函数F被定义时,JS引擎会为F添加prototype原型,然后再在prototype上添加一个constructor属性,并让其指向F的引用。

当执行 var f = new F() 时,F被当成了构造函数,f是F的实例对象,此时F原型上的constructor传递到了f上,因此f.constructor === F;

可以看出,JS在函数F的原型上定义了constructor,当F被当作构造函数用来创建对象时,创建的新对象就被标记为了“F” 类型,使得新对象有名有姓,可以追溯。

同理,JS中的数据类型也遵守这个规则:

细节问题:

  • null和undefined是无效的对象,因此是不会有constructor存在的,这两种类型的数据需要通过typeof来判断。
  • JS对象的constructor是不稳定的,这个主要体现在自定义对象上,当开发者重写prototype后,原有的constructor会丢失,constructor会默认为Object

为什么变成了Object?

prototype被重新赋值的是一个{}, {}是new Object()的字面量,因此new Object()会将Object原型上的constructor传递给{},也就是Object本身。

因此,为了规范,在重写对象原型时一般都需要重新给constructor赋值,以保证实例对象的类型不被改写。

4、Object.prototype.toString (完美)√

toString是Object原型对象上的一个方法,该方法默认返回其调用者的具体类型,更严格的讲,是 toString运行时this指向的对象类型, 返回的类型格式为[object,xxx],xxx是具体的数据类型,其中包括:String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument,... 基本上所有对象的类型都可以通过这个方法获取到。

  function typeofToString(obj) {
    var str = Object.prototype.toString.call(obj);
    var substr = str.match(/\s(\S*)]/);
    substr = str.match(/\s(\S*)]/);
    return substr[1];
  }
  console.log(typeofToString('')); //string
  console.log(typeofToString(1)); //Number
  console.log(typeofToString(true)); //Boolean
  console.log(typeofToString(undefined)); //Undefined
  console.log(typeofToString(null)); //Null
  var obj=new Function();
  console.log(typeofToString(obj)); //Function
  var obj=new Date();
  console.log(typeofToString(obj)); //Date
  console.log(typeofToString([])); //Array
  var obj=new RegExp();
  console.log(typeofToString(obj)); //RegExp
  var obj=new Error();
  console.log(typeofToString(obj)); //Error
  console.log(typeofToString(document)); //HTMLDocument
  console.log(typeofToString(window)); //Window

需要注意的是,必须通过Object.prototype.toString.call来获取,而不能直接 new Date().toString(), 从原型链的角度讲,所有对象的原型链最终都指向了Object, 按照JS变量查找规则,其他对象应该也可以直接访问到Object的toString方法,而事实上,大部分的对象都实现了自身的toString方法,这样就可能会导致Object的toString被终止查找,因此要用call来强制执行Object的toString方法。  

数据检测,原文地址

javascript变量的引用类型值的更多相关文章

  1. JavaScript基本类型值与引用类型值

    前言 JS变量可以用来保存两种类型的值:基本类型值和引用类型值.基本类型的值源自一下5种基本数据类型:Underfined.Null.Boolean.Number和String. 基本类型值和引用类型 ...

  2. JavaScript 变量类型 保存内存中的位置 和 引用

    1. JavaScript变量 基本类型值在内存中占据固定大小的空间 因此被保存在栈内存中. 从一个变量向另一个变量复制基本来下的值 会创建这个值得一个副本. 引用类型的值是对象 保存在堆内存中. 包 ...

  3. javascript变量问题

    CMAScript变量包含两种不同数据类型的值: 基本类型值:简单的数据段:引用类型值:可能有多个值构成的对象. 5种基本类型:Undefined,Null,Bollean,Number,String ...

  4. 深入浅出 JavaScript 变量、作用域和内存 v 0.5

    本文主要从原理入手分享变量和作用域的相关知识,最后结合本文所分享知识,再次深入了解下闭包的运行原理. 主要参考<JS高级程序设计> <JS权威指南> <高性能 JS> ...

  5. 【javascript 变量和作用域】

    今天学习了javascript 的变量和作用域的基本知识,对于以前在开发中遇到的一些不懂的小问题也有了系统的认识,收获还是比较多的. [基本类型和引用类型] ECMAScript 变量可能包含两种不同 ...

  6. 第一百零六节,JavaScript变量作用域及内存

    JavaScript变量作用域及内存 学习要点: 1.变量及作用域 2.内存问题 JavaScript的变量与其他语言的变量有很大区别.JavaScript变量是松散型的(不强制类型)本质,决定了它只 ...

  7. JavaScript变量相关问题

    本文重在探讨JavaScript变量包含的两种不同数据类型的值--基本类型值和引用类型值的区别.在此外稍微带过ECMAScript和JavaScript的关系. 题为JavaScript变量,但更具体 ...

  8. JavaScript变量与数据类型详解

    变量 变量来源于数学,是计算机语言中能储存计算结果或能表示值抽象概念.变量可以通过变量名访问. 变量的作用就是用于存储值. 语法: 声明变量时,总是以关键字var打头.任何情况下都应该这样做.然后给变 ...

  9. JavaScript变量类型检测总结

    JavaScript中的变量类型: 基本类型值:Undefined,Null,Boolean,Number和String. 按值访问(可直接操作保存在变量中的变量值): 复制规则:当复制基本类型值时: ...

随机推荐

  1. power designer和uml应用

    1.power designer和uml应用,它们可以帮助我们画图power designer还能在画图时帮助你完成代码.对于新手是很合适的一个画图工具, 2.这就是power designer 的示 ...

  2. eclipse首次使用的基本设置

    最近,一些刚开始学习Java的朋友使用eclipse遇到了一些编码导致的问题向我询问,那就总结一下首次安装eclipse后我们大体应该设置哪些基本东西吧~大神们呐就不用看啦. 一.修改工作空间默认编码 ...

  3. .Net Core 使用NLog记录日志到文件和数据库

    NLog 记录日志是微软官方推荐使用. 接下来,通过配置日志记录到文件和Sql Server数据库. 第一步:首先添加包NLog.Config (可通过微软添加包命令Install-Package 包 ...

  4. linux下启动tomcat服务的命令是什么

    Linux下tomcat服务的启动.关闭与错误跟踪,使用PuTTy远程连接到服务器以后,通常通过以下几种方式启动关闭tomcat服务:切换到tomcat主目录下的bin目录(cd usr/local/ ...

  5. C. Edgy Trees Codeforces Round #548 (Div. 2) 【连通块】

    一.题面 here 二.分析 这题刚开始没读懂题意,后来明白了,原来就是一个数连通块里点数的问题.首先在建图的时候,只考虑红色路径上的点.为什么呢,因为为了不走红色的快,那么我们可以反着想只走红色的路 ...

  6. Google发布移动网站设计原则

    Google 刚刚发布了由 Google 与 AnswerLab 联合打造,名为<Principles of Mobile Site Design: Delight Users and Driv ...

  7. linux通过源码安装nodejs

    1.下载nodejs源码,下载地址:https://nodejs.org/en/download/ 2.下载回来后,解压缩,ubuntu系统ctrl + alt +T 打开终端 假如tar.gz压缩包 ...

  8. JavaScript设计模式-20.责任链模式

    <html> <head> <title>javascript高级语法20-责任链模式</title> </head> <body&g ...

  9. 【LESS系列】内置函数说明

    本文转自 http://www.cnblogs.com/zfc2201/p/3493335.html escape(@string); // 通过 URL-encoding 编码字符串 e(@stri ...

  10. IDEA 启动项目,tomcat中配置的虚拟路径无法使用

    有时候,使用idea启动项目,非动静分离项目,直接根据图片url地址显示图片,会发现图片无法显示,tomcat中配置的虚拟路径无法使用,这时候需要配置idea.选择路径,然后给与一个访问名就行了.