mc-congxueda

导航

 

一、JavaScript 数据类型

       两种: 基本数据类型 、 引用数据类型

 

     基本数据类型Number、String、Boolean、Null、 Undefined、Symbol(ES6),这些类型可以直接操作保存在变量中的实际值

     引用数据类型Object(在JS中除了基数据类型以外的都是对象,数据是对象,函数是对象,正则表达式是对象)

 

  var x;               // x 为 undefined
  var x = 5;           // 现在 x 为数字
  var x = "John";      // 现在 x 为字符串

  var x = false          // 现在x为布尔类型

      var x  = [] | {} | NULL  // 现在x类型为对象'Object'

 

二、JavaScript 数据类型判断

  1、typeof 

  2、instanceof

  3、constructor   除null  \ undefined  其它都可以

  4、Object.prototype.toString.call()

 

 

 

》》》》typeof

基本数据类型中:Number,String,Boolean,undefined 以及引用数据类型中Function ,可以使用typeof检测数据类型,分别返回对应的数据类型小写字符

另:用typeof检测构造函数创建的Number,String,Boolean都返回object    

基本数据类型中:null 。引用数据类型中的:Array,Object,Date,RegExp。不可以用typeof检测。都会返回小写的object

console.log(
    typeof 100, //"number"
    typeof 'abc', //"string"
    typeof false, //"boolean"
    typeof undefined, //"undefined"
    typeof null, //"object"
    typeof [1,2,3], //"object"
    typeof {a:1,b:2,c:3}, //"object"
    typeof function(){console.log('aaa');}, //"function"
    typeof new Date(), //"object"
    typeof /^[a-zA-Z]{5,20}$/, //"object"
    typeof new Error() //"object"
    typeof new Number(100), //'object'
    typeof new String('abc'),// 'string'
    typeof new Boolean(true),//'boolean'
);

 

》》》》instanceof

除了使用typeof来判断,还可以使用instanceof。instanceof运算符需要指定一个构造函数,或者说指定一个特定的类型,它用来判断这个构造函数的原型是否在给定对象的原型链上。

 

console.log(
    100 instanceof Number, //false
    'dsfsf' instanceof String, //false
    false instanceof Boolean, //false
    undefined instanceof Object, //false
    null instanceof Object, //false
    [1,2,3] instanceof Array, //true
    {a:1,b:2,c:3} instanceof Object, //true
    function(){console.log('aaa');} instanceof Function, //true
    new Date() instanceof Date, //true
    /^[a-zA-Z]{5,20}$/ instanceof RegExp, //true
    new Error() instanceof Error //true
)

 

  • 基本数据类型中:Number,String,Boolean。字面量值不可以用instanceof检测,但是构造函数创建的值可以,如下:
var num = new Number(123);
var str = new String('dsfsf');
var boolean = new Boolean(false);

 

num instanceof Object   // true

需要注意null和undefined都返回了false,这是因为它们的类型就是自己本身,并不是Object创建出来它们,所以返回了false。

 

》》》》》constructor  构造函数

onstructor是prototype对象上的属性,指向构造函数。根据实例对象寻找属性的顺序,若实例对象上没有实例属性或方法时,就去原型链上寻找,因此,实例对象也是能使用constructor属性的。

如果输出一个类型的实例的constructor,就如下所示:

console.log(new Number(123).constructor)
//ƒ Number() { [native code] }

 

var num  = 123;
var str  = 'abcdef';
var bool = true;
var arr  = [1, 2, 3, 4];
var json = {name:'wenzi', age:25};
var func = function(){ console.log('this is function'); }
var und  = undefined;
var nul  = null;
var date = new Date();
var reg  = /^[a-zA-Z]{5,20}$/;
var error= new Error();

function Person(){
  
}
var tom = new Person();

// undefined和null没有constructor属性
console.log(
    tom.constructor==Person,
    num.constructor==Number,
    str.constructor==String,
    bool.constructor==Boolean,
    arr.constructor==Array,
    json.constructor==Object,
    func.constructor==Function,
    date.constructor==Date,
    reg.constructor==RegExp,
    error.constructor==Error
);
//所有结果均为true

在构造函数判断,当前值类型

除了undefined和null报错之外,其他类型都可以通过constructor属性来判断类型。

 

》》》》使用Object.prototype.toString.call()检测对象类型

var toString = Object.prototype.toString;

toString.call(123); //"[object Number]"
toString.call('abcdef'); //"[object String]"
toString.call(true); //"[object Boolean]"
toString.call([1, 2, 3, 4]); //"[object Array]"
toString.call({name:'wenzi', age:25}); //"[object Object]"
toString.call(function(){ console.log('this is function'); }); //"[object Function]"
toString.call(undefined); //"[object Undefined]"
toString.call(null); //"[object Null]"
toString.call(new Date()); //"[object Date]"
toString.call(/^[a-zA-Z]{5,20}$/); //"[object RegExp]"
toString.call(new Error()); //"[object Error]"

 

封装一个获取变量准确类型的函数

function gettype(obj) {
  var type = typeof obj;

  if (type !== 'object') {
    return type;
  }
  //如果不是object类型的数据,直接用typeof就能判断出来

  //如果是object类型数据,准确判断类型必须使用Object.prototype.toString.call(obj)的方式才能判断
  return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1');
}

 

三、JavaScript 数据类型堆栈概念

栈为自动分配的内存空间,它由系统自动释放;而堆则是动态分配的内存,大小也不一定会自动释放

基本类型:存在栈中,简单数据类型 , 大小确定,存放值直接访问  或引用类型指针

引用类型:堆中  ,大小不确定  存放数据

var a = 10;

var b = a;
b = 20;
console.log(a); // 10值
console.log(b); // 20值

 

 

 基本类型赋值 会创建一个独立空间,赋值不影响原有值;独立空间 、独立空间、独立空间

引用数据类型(存放在堆内存中的对象,每个空间大小不一样,要根据情况进行特定的配置)

    引用类型是存放在堆内存中的对象,变量其实是保存的在栈内存中的一个指针(保存的是堆内存中的引用地址),这个指针指向堆内存。

    引用类型数据在栈内存中保存的实际上是对象在堆内存中的引用地址。通过这个引用地址可以快速查找到保存中堆内存中的对象

var obj1 = new Object();

var obj2 = obj1;

obj2.name = "我有名字了";

console.log(obj1.name); // 我有名字了

 

    说明这两个引用数据类型指向了同一个堆内存对象。obj1赋值给obj2,实际上这个堆内存对象在栈内存的引用地址复制了一份给了obj2,但是实际上他们共同指向了同一个堆内存对象,所以修改obj2其实就是修改那个对象,所以通过obj1访问也能访问的到。

 

 

 var a = [1,2,3,4,5];

var b = a;//传址 ,对象中传给变量的数据是引用类型的,会存储在堆中;
var c = a[0];//传值,把对象中的属性/数组中的数组项赋值给变量,这时变量C是基本数据类型,存储在栈内存中;改变栈中的数据不会影响堆中的数据
alert(b);//1,2,3,4,5
alert(c);//1
//改变数值 
b[4] = 6;
c = 7;
alert(a[4]);//6
alert(a[0]);//1

从上面我们可以得知,当我改变b中的数据时,a中数据也发生了变化;但是当我改变c的数据值时,a却没有发生改变。

     这就是传值与传址的区别。因为a是数组,属于引用类型,所以它赋予给b的时候传的是栈中的地址(相当于新建了一个不同名“指针”),而不是堆内存中的对象。而c仅仅是从a堆内存中获取的一个数据值,并保存在栈中。所以b修改的时候,会根据地址回到a堆中修改,c则直接在栈中修改,并且不能指向a堆内存中。

 

 

四、JavaScript 数据类型-类型转换

JS中的类型转换方式一般分为三类:转为String型,转为数字型,转为布尔型     string \ number \ Boolean

  

一.转为String型

1.toString()

通过变量.toString()可以将其他类型的变量转换为字符串型(null和undefined没有toString()方法)

  

 

 

 

这种方法为强制转换(null和undefined通过这个方法可以成功转换为字符串类型)

let age = 18;
let myname = true;
let temp = null;

console.log(typeof age);
console.log(typeof myname);
console.log(typeof temp);

age = String(age);
myname = String(myname);
temp = String(temp);

console.log(typeof age);
console.log(typeof myname);
console.log(typeof myname);

 

 

 

 3.隐式转换(通过+)

        let age = 18;
        let myname = true;
        let temp = null;
 
        console.log(typeof age);
        console.log(typeof myname);
        console.log(typeof temp);
 
        age = age + '';
        myname = myname + '';
        temp = temp + '';
 
        console.log(typeof age);
        console.log(typeof myname);
        console.log(typeof myname);

 

 

 

 

二.转为数字型
表单输入的数据通常为字符串型,但是要进行加法操作得到数字型数据,只能为两个数字型相加减,所以需要将字符串型转为数字型

1.Number()

1)如果字符串中全为数字,转换后结果为字符串中数字

2)字符串中有非数字内容,转换后结果为NaN

3)字符串为空,转换后为0

注:true--1,false--0,null--0,undefined--NaN 

        let a = '18123';
        let b = '12dddd';
        let c = ' ';
        let d = true;
 
        a = Number(a);
        b = Number(b);
        c = Number(c);
        d = Number(d);
 
        console.log(a);
        console.log(b);
        console.log(c);
        console.log(d);

 

 

 

 

 

2.parseInt()

通过这个方法,可以将字符串中含有非数字内容且以数字内容开头的字符串转换为数字型,当字符串以字母或者符号开头,只能转换为NaN,但是其他可转换类型的数据只能转换为整数,当遇到数据中存在小数点时,进行取整。(空字符串,布尔型,null,undefined进行转换只能转换为NaN) 

        let a = '18123';
        let b = '12dddd';
        let c = ' 12';
        let d = '';
        let e = '5.67'
 
        a = parseInt(a);
        b = parseInt(b);
        c = parseInt(c);
        d = parseInt(d);
        e = parseInt(e);
 
        console.log(a);
        console.log(b);
        console.log(c);
        console.log(d);
        console.log(e);

 

 

 

3.parseFloat()

原理与parseInt()相同,只不过此时通过这个方法,可以将有小数点的字符串转换为有小数点的数字型,此类方法不可以指定进制,只能转为十进制

 

        let a = '18.123';
        let b = '12.38dddd';
        let c = ' 12';
        let d = '';
        let e = '5.67'
 
        a = parseFloat(a);
        b = parseFloat(b);
        c = parseFloat(c);
        d = parseFloat(d);
        e = parseFloat(e);
 
        console.log(a);
        console.log(b);
        console.log(c);
        console.log(d);
        console.log(e);

 

 

 

 

4.隐式转换

通过与数字型数字进行减法,除法,乘法运算,可以将其转换为数字型,可以理解为系统自动先使用Number(),对需要转换的值进行转换后再与数字型相运算,Number()中转换为NaN的类型,使用隐式转换仍为NaN

 

        let a = '18123';
        let b = '12dddd';
        let c = null;
        let d = true;
 
        a = a * 1;
        b = b - 1;
        c = c - 1;
        d = d / 1;
 
        console.log(a);
        console.log(b);
        console.log(c);
        console.log(d);

  

 

 

 

 三.转为布尔型

1)Boolean()

其他类型通过这个方法,均可以转换为true或者false,空字符串,null,undefined,NaN,0均转为false,其他的全为true。

 

        let a = '18';
        let b = 12;
        let c;
        let d = '';
        let e = null;
 
        a = Boolean(a);
        b = Boolean(b);
        c = Boolean(c);
        d = Boolean(d);
        e = Boolean(e);
 
        console.log(a);
        console.log(b);
        console.log(c);
        console.log(d);
        console.log(e);

 

 

 


在 JavaScript 有两种类型转换的方式,分别是隐式类型转换和强制类型转换(也叫显式类型转换)。

1. JS 隐式类型转换

隐式转换就是自动转换,通常发生在一些数学运算中。因为 JavaScript 是一种弱类型的语言,在一个表达式中,运算符两边的类型可以不同(比如一个字符串和一个数字相加),JavaScript 解释器会在运算之前将它们的类型进行转换,如下所示:

  1. var str = "http://c.biancheng.net/";
  2. var num = 123;
  3. var res = str + num;
  4. document.write(typeof res); // 输出:string
  5. document.write(res); // 输出:http://c.biancheng.net/123

通过运行结果可以看出,将一个字符串与一个数字相加,会得到一个字符串类型的值。如果是在 C语言或者 Java 语言中的话,上面的运算会因为运算符两边的数据类型不一致而导致报错,但在 JavaScript 中则不会,因为在运算之前 JavaScript 解释器会将上面的 num 变量隐式的转换为字符串类型,之后再进行运算。

JavaScript 中,表达式中包含以下运算符时,会发生隐式类型转换:

  • 算术运算符:加(+)、减(-)、乘(*)、除(/)、取模(%);
  • 逻辑运算符:逻辑与(&&)、逻辑或(||)、逻辑非(!);
  • 字符串运算符:+、+=。


示例代码如下:

  1. document.write("3" - 2); // 输出:1
  2. document.write("3" + 2); // 输出:"32"
  3. document.write(3 + "2"); // 输出:"32"
  4. document.write("3" * "2"); // 输出:6
  5. document.write("10" / "2"); // 输出:5
  6. document.write(1 + true); // 输出:2
  7. document.write(1 + false); // 输出:1
  8. document.write(1 + undefined); // 输出:NaN
  9. document.write(3 + null); // 输出:3
  10. document.write("3" + null); // 输出:"3null"
  11. document.write(true + null); // 输出:1
  12. document.write(true + undefined); // 输出:NaN

通过运行结果可以得出:

  • 字符串加数字,数字会转换为字符串;
  • 数字减字符串,字符串会转换为数字,如果字符串无法转换为数字(例如"abc"、"JavaScript"),则会转换为 NaN;
  • 字符串减数字,字符串会转换为数字,如果字符串无法转换为数字,则会转换为 NaN;
  • 乘、除运算时,也会先将字符串转换为数字。

2. JS 强制类型转换

与隐式类型转换相反,强制类型转换需要手动进行,在 JavaScript 中,强制类型转换主要是通过调用全局函数来实现的,例如 Number()、Boolean()、parseInt()、parseFloat() 等。

1) 使用 Number() 函数

Number() 函数的语法格式如下:

Number(value);

示例代码如下:

  1. document.write(Number("10.5")); // 输出:10.5
  2. document.write(Number(true)); // 输出:1
  3. document.write(Number(false)); // 输出:0
  4. document.write(Number(null)); // 输出:0

在使用 Number() 函数时,有以下几点需要注意:

  • 如果参数中只包含数字,将转换为十进制数字,忽略前导 0 以及前导空格,如果数字前面有负(-)号,那么-会保留在转换结果中,如果数字前面有加(+)号,转换后会删掉+号;
  • 如果参数中包含有效浮点数字,将转换为对应的浮点数字,忽略前导 0 以及前导空格,同样对于数字前的正负号,会保留负号忽略正号;
  • 如果参数中包含有效的十六进制数字,将转换为对应大小的十进制数字;
  • 如果参数为空字符串,将转换为 0;
  • 如果参数为布尔值,则将 true 转换为 1,将 false 转换为 0;
  • 如果参数为 null,将转换为 0;
  • 如果参数为 undefined,将转换为 NaN;
  • 如果参数为 Date 对象,将转换为从 1970 年 1 月 1 日到执行转换时的毫秒数;
  • 如果参数为函数、包含两个元素以上的数组对象以及除 Date 对象以外的其他对象,将转换为 NaN;
  • 如果在参数前面包含了除空格、+-以外的其他特殊符号或非数字字符,或在参数中间包含了包括空格、+-的特殊符号或非数字字符,将转换为 NaN。

2) 使用 parseInt() 函数

parseInt() 函数的语法格式如下:

parseInt(string, radix);

其中 string 为要转换的值,如果参数不是一个字符串,则会先将其转换为字符串,字符串开头的空白将会忽略;radix 为一个可选参数,表示字符串的基数,取值范围在 2 到 36 之间,例如将 radix 参数设置为 16,则表示将 string 转换为一个十六进制数。

在使用 parseInt() 函数时,有以下几点需要注意:

  • 解析字符串时,会忽略字符串前后的空格,如果字符串第一个字符为负号(-),那么负号会保留在转换结果中,如果字符串第一个字符为正号(+),那么转换后将忽略正号;
  • 如果字符串前面为除空格、正号(+)、负号(-)以外的特殊符号或者除 a~f(或 A~F)之外的非数字字符,那么字符串将不会被解析,返回结果为 NaN;
  • 在字符串中包含空格、小数点(.)等特殊符号或非数字的字符时,解析将在遇到这些字符时停止,并返回已解析的结果;
  • 如果字符串是空字符串,返回结果为 NaN。


示例代码如下:

  1. document.write(parseInt("1101",2)); // 输出:13
  2. document.write(parseInt("a37f",16)); // 输出:41855
  3. document.write(parseInt("123")); // 输出:123
  4. document.write(parseInt(" 123")); // 输出:123

3) 使用 parseFloat() 函数

parseFloat() 函数的语法格式如下:

parseFloat(string);

其中 string 为要被转换为浮点数的值,如果转换失败,则会返回 NaN。

在使用 parseFloat() 函数时,有以下几点需要注意:

  • 如果在解析的过程中遇到了正号(+)、负号(-)、数字(0-9)、小数点(.)、或科学计数法中的指数(e 或 E)以外的字符,则会忽略该字符以及之后的所有字符,并返回解析到的浮点数;
  • 解析过程中若遇到多个小数点,则会在解析到第二个小数点时停止,并返回第二个小数点之前的解析结果;
  • 解析过程中会忽略参数开头或末尾的空白字符;
  • 如果参数的第一个字符不能被解析为数字,则会返回 NaN。


示例代码如下:

  1. document.write(parseFloat("312.456")); // 输出:312.456
  2. document.write(parseFloat("-3.12")); // 输出:-3.12
  3. document.write(parseFloat("+3.12")); // 输出:3.12
  4. document.write(parseFloat(".12")); // 输出:0.12

五、JavaScript 数据类型-深浅拷贝

浅拷贝:

1、将原有的数据赋值过去,只进行一层拷贝,深层次的对象级别的就拷贝引用;

2、原始类型为值传递,对象类型仍为引用传递。;

3、是拷贝引用, 拷贝后的引用都是指向同一个存放数据位置的指针,;

4、拷贝后,修改拷贝后的对象,会影响拷贝前的对象。

function Copy(p){
   var c ={};
   for (var i in p){
      c[i]=p[i]
   }    
   return c;
}

 

 // 浅拷贝 方法:

 

  Object.assign()

  slice()

  concat()

  [... a]

  

//ES6实现浅拷贝的方法
var a = {name:"暖风"}
var b= Object.assign({},a);
b.age = 18;
console.log(a.age);//undefined
----------------------------------
//数组
var a = [1,2,3];
var b = a.slice();
b.push(4);
b//1,2,3,4
a//1,2,3
----------------------------------
var a = [1,2,3];
var b = a.concat();
b.push(4);
b//1,2,3,4
a//1,2,3
----------------------------------
var a = [1,2,3];
var b = [...a]
b//1,2,3,4
a//1,2,3

 

深拷贝

 层级copy,那么我们就用递归来解决这个问题,把父对象中所有属于对象的属性类型都遍历赋给子对象即可。

1 function deepClone(obj){
 2   let objClone =  Array.isArray(obj) ? [] : {};
 3   if (obj && typeof obj === 'object') {
 4     for(let key in obj){
 5       if (obj[key] && typeof obj[key] === 'object'){
 6         objClone[key] = deepClone(obj[key]);
 7       }else{
 8         objClone[key] = obj[key]
 9       }
10     }
11   }
12   return objClone;
13 }

 

 

通过JSON对象实现深拷贝 

 

function deepClone2(obj) {

  let _obj = JSON.stringify(obj),
  return JSON.parse(_obj);
}

注意: 无法实现对象中方法的深拷贝

 

 

 

 

通过Object.assign()拷贝

注意: 当对象只有一级属性为深拷贝;

当对象中有多级属性时,二级属性后就是浅拷贝

 

 

 

 

 

 

二,数组深拷贝的几种方法

1. concat(arr1, arr2,....)

注意:当数组中的元素均为一维是深拷贝

          数组中元素一维以上是值的引用

 

 

 

 

 

2. slice(idx1, idx2)

参数可以省略

1)没有参数是拷贝数组

2)只有一个参数是从该位置起到结束拷贝数组元素

3)两个参数,拷贝从起始位置到结束位置的元素(不包含结束位置的元素:含头不含尾)

注意:当数组中的元素均为一维是深拷贝

          数组中元素一维以上是值的引用

 

posted on 2022-09-19 20:49  MC~大叔  阅读(133)  评论(0)    收藏  举报