js基本类型

参考:http://blog.csdn.net/wkyseo/article/details/51484506
参考: https://www.cnblogs.com/phillyx/p/5603738.html
参考:http://blog.csdn.net/liangshiquan1/article/details/49909825
javascript的数据类型可以分为两种:原始类型和引用类型

原始类型也称为基本类型或简单类型,因为其占据空间固定,是简单的数据段,为了便于提升变量查询速度,将其存储在栈(stack)中(按值访问)。
  
引用类型由于其值的大小会改变,所以不能将其存放在栈中,否则会降低变量查询速度,因此其存储在堆(heap)中,存储在变量处的值是一个指针,指向存储对象的内存处(按址访问)

[注意]对于引用类型的值,可以为其添加属性和方法,也可以改变和删除其属性和方法;但基本类型不可以添加属性和方法

基本数据类型: Undefined、Null、String、Number、Boolean。(按值访问,可操作保存在变量中的实际的值。基本类型值指的是简单的数据段。)

引用类型: object、Array、RegExp、Date、Function(当复制保存着对象的某个变量时,操作的是对象的引用,但在为对象添加属性时,操作的是实际的对象。引用类型值指那些可能为多个值构成的对象。)

区别

  1. 基本类型值不允许添加属性和方法,引用类型可以
//基本类型
let str = 'bbj';
str.age = 10;
str.say = function () {
    console.log(112);
};
console.log(str);
console.log(str.age);
console.log(str.say);

//bbj
//undefined
//undefined
//引用类型
let str1 = new Object();
str1.age = 18;
str1.say1 = function () {
    console.log(this.age);
}

console.log(str1.age);
str1.say1();

//18
//18

2. 在复制变量值时,基本类型会在变量对象上创建一个新值,再复制给新变量。此后,两个变量的任何操作都不会影响到对方;而引用类型是将存储在变量对象的值复制一份给新变量,但是两个变量的值都指向存储在堆中的一个对象,也就是说,其实他们引用了同一个对象,改变其中一个变量就会影响到另一个变量。

//基本类型
let str = 'bbj';
let str1 = str;
str = 'ddj';
console.log(str);
console.log(str1);

//ddj
//bbj
//引用类型

//1.对其中一个变量直接赋值不会影响到另一个变量(并未操作引用的对象)
let str = ['bbj', 'ddj'];
let str1 = str;
str = ['bbj', 'ddj', 'ggj'];
console.log(str);
console.log(str1);

// [ 'bbj', 'ddj', 'ggj' ]
// [ 'bbj', 'ddj' ]

//2.使用push(操作了引用的对象)
let str = ['bbj', 'ddj'];
let str1 = str;
str.push('aaj');
console.log(str);
console.log(str1);

//[ 'bbj', 'ddj', 'aaj' ]
//[ 'bbj', 'ddj', 'aaj' ]

//3.应该是str赋值的时候相当于重新创建变量
let str = ['bbj', 'ddj'];
let str1 = str;
str = ['bbj', 'ddj', 'ggj'];
str.push('aaj');
console.log(str);
console.log(str1);

//[ 'bbj', 'ddj', 'ggj', 'aaj' ]
//[ 'bbj', 'ddj' ]

3.参数的传递

ECMAScript所有的函数的参数都是按值传递的。函数外部的值赋值给函数内部的参数,与一个变量复制到另一个变量一样。基本类型值的传递和基本类型一样,引用类型的传递和引用类型的复制一样。

let num = 10;
function add (num) {
    num += 10;
    return num; 
}
console.log(num);
console.log(add(num));

// 10
// 20
let person = {};
function setName (obj) {
    obj.name = 'bbj';
    obj = new Object();
    obj.name = 'ddj';
    return obj;
}
setName(person);
console.log(person.name);
console.log(setName(person).name);

// bbj
// ddj

即使在函数内部修改了参数的值,但原始的引用(person对象,存储在堆上)仍保持不变。具体传递的obj不是指针而是指针引用的对象(副本copy)。实际上,当在函数内部重写obj时,这个变量的引用的就是一个局部对象了,而这个局部对象会在函数执行完毕后立即被销毁。
扩展:值传递与引用传递

值传递和引用传递,属于函数调用时参数的求值策略(Evaluation Strategy),这是对调用函数时,求值和传值的方式的描述,而非传递的内容的类型(内容指:是值类型还是引用类型,是值还是指针)。值类型/引用类型,是用于区分两种内存分配方式,值类型在调用栈上分配,引用类型在堆上分配。一个描述内存分配方式,一个描述参数求值策略,两者之间无任何依赖或约束关系。

区别值传递引用传递
根本区别会创建副本(copy)不创建副本
所以函数中无法改变原始对象函数中可以改变原始对象

对于值传递,无论是值类型还是引用类型,都会在调用栈上创建一个副本,不同是,对于值类型而言,这个副本就是整个原始值的复制。而对于引用类型而言,由于引用类型的实例在堆中,在栈上只有它的一个引用(一般情况下是指针),其副本也只是这个引用的复制,而不是整个原始对象的复制。

这便引出了值类型和引用类型(这不是在说值传递)的最大区别:值类型用做参数会被复制,但是很多人误以为这个区别是值类型的特性。其实这是值传递带来的效果,和值类型本身没有关系。只是最终结果是这样。

4.两种类型的比较

let a = '123';
let b = '123';
console.log(a == b);
console.log(a === b);

// true
// true

let aa = {};
let bb = {};
console.log(aa == bb);
console.log(aa === bb);

// false
// false

Undefined

Undefined类型只有一个值,即特殊的undefined。在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined。不过,一般建议尽量给变量初始化,但是在早期的js版本中是没有规定undefined这个值的,所以在有些框架中为了兼容旧版浏览器,会给window对象添加undefined值。

出现场景

  [1]已声明未赋值的变量
  [2]获取对象不存在的属性
  [3]无返回值的函数的执行结果
  [4]函数的参数没有传入
  [5]void(expression)

Null

Null类型只有一个值,就是null。逻辑角度看,null值表示一个空对象指针,而这也正是使用typeof操作符检测null时会返回object的原因。

如果定义的变量将用于保存对象,最好将该变量初始化为null。这样一来,只要直接检测null值就可以知道相应的变量是否已经保存了一个对象的引用了。实际上undefined值是派生自null值的,所以undefined == null

尽管null和undefined有这样的关系,但它们的用途完全不同。无论在什么情况下都没有必要把一个变量的值显式地设置为undefined,可是同样的规则对null却不适用。换句话说,只要意在保存对象的变量还没有真正保存对象,就应该明确地让该变量保存null值。这样做不仅可以体现null作为空对象指针的惯例,而且也有助于进一步区分null和undefined。

[注意]null是空对象指针,而[]是空数组,{}是空对象,三者不相同

出现场景
  对象不存在时

Boolean

该类型只有两个字面值:true和false。这两个值与数字值不是一回事,因此true不一定等于1,而false也不一定等于0。

虽然Boolean类型的字面值只有两个,但JavaScript中所有类型的值都有与这两个Boolean值等价的值。要将一个值转换为其对应的Boolean值,可以调用类型转换函数Boolean()

各种数据类型及其对象的转换规则

数据类型转换为true的值转换为false的值
Booleantruefalse
String任何非空的字符串“”(空字符串)
Number任何非0数值(包括无穷大)0和NAN
Object任何对象null
Undefined不适用undefined

!!一般用来将后面的表达式强制转换为布尔类型的数据(boolean),也就是只能是true或者false;

两个感叹号的作用就在于,如果明确设置了变量的值(非null/undifined/0/”“等值),结果就会根据变量的实际值来返回,如果没有设置,结果就会返回false。

出现场景
  [1]条件语句导致系统执行的隐士类型转换
  [2]字面量或变量定义

Number

javascript只有一种数字类型,既可以表示32位的整数,还可以表示64位的浮点数

这种类型用来表示整数和浮点数值,还有一种特殊的数值,即NaN(非数值 Not a Number)。这个数值用于表示一个本来要返回数值的操作数未返回数值的情况(这样就不会抛出错误了)。例如,在其他编程语言中,任何数值除以0都会导致错误,从而停止代码执行。但在JavaScript中,任何数值除以0会返回NaN,因此不会影响其他代码的执行。

NaN本身有两个非同寻常的特点。首先,任何涉及NaN的操作(例如NaN/10)都会返回NaN,这个特点在多步计算中有可能导致问题。其次,NaN与任何值都不相等,包括NaN本身

isNaN()函数,用于判断是否是一个非数字类型。如果传入的参数是一个非数字类型,那么返回true;否则返回false;

isNaN()函数,传入一个参数,函数会先将参数转换为数值。

如果参数类型为对象类型,会先调用对象的valueOf()方法, 再确定该方法返回的值是否可以转换为数值类型。如果不能,再调用对象的toString()方法,再确定返回值。

String

string类型有些特殊,因为字符串具有可变的大小,所以显然它不能被直接存储在具有固定大小的变量中。由于效率的原因,我们希望JS只复制对字符串的引用,而不是字符串的内容。但是另一方面,字符串在许多方面都和基本类型的表现相似,而字符串是不可变的这一事实(即没法改变一个字符串值的内容),因此可以将字符串看成行为与基本类型相似的不可变引用类型

String类型是javascript中唯一没有固定大小的原始类型

字符串的值是不可变的。要改变一个字符串的值,首先要销毁原来的字符串,再用另一个包含新值的字符串去填充该字符串。

Boolean、Number、String 这三个是Javascript中的基本包装类型,也就是这三个其实是一个构造函数,他们是Function的实例,是引用类型,至于这里的String与以上说的String是同名,是因为其实上文说的String是指字符串,这里的String指的是String这个构造函数,上面那么写,是为了更好的理解,因为Javascript是松散类型的。

其实string只是String的一个实例,类似于C#中的String,和string.

注意,typeof 变量 如果值是”string” 的话,也就是这个变量是字符串,在Javascript中,字符串是基本类型,而在C#或Java中,字符串是引用类型,但是Javascript中的String是引用类型,因为它是Javascript中定义好的基本包装类型,在C#中,String跟string其实是一样的。

JavaScript三个基本数据类型都有相应的对象类;分别为Sring,Number,Boolean类;
JavaScript可以灵活的将一种类型的值转换为另一种类型;
当我们在对象环境中使用字符串时,即当我们试图访问这个字符串的属性或方法时;
JavaScript会为这个字符串值内部地创建一个String包装对象;
String对象会暂时代替原始的字符串值,完成我们的访问;
这个被内部创建的String对象是瞬间存在的,它的作用是使我们可以正常访问属性和方法;
String对象在使用过后会被系统丢弃掉;
而原始值并不会被改变;

以上同样适用于数字和布尔值类型;

使用Object()函数,任何数字、字符串、布尔值都可以转换为它对应的包装对象;

引用类型

引用类型是一种用于将数据和功能组织在一起的数据结构(也常被成为类),引用类型的值(对象)是引用类型的一个实例。
但是js中没有类的概念,因此引用类型也可以被称为对象定义,因为他们描述的是一类对象所具有的属性和方法。
对象是某个特定引用类型的实例,新对象是使用new操作符后跟一个构造函数来创建的,构造函数本身就是一个函数,只不过该函数是出于创建新对象的目的而定义的。
对象是某个特定引用类型的实例,新对象是使用new操作符后跟一个构造函数来创建的,构造函数本身就是一个函数,只不过该函数是出于创建新对象的目的而定义的。
ECMAScript提供了很多原生引用类型(如:Object),以便开发人员用以实现常见的计算任务

Object

我们看到的大部分引用类型都是Object类型的实例,Object的实例本身不具备很多功能,单对于在应用程序中存储和传输数据而言,是非常理想的选择。

创建Object类型

  • 直接new
    语法: new操作符跟Obeject构造函数
let obj = new Object();
  • 对象字面量
    语法:花括号,里面的属性用键值对形式,每个属性用逗号隔开,最后一个属性不用逗号。
let person = {
    name: 'bbj',
    age: 18,
    sex: 'n'
}

访问属性

  • 通过点表示法
let person = new Object();
person.name = 'bbj';
  • 方括号
var o = new Object();
o.age = 22;
console.log(o["age"]);  //22
//方括号可以用变量来访问属性
var otherAge = "age";
console.log(o[otherAge]);  //22

Array

创建数组

  • new Array()
//创建一个空数组
var arr1 = new Array();
//创建一个长度为10的空数组,
var arr2 = new Array(10);
//创建一个包含一个字符串good的数组
var arr3 = new Array("good");
  • 数组字面量
var cars = ["BMW","BenZ","Ferrari"];
//注意,创建数组不要留空项。浏览器兼容性问题,IE8或以前版本会认为这是有3项,下面这种不建议。
let nums = [1,2,];
  • 访问数组
cars[0];
//下标访问

Date

创建对象

new Date();

RegExg

ES通过RegExg类型来支持正则表达式,语法:var e = /pattern/flag
其中pattern表示正则表达式,flag表示标识,标识可以一个或多个

flags说明
g全局模式,该模式应用于所有的字符串
i不区分大小写模式,确定匹配项时忽略模式与字符串的大小写
m多行模式,一行文本到尾后还会查下一行的字符串,如果有的话

创建RegExg对象

  • 字面量方式
var p1 = /at/g;  //匹配所有"at" 的实例
var p2 = /[bc]at/i  //匹配第一个bat或cat,不区分大小写
var p3 = /.at/gi  //匹配所有at结尾的组合,不区分大小写

//正则中如果想在字符中包含元字符需要对其进行转义
//这里和p3不同的是对.这个元字符进行转义,用\符号转义
var p4 = /\.at/gi;  //这里的意思是匹配所有的".at",不区分大小写。
  • 使用new RegExg构造函数
//RegExg() 接受两个参数,一个是正则表达式,一个是标志
var pattern1 = new RegExg("at","gi");
//pattern1和pattern2完全等价
var pattern2 = /at/gi;

Function

定义函数

//1.函数声明
function getName(){
    var name = 'ry-yuan';
    return name;
}
//2.函数表达式
var getAge = function(){
    var age = 100;
    return age;
}
//3.使用Function构造函数,前面1-n个是参数,最后一个参数的是函数体,这种不推荐使用。
var sum = new Function("num","return num");
  • 函数声明和函数表达式的区别
//函数声明,我们先运行sayHello,但是不会报错,因为函数声明已经在解析时被提到顶部
sayHello();  //hello everyone
function sayHello(){
    console.log("hello everyone");
}


//函数表达式,用var定义函数名.用函数表达式,不会提升,所以先运行sayBye就会找不到函数体
sayBey();  //报错 TypeError: sayBye is not a function
var sayBye = function(){
    console.log("bye bye");
}
  • 函数名是指向函数的指针

一个函数在js种就是一个Function的实例,函数名就是对实例的引用,一个指针,前面的对象中也有说过。那么一个函数就可以有多个函数名了。

//定义一个函数,函数名是sum
var sum = funtion(num1,num2){
    return num1+num2;
}

//讲sum复制给otherSum,那么otherSum和sum都指向同一个function对象
otherSum = sum;

otherSum(100,420);  //520
sum(1300+14); //1314

//对sum设置为null,sum变量就不在指向function对象
sum  = null;

//otherSum依然能够使用
otherSum(1,9); //10
  • 函数没有重载

上面说了,函数名只是函数的指针,函数名是变量一样,重复复制就会覆盖原来的。
在java语言来说,有不同的参数数量也称为重载,但是js中没这种操作

//函数声明,fn为函数名
function fn(num1, num2){
    return num1+ num2;
}
//再来函数声明,fn为函数名
function fn(num){
    return num;
}

//fn只会指向最后一次声明的函数
fn(1,43);  //1
  • 函数像值一样传递

因为函数名本来就是一个变量,所以函数也可以像值一样被传递

//声明一个函数fn1,它可以接受两个参数,一个是函数,一个是值
function fn1(fn,value){
    return (fn(value));
}
//声明一个fn2,接受一个参数
function fn2(val){
    console.log(val+1000);
}
//fn2当成参数传递给fn1
fn1(fn2,24);  //1024
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值