【JS笔记】二、javascript中的变量和数据类型 2022-04-11

9-JS的组成和变量

推荐书籍

《Javascript高级程序设计》
《ES6标准入门》 es6.ruanyifeng.com
《Javascript权威指南》
《你不知道的Javascript》上中下

JS做客户端语言

按照相关的JS语法,去操作页面中的元素,有时还要操作浏览器里面的一些功能

  • ECMA Script3/5/6: JS的语法规范(变量、数据类型、操作语句等等)
    如,使用var还是let
  • DOM(document object model):文档对象模型,提供一些JS的属性和方法,用来操作页面中的DOM元素
  • BOM(browser object model):浏览器对象模型,提供一些JS的属性和方法,用来操作浏览器
    把整个浏览器刷新,实现浏览器页面跳转,关掉浏览器当前窗口,关掉窗口前做相关提示,检查当前浏览器版本等

JS中的变量(variable)

变量:可变的量,在编程语言中,变量其实就是一个名字,用来存储和代表不同的东西

10-创建变量的几种方式

创建变量的几种方式

  // ES3、5
  /* var没有变量的作用域,是JS设计早期的一个缺陷,在ES6中改掉了,一般用let定义变量,用const定义常量 */
  var a = 12;
  a=13;
  console.log(a); // =>输出的是a代表的值13

  // ES6
  let b = 100;
  b = 200;

  const c = 1000;
  c = 2000; // =>报错:const创建的变量,存储的值不能被修改,特殊变量,(可以理解为叫做常量)
  本身具体的东西是真正的常量,而起的名字是变量,名字可以指向其他东西;const本身起的是名字

  // 创建函数也相当于在创建变量
  function fn() {} // =>相当于创建一个变量名叫fn,fn存的是整个函数
  // 创建类也相当于创建变量
  class A{} // =>创建一个变量名叫A,存的是整个类
  // ES6的模块导入也可以创建变量
  import B from './B.js'; // =>导入一个模块,创建一个变量名B,存储这个模块的一些信息
  // Symbol创建唯一值
  let n = Symbol(100); 
  let m = Symbol(100); 
  n == m // =>false

11-JS命名规范

JS命名规范

  • 严格区分大小写
let Test = 100;
console.log(test); // =>无法输出
  • 使用数字、字母、下划线、$,数字不能作为开头
let $box; // =>一般用JQuery获取的以$开头
let _box; // =>一般公共变量都是_开头,公共变量/全局变量(约定俗成,非官方规范)
let 1box; // =>不可以,但是可以写box1
  • 使用驼峰命名法:首字母小写,其余每一个有意义单词的首字母都要大写(命名尽可能语义化明细,使用英文单词)
let studentInformation;
let studentInfo;
// 常用的缩写:add/insert/create/new(新增)、update(修改)、delete/del/remove/rm(删除)、sel/select/query/get(查询)、info(信息)...

// 不正确的写法
let xueshengInfo;
let xueshengxinxi;
let xsxx;
  • 不能使用关键字和保留字
当下有特殊含义的是关键字,未来可能会成为关键字的叫做保留字(?)
var let Cindy function …
var var = 10; //=>肯定不行的
// =>代码强迫症(代码洁癖):良好的编程习惯、极客精神

12-JS中的数据类型分类

JS中常用的数据类型

  • 基本数据类型
    • 数字number
      常规数字和NaN
    • 字符串string
      所有用单引号、双引号、反引号(撇)包起来的都是字符串
      反引号包起来的是ES6新加的模板字符串
      如 '{name:10}' 是字符串
    • 布尔boolean
      true/false
    • 空对象指针null
    • 未定义undefined
  • 引用数据类型
    • 对象数据类型object
      • {} 普通对象
      • [] 数组对象
      • /^[+-]?(\d|([1-9]\d+))(.\d+)?$/ 正则对象
      • Math数学函数对象
      • 日期对象
      • ...
    • 函数数据类型function

13-NUMBER数字数据类型详解

number数字类型

包含:常规数字、NaN(不是一个有效数字,但它率属于数字类型)

NaN

not a number:不是一个数,但它率属于数字类型

NaN和任何值(包括自己)都不相等:NaN!=NaN,所以我们不能用相等的方式判断是否为有效数字

isNaN

检测一个值是否为非有效数字,如果不是有效数字返回true,反之是有效数字返回false

// isNaN([val])  []参数描述占位符
console.log(isNaN(10)); // =>false
console.log(isNaN('AA')); // =>true
/*
 *  Number('AA') =>NaN 不能转化为数字
 *  isNaN('AA') =>true
 */
console.log(isNaN('10')); // =>false 是有效数字
/*
 *  Number('10') =>10
 *  isNaN(10) => false
 */

isNaN底层机制:在使用isNaN进行检测的时候,首先会验证检测的值是否为number类型,如果不是,先基于Number()这个方法,把值转换为数字类型,然后再进行检测

把其他类型值转换为数字类型

  • Number([val])

    把字符串转换为数字,只要字符串中包含任意一个非有效数字字符(第一个点除外),结果都是NaN。
    1)空字符串(''里面什么也没有,没空格)会变为数字零;
    2)布尔值true会变成1,false变成0;
    3)空对象指针null会变成0,未定义undefined会变成NaN。
    4)把引用数据类型(包括对象包括函数)转化为数字,是先把它基于toString方法转化为字符串,然后再转换为数字。
    注:
    普通对象、正则对象等结果都是NaN,只有数组的结果才可能是数字。

    一系列转换是走的是浏览器底层渲染规则

    console.log(Number('12.5')); // =>12.5
    console.log(Number('12.5px')); // =>NaN
    console.log(Number('12.5.5')); // =>NaN
    console.log(Number('')); // =>0 
    console.log(Number(true)); // =>1
    
    // 布尔转换为数字
    console.log(Number(false)); // =>0
    console.log(Number(false)); // =>0
    console.log(isNaN(false)); // =>false
    console.log(isNaN(true)); // =>false
    
    // null->0   undefined->NaN
    console.log(Number(null)); //=>0 可以这样理解:空对象指针虽然代表没有,但其实还是有一个东西的
    console.log(Number(undefined)); //=>NaN 可以这样理解:undefined代表未定义,未定义代表没有赋值,没有赋值的值就是没有值,没有值的话肯定是NaN
    
    // 把引用数据类型(包括对象包括函数)转化为数字,是先把他基于toString方法转化为字符串,然后再转换为数字
    console.log(Number({name:'10'})); // =>NaN
    console.log(Number({})); // =>NaN
    // 普通对象 {}或{xxx:'xxx'}.toString() =>"[object object]"
    console.log(Number([])); // =>0
    // [].toString -> ""
    console.log(Number([12])); // =>12
    // [12].toString() -> "12"
    console.log(Number([12,23])); // -> NaN
    // [12,23].toString() -> "12,23"
    
  • parseInt/parseFloat([val],[进制]):也是转换数字的方法,对于字符串来说,它是从左到右依次查找有效数字字符,直到遇到非有效数字字符,停止查找(不管后面是否还有数字,都不再找了),把找到的当做数字返回

    let str = '12.5px';
    console.log(Number(str)); // =>NaN
    console.log(parseInt(str)) // =>12
    console.log(parseFloat(str)) // =>12.5
    console.log(parseFloat('width:12.5px')) // =>NaN
    parseInt("") // =>NaN (因为没有找到有效数字,如果是Number()方法则会返回0)
    

注:
Number(),parseInt/parseFloat()都是把其他类型转换为数字类型:
1)Number()是浏览器内置的一个非常重要的方法,它的一系列的转换规则,走的是浏览器渲染的底层规则,走的是V8引擎最底层的机制;
2)parseInt/parseFloat()是额外提供的一种方法,是处理这种字符串的,如果不是字符串,把它变成字符串,然后再从左到右查找,只能把字符串从左到右查找。

parseFloat(true); // => NaN
parseFloat('true'); // => NaN
  • ==进行比较的时候,可能要出现把其它类型转换为数字
    '10'==10 // =>true
    
  • 数学运算
    加减乘除,除了加可能变成字符串拼接

15-string字符串数据类型详解

string字符串数据类型

所有用单引号、双引号、反引号(撇 ES6模板字符串)包起来的都是字符串

把其它类型值转换为字符串

  • [val].toString()
  • 字符串拼接
console.log(12.toString()) // =>报错 实例概念
let a = 12;
console.log(a.toString()); // => '12'
console.log((NaN).toString()); // => 'NaN'   之前长什么样,外面包一层引号
// null和undefined是禁止直接toString 的
(null).toString() // =>报错 浏览器的保护机制
// 但是和undefined一样转换为字符串的结果就是'null'/'undefined '

[].toString(); // => ""
[12].toString(); // => "12"
[12,23].toString(); // => "12,23"
/^$/.toString(); // => "/^$/"
{{name: 'xxx'}}.toString(); //=>  "[object Object]"
// 普通对象.toString()的结果是"[object Object]"
=>Object.prototype.toString方法不是转换为字符串的,而是用来检测数据类型的

// ============字符串拼接
// 四则运算法则,除加法之外,其余都是数学计算,只有加法可能存在字符串拼接(一旦遇到字符串,则不是数学运算,而是字符串拼接)
console.log('10'+10); //=>1010
console.log('10'-10); //=>0
console.log('10px'-10); //=>NaN
// 10px用Number()转换,NaN-10是NaN
let a = 10 + null + true + [] + undefined + '珠峰' + null + [] +10 + false;
console.log (a);
/*
 * 10 + null -> 10 + 0 -> 10
 * 10 + true -> 10 + 1 -> 11
 * 11 + [] -> 11 + '' -> '11' 空数组变为数字,先要经历变为空字符串,遇到字符串,啥都别想了,直接变为字符串拼接
 * '11'+undefined -> '11undefined'
 * …
 * '11undefined珠峰null10false'
 */

16-boolean布尔数据类型详解

boolean布尔数据类型

只有两个值 true/false

把其它类型值转换为布尔类型

只有0、NaN、''(空字符串)、null、undefined 五个值转换为false,其余都转换为true(而且没有任何的特殊情况)
V8引擎底层机制,在实现数据类型转换的时候,给予的机制就是这样的

  • Boolean([val])
// 只要不在五种情况之中,都为true
console.log(Boolean('')); // =>false
console.log(Boolean(' ')); // =>true 有空格
console.log(Boolean([])); // =>true 五种之外
console.log(Boolean([12])); // =>true
console.log(Boolean(-1)); // =>true
  • !/!!
    !:取反(先转为布尔,然后取反)
    !!:取反再取反,只相当于转换为布尔<=>Boolean
console.log(!1); //=>false
console.log(!!1); //=>true
  • 条件判断
    如果条件只是一个值,不是==/===/!=/>=等这些比较,是要把这个值先转换为布尔类型,然后验证真假
// 能输出 哈哈
if(1) {
    console.log('哈哈');
}
// 能输出 呵呵
if('3px'+3) {
    // => '3px3'
    console.log('呵呵');
}
// 不能输出 嘿嘿
if('3px'-3) {
    // => NaN-3 => NaN
    console.log('嘿嘿');
}

17-null和undefined的区别

null/undefined

null和undefined都代表没有

  • null:意料之中(一般都是开始不知道值,我们手动先设置为null,后期再给予赋值操作)
let num = null; // =>一般最好用null作为初始的空值,因为零不是空值,它在栈内存中有自己的存储空间(占了位置)
let num = 0; // =>有空间来存储,相对消耗一丢丢丢丢性能
...
num = 12;
  • undefined:意料之外(不是我能决定的)
let num; // =>创建一个变量没有赋值,默认值是undefined
...
num = 12;

18-对象数据类型的基本结构和操作

object对象数据类型-普通对象

{[key]:[value],...}
任何一个对象都是由零到多组键值对(属性名:属性值)组成的,每组键值对或每组属性名和属性值之间用逗号分隔;
属性名不能重复;
属性名只能是数字或字符串;
属性名是数字或者字符串格式的,不写单引号双引号默认也是字符串格式的,加上也不会有错误,默认不写

let person = {
    name: '易烊千玺',
    age: 40,
    height: '185cm',
    weight: '80kg',
    1: 100
};
获取属性名对应的属性值(查)
  • 对象.属性名
    属性名是字符串的情况可用
  • 对象[属性名]
    属性名是数字或者字符串格式(带引号)的
console.log(person.name);
console.log(person['age']); // 不能直接写age,属性名是个字符串
或console.log(person["age"]); 
// =>如果当前属性名不存在,默认的属性值是undefined
console.log(person.sex); // =>undefined
console.log(person[1]);
// =>如果属性名是数字,则不能使用点的方式获取属性值
// console.log(person.1); // =>SyntaxError:语法错误
设置属性名属性值(改、增)
person.GF = '园园';
console.log(person['GF']); // =>园园
// =>属性名不能重复,如果属性名已经存在,不属于新增属于修改属性值
person.name = '李易峰';
console.log(person['name']); // =>李易峰
删除属性(删)
  • 真删除:把属性彻底干掉
  • 假删除:属性还在,值为空
// 假删除
person.weight = null;
console.log(person);
/*
 * 1: 100
 * age: 40
 * height: "185cm"
 * name: "易烊千玺"
 * weight: null
 */
// 真删除
delete person[1];
console.log(person);
/*
 * age: 40
 * height: "185cm"
 * name: "易烊千玺"
 * weight: null
 */

19-数组的基本结构(特殊对象类型)

对象数据类型object-数组对象

数组是特殊的对象数据类型
1)我们中括号中设置的是属性值,它的属性名是默认生成的数字,从0开始递增,而且这个数字代表每一项的位置,我们把其称为“索引”=>从零开始连续递增,代表每一项位置的数字属性名
2)天生默认一个属性名length,存储数组的长度

let ary = [12,'哈哈',true,13];

// 任何一个对象都必须有键值对(看到的是属性值:属性名),数组也是对象,它肯定也是由属性名属性值组成的,只不过比较特殊,写的时候不需要写属性名,从0开始逐级递增,既是属性名也是索引
console.log(ary);
/* [12, "哈哈", true, 13]
 * 0: 12
 * 1: "哈哈"
 * 2: true
 * 3: 13
 * length: 4
 */

// 默认一个属性名length
console.log(ary.length); // =>4
console.log(ary['length']); // =>4 需要写单引号 字符串格式

/* 数组虽然是特殊对象,看起来不一样,本质仍是对象,只要是对象,就可以使用上面的对象操作法则 */

// 输出哈哈 哈哈索引是1
console.log(ary[1]); // =>哈哈 属性名是数字只能用中括号方式
// 第一项索引是0 最后一项索引ary.length-1
console.log(ary[0]); //=>12
console.log(ary[ary.length-1]); //=>13

// 向数组末尾追加内容
ary[ary.length] = 100;
console.log(ary);

20-数据类型的区别(堆栈底层机制)

let a = 12;
let b = a;
b = 13;
console.log(a); // =>12

let n = {
    name: '珠峰'
};
let m = n;
m.name = '培训';
console.log(n.name); // =>培训

浏览器想要执行JS代码:
环境、人
1)从电脑内存当中分配出一块内存,用来执行代码(栈内存=>Stack)
电脑买高内存的原因之一
2)分配一个主线程用来自上而下执行JS代码

上面用来存东西,下面用来执行代码

image.png

简单的基本类型值存储

image.png
  • let a =12;
    1.创建变量a,放到当前栈内存变量存储区域中
    2.创建一个值12,把它存储到当前栈内存值区域中(简单的基本类型值是这样存储的,复杂的引用类型值不是这样做的)
    3.=为赋值,其实赋值是让变量和值相互关联的过程
  • let b = a;
    上述第1条第3条
  • b = 12;
    上述第2条第3条

复杂的引用类型值存储

image.png

name属性名已存在,属于改

复杂值(引用类型值)的存储,又分成了三个步骤:
1.在内存中分配出一块新内存,用来存储引用类型值(堆内存=>heap ) =>内存有一个16进制地址
2.把对象中的键值对(属性名:属性值)依次存储到堆内存中
3.把堆内存地址和变量关联起来
注意:本质仍是遵照创建变量、创建值、关联,三个步骤(见下面题)

基本数据类型、引用数据类型存储对比

基本类型∶按值操作(直接操作的是值),所以也叫作值类型
引用类型∶操作的是堆内存的地址(按引用地址操作的),所以叫作引用数据类型

  • 基本类型值
    因为结构简单,直接存储在栈内存的值存储空间当中,所有的操作是直接操作这个值
  • 引用类型值
    结构复杂,不能直接存储在值存储空间中,必须开一个堆内存,将内容存在堆里面,然后操作的都是堆内存的引用地址,可能会导致两个变量用的都是同一个地址,管控的是同一个堆,其中一个变量把堆里的东西改了,另外一个变量受影响

21-堆栈内存课程练习题

image.png

最底层的机制
1、创建变量(先处理等号左边)
2、创建值(再处理等号右边)
3、关联,关联前两者无关(js的特点,不同于某些语言,不是拷贝,是关联)
x = [30,40]
创建过变量x了不用管,创建新的值-新数组-新空间,关联,x只能关联一个

22-阿里的一道引发血案的面试题

// 写出下面结果输出的答案
let a = {
    n:1
};
let b = a;
a.x = a = {
    n:2
};
console.log(a.x);
console.log(b);

image.png

关于连等赋值:
a=b=3
从左到右
a=3
b=3
3都是一个值3,先让a和它关联,再让b和它关联,连等赋值,是让每一个变量都和这个值关联
a.x = a = {n:2}
1、先处理等号左边的,看是不是要创建变量:
a.x 不是创建变量,是给a设置一个属性x
a变量已存在,不用创建
2、再处理等号右边的,看要不要创建值:
等号右边是个值,需要创建值,值存储空间/开个堆
等号右边是引用类型,开个堆,AAAFFF111
3、关联
先让a.x和值关联,之前没有x这个属性名,新增,x和AAAFFF111关联
再让a和AAAFFF111关联

// 变形
let a = {
    n:1
};
let b = a;
a.x = b;

无限次嵌套,堆的嵌套,内存嵌套,导致内存无限溢出


image.png

23-数据类型检测

JS中的数据类型检测

  • typeof [val]:用来检测数据类型的运算符
  • instanceof:用来检测当前实例是否率属于某个类
  • constructor:基于构造函数检测数据类型(也是基于类的方式)
  • Object.prototype.toString.call():检测数据类型最好的办法

注:
1、前三个都有不足,第四个没有,做轻量级检测的时候,前三个能处理某些事,就不用第四个了
2、
typeof ,运算符,不是方法;
instanceof,运算符,不是方法;
constructor,属性,不是方法,但是constructor构造函数也可以当作方法;
运算符如 1 + 1中的+
方法如sum()
所以typeof运算符后面直接加value值,不加()执行

typeof

基于typeof检测出来的结果
1、首先是一个字符串
2、字符串中包含对应的类型
局限性
1、typeof null => "object" 但是null并不是对象
2、基于typeof无法细分出当前值是普通对象还是数组对象等,因为只要是对象数据类型,返回的结果都是"object"

image.png

image.png

console.log(typeof 1); // =>number (控制台打出来的是黑色字体的number,默认省略"",但控制台其实是有颜色区分的,黑色代表是字符串,蓝色是数字,直接在控制台typeof 1更加明显,是"number")
let a = NaN;
console.log(typeof a); //=>'number'
console.log(1);
console.log(typeof typeof typeof []); 
// 从和值最近的开始,先靠近值的先运算,从右到左
// =>typeof [] => "object"
// =>typeof "object" => "string"
// 因为typeof检测的结果是字符串,只要两个及两个以上同时检测,最后结果必然是"string"
答案是"string" 加双引号或单引号,注意细节

你可能感兴趣的:(【JS笔记】二、javascript中的变量和数据类型 2022-04-11)