JS - 数据类型 以及 数据、变量和内存、值传递

本文详细解析JavaScript的基本类型(如String、Number等)和引用类型(如Object和Function)区别,探讨typeof、instanceof和==的判断技巧,讲解实例、undefined、null的含义,以及变量、数据、内存和赋值的关系。重点剖析值传递与引用传递的实例,揭示JS中复杂的数据传递策略——共享传递。

1.分类

(1).基本(值)类型(保存变量内存值的类型)
  ① String
  ② Number
  ③ boolean
  ④ undefined
  ⑤ null
(2). 对象 (引用) 类型(保存地址值)
  ① Object:任意对象
  ② Function:一种特别的对象(可以执行)
  ③ Array:一种特别的对象(数值下标,内部数据有序)

2. 判断
  ① typeof:返回的是数据类型的字符串表达,可以判断 undefined/ 数值/字符串/布尔值
          可以判断:undefined / 数值 / 字符串 / 布尔值 / function
          不能判断:null与object、object与array
  ② instanceof:判断对象的类型(具体类型)
         定义: instanceof 用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上;
         语法:object  instanceof  constructor 
                    object:某个实例对象
                    constructor :某个构造函数
  ③ ===:  可以判断undefined,null

// ① 基本类型
var a;
console.log(a, typeof a, type a ==='undefined', a === undefined) // undefined   'undefined'  true  true
console.log( undefined === 'undefined')  // false
// ② 对象
var b1 = {
  b2: [1, 'abc', console.log]
  b3: function() {
    console.log('b3')
    return function() {
      retuen 'xxxxxx'
    }
  }
}
cosnole.log(b2 instanceof Object, b1 instanceof Array)  // true  false
cosnole.log(b1.b2 instanceof Object, b1.b2 instanceof Array)  // true  true
cosnole.log(b1.b3 instanceof Function, b1.b3 instanceof Object)  // true  true
console.log(b1.b3()())  // xxxxxx

3. 相关问题
(1)
. 实例是什么?
     实例:实例对象
     类型:类型对象
function Persion(name,age) {      // Persion是构造函数实际上是类型对象(函数)
    this.name = name;
    this.age= age;
}
 ①  var p = new Persion('Tom', 12);  //  p 是根据类型创建的实例对象,其实调用的时候用new来调用才能确定他是构造函数,只不过创建的时候就算当作构造函数创建的,以为我们的函数名是大写的。
 ②  Persion(‘Jack’,12);  //  这种调用从语法上来说是符合的,但是从原则上来说是不应该的,毕竟函数进行创建的时候就算一构造函数的目的来创建的,所以调用的时候也要使用正确的调用方法
(2). undefined 和 null 的区别?
   undefind:定义未赋值
   null:定义并赋值,值为null

4.(1) 什么是数据:存储在内存中代表特定信息的“东西”,本质上是0101..
         ① 数据的特点:可传递、可运算;
         ② 算术运算、逻辑运算、赋值运算、运行函数
   (2) 什么是内存:内存条通电后产生可存储数据的空间(临时的)
        ① 内存的产生和死亡:内存条(电路板) --> 产生内存空间 --> 存储数据 --> 处理数据 --> 断电 --> 内存空间和数据消失。
        ② 一块内存里有两个数据:内部存储的数据、地址值
        ③ 内存分类:
            * 栈:  全局变量/局部变量、
            * 堆:对象
左侧是栈右侧是堆,栈里放变量,堆里放对象​​​​​​​
  (3) 什么是变量:可变化的量,由变量名和变量值组成;每个变量对应一块内存,变量名用来查找对应的内存,变量值就算内存中保存的数据;
5. 赋值和内存的问题
    var a = xxx, a内存中到底保存的是什么?
 xxx是基本数据,保存的就是这个数据;
 xxx是对象,保存的是对象的地址值;
 xxx是一个变量,保存的是xxx的内存内容(可能是基本数据,也可能是地址值)
6. 引用变量赋值传递问题

(1). 2个引用变量指向同一个对象,让其中一个引用变量指向另一个对象,另一引用变量依然指向前一个对象
  var a = {age: 12};
  var b = a ;
  a =  {name: 'Tom', age: 13};
  console.log(b.age, b.name, a.age, a.name) // 12, undefined, 13, Tom
(2). 2个引用变量指向同一个对象,让其中一个引用变量指向另一个对象,另一引用变量依然指向前一个对象
  function fn2 (obj) {
    obj = { age: 15 }
  };
  fn2(a);
  console.log(a.age);  // 13   (obj 和 a 是两个对象,obj的age值改为15,不影响a的值)
(3). 2个引用变量指向同一个对象,通过一个变量修改对象内部的数据,另一个变量看到的是修改之后的数据
  var obj1 = {name: 'Tom'};
  var obj2 = obj2;
  obj2.age = 12;
  console.log(obj1.age);  // 12
  function fn (obj) {
    obj.name = 'A'
  };
  fn(obj1);
  console.log(obj.name); // A

7. 在js调用函数传递参数变量时,是值传递还是引用传递:

// 基本类型按值传递              // 换种写法
var a = 3;                               var a = 3;  
function fn(a){                          function fn(c) { 
 a = a + 1                                 b = c+1; 
                                           console.log(c,111)  // 3
                                       
}                                         }                                  
fn(a);                                    fn(a);
console.log(a); // 3                      console.log(a,222);  // 3
                                          console.log(b,333);  // 4
// eg2:
var a = 1;
function foo(val) {
  val = 2;
}
foo(a);
console.log(a);  // 输出结果为:1
// 引用类型按照对象传递(传递的是对象的地址值,其实也相当于一种值传递)
function fn2 (obj) {
 console.log(obj.name)
}
var obj = {name: 'Tom'};  
fn2(obj);  //读到obj的(地址)值,然后把地址值赋值给形参,也就是函数内部的局部变量obj

// eg2:
var person = {name:'MJ'};
function foo(obj) {
  obj.name = 'EP';
}
foo(person);
console.log(person.name); // 输出结果为:EP

 对象person被修改了!这说明obj跟person指向的是同一个对象,可以肯定不是按值传递的了,那么就是引用传递了吗?从这个例子来看确实很像,我们再对上面的例子做下修改,如下:

// eg3:
var person = {name: "MJ"};
function foo(obj) {
  obj = new Object(); // 修改部分
  obj.name = "EP";
}
foo(person);
console.log(person.name); // 输出结果为:MJ

        输出结果是MJ,也就是说person对象并未被修改,如此可以确定,js的引用类型也不是按引用传递。既不是按值传递,又不是按引用传递,那是按什么传递呢?
        准确的说,JS中的基本类型按值传递,引用类型按共享传递(call by sharing,也叫按对象传递、按对象共享传递);该策略的重点是:调用函数传参时,函数接受对象实参引用的副本(既不是按值传递的对象副本,也不是按引用传递的隐式引用)。 它和按引用传递的不同在于:在共享传递中对函数形参的赋值,不会影响实参的值。
        那为什么eg3中person没有被修改?

        我们都知道对象保存在堆中,person持有堆中对象的引用,在调用foo函数时,函数接收的实际是person持有的对象(下面称之为原对象)引用的副本,这样obj和person都指向了同一个地方(也就是原对象在堆中存放的地址),而函数中的obj = new Object()操作其实是在堆中创建了一个新对象,并让obj持有该对象的引用,这样obj与原对象之间的关系就断开了,转而与新对象建立了关系,所以对obj的修改并不会影响到原对象。(本来obj和person指向的是同一个地址值,但是创建的新对象打断了obj之前的指向)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值