一次与 JavaScript 的深入交流 💯

本篇文章学习: 菜鸟教程、尚硅谷

JavaScript 快速入门手册 💯

前言:

本人目前算是一个Java程序员,但是目前环境.... ε=(´ο`*))) 一言难尽啊,blog也好久好久没有更新了,一部分工作原因吧(外包真的狗都不干了).....,为了以后多一口饭还是要多学习呐;

JS 依稀记得记忆中学习过 最初天真的我甚至认为会一点前端、Java 可以算是一个小全栈了吧,结果现在前端工程化之后,回头看前端的代码结构甚至都怀疑自己是不是会前端;

VUE、Element... 还记的第一家公司,有一段时间比较缺人,前端没人搞,领导问我会吗? :会前端吗? :了解过VUE语法 (现在想想真是年少轻狂) 结果一个功能硬是憋了两天,终于搞出来了...... 那时候就想要了解前端,

HTML+CSS+JS 远古时代已经结束了,听朋友说前端变换挺大了,而且更新飞快,而最近又在传言前端已死.... Java已死、后端已死。互联网真的烂透了😭

未来计划: 学习一下烤面筋的原理💯

JavaScript的介绍,就不介绍了....,这里仅仅介绍JS的语法,暂时通过node环境去测试代码,所以这里仅仅介绍JS基础语法: 一定程度的方便,还有就是新公司的项目开发架构是:node后端,后面会扩展:前端、node学习笔记。

简介

JavaScript是一门解释型语言,所谓解释型指语言是指不需要被编译为机器码在执行,而是直接浏览器|node中执行

简介

JavaScript是一门解释型语言,所谓解释型指语言是指不需要被编译为机器码在执行,而是直接浏览器|node中执行。

JavaScript 组成:

ECMAScript 规范:

  • ECMAScript是一个规定了脚本语言,属性方法对象的标准,在使用web客户端编写脚本语言时要遵循:ECMAScript 标准;
  • ECMAScript是一种开放的,被国际上广为接收的,标准的脚本语言规范,它不与任何具体的浏览器绑定
  • 主要描述:语法,变量,数据类型,运算符,逻辑控控制语句,关键字保留字,对象;

浏览器对象模型 (Browser Object Model BOM )

  • 提供了内容与浏览器窗口进行交互的对象,实现与 HTML交互
  • 网上常见的 弹出窗口,前进后退等功能都是浏览器对象控制的;

文档对象模型 (Document Object Model DOM) :

  • HTML文档对象模型(HTML DOM)定义的一套标准方法 , 用来访问和操作HTML文档。
  • 网上商城常见的随鼠标移动显示大图片,弹出小提示都是文档对象的功劳

基础语法:

JavaScript 虽说和 Java没有任何关系,如果说有关系,就是语法有一些类似,就比如说注释,逻辑运算符...

注释:

arduino 复制代码
 //单行注释
 ​
 /**
  * 多行注释
  * 多行注释
  */

JavaScript变量

在这里插入代码片变量字面量

  • 变量: 的作用是给某一个值或对象标注名称,程序中有一个值123,这个值我们是需要反复使用的,这个时候 我们最好将123这个值赋值给一个变量。
  • 字面量: 字面量实际上就是一些固定的值,比如:1、2、3、true、flase、"hello"等,字面量不可以改变的,不是很方便使用。

变量的声明:

csharp 复制代码
 //使用var关键字声明一个变量
 var 变量名;
 ​
 //可以使用,逗号进行同时声明多个变量;
 var 变量名0,变量名1,变量名2;

变量的赋值:

ini 复制代码
 //使用=为变量赋值
 var 变量名 = 123;
 //逗号声明多个变量,但是赋值需要给每一个变量进行赋值;
 var 变量名0='a',变量名1='b',变量名2='c';

JS中变量名规范标识符

所谓标识符,就是指给变量函数属性函数 参数起名字,标识符可以是按照下列格式规则组合起来的一或多个字符:

  • 第一个字符必须是一个字母、下划线( _ )或一个美元符号( $ )。
  • 其它字符可以是字母、下划线、美元符号或数字。
  • 按照惯例,ECMAScript 标识符采用驼峰命名法。
  • 标识符不能是关键字和保留字符

关键字:

保留字符:

其它不建议使用的标识符:

基本数据类型

  • JS的基本数据类型主要有五大类: String字符串、Number数值型、Boolean布尔型、Undefined、Null。
  • 这5种之外的类型都称为Object,引用类型,所以总的来看JavaScript中共有六种数据类型

typeof 运算符:

  • js是一门弱语言 ,我们在使用的时候无法得知变量的类型,js在运行时会自动判断,但我们也想知道变量类型,可以使用:typeof typeof(x);
  • typeof | typeof(x): 第一种是对变量做运算,第二种可以对表达式做运算;运算符|函数,返回值就是String类型
  • typeof 的局限性: typeof 的局限性,在于无法精确判断出 null、数组、对象、正则 的类型

注意: JavaScirpt 区分大小写,所以typeof 不要写成 Typeof ,语法不成立会报错;

js 复制代码
 //typeof  运算符
 console.log(typeof "wsm");  
 console.log(typeof 123);
 console.log(typeof true);
 console.log(typeof undefined);
 console.log(typeof null); 
 ​
 //typeof(表达式); 
 console.log(typeof("w"+"s"+"m"+123));  
 console.log(typeof(1+3));
 console.log(typeof(1==1));
 var a;
 console.log(typeof(a));
 a = null;
 console.log(typeof(null));  
 //运行结果: string number boolean undefined object

String 字符串:

js 复制代码
 //String用于表示一个字符序列使用 '' 或 "" 包括起来;
 var q = '123';      
 var qq = "123";
 console.log(q+"类型是:"+typeof q);
 console.log(qq+"类型是:"+typeof qq);

转义字符: 字符串中对于一些特殊符号,的使用和Java类似

| 转义字符 | 含义 | 转义字符 | 含义 | 转义字符 | 含义 |
|------|----|------|------------|-------|-------|--------|
| \n | 换行 | \t | 制表符,相当于tab | \b | 空格 |
| \r | 回车 | \ | 斜杠 \ | ' 或 " | 单引号 ' | 双引号 '' |

md的语法对 `` 有影响所以查看文档时候需要注意;

类型转换为String :

将其它数值转换为字符串有三种方式:toString()、String()、 拼串

js 复制代码
 /**toString();
  * 调用被转换数据类型的toString()方法,该方法不会影响到原变量,它会将转换的结果返回;
  * 注意:null和undefined这两个值没有toString()方法,如果调用它们的方法,会报错;
  */
 var q = 123;
 console.log("number调用toString()方法"+typeof q.toString()+": "+q.toString());
 ​
 /**String();
  * 将被转换的数据作为参数传递给函数,
  * 对于Number和Boolean实际上就是调用的toString()方法;
  * 但是对于null和undefined,就不会调用toString()方法,它会将 null 直接转换为 "null",将 undefined 直接转换为 "undefined"
  */
 var q = 123;
 console.log("使用String(q)方法"+typeof String(q)+": "+String(q));
 var qq = null;
 console.log("使用String(qq)方法"+typeof String(qq)+": "+String(qq));
 var qqq = undefined;
 console.log("使用String(qqq)方法"+typeof String(qqq)+": "+String(qqq));
 ​
 /** +"" 拼接方式,为任意的数据类型 +""   和Java很类似,""+拼任何类型结果都是String */
 var q = 123
 console.log("使用""+ 拼接方式"+typeof(""+q)+": "+typeof(""+q));     //因为双引号在JS是特殊符号所以 "" 表示;

cmd 输出

sh 复制代码
 number调用toString()方法string: 123
 使用String(q)方法string: 123
 使用String(qq)方法string: null
 使用String(qqq)方法string: undefined
 使用""+ 拼接方式string: string

Number数值类型:

js 复制代码
 //Number类型用来表示 浮点数(小数)|整数|正负数;
 //Number表示的数字大小是有限的,如果超过了这个范围,则会返回 ±Infinity
 //  最大值:+1.7976931348623157e+308
 //  最小值:-1.7976931348623157e+308
 //  0以上的最小值:5e-324
 ​
 var w = 123;
 var ww = 1.23;
 var www = -1.23;
 console.log(w+"类型是:"+typeof w);
 console.log(ww+"类型是:"+typeof ww);
 console.log(www+"类型是:"+typeof www);
 console.log("Infinity的类型也是number:"+typeof Infinity);
类型转换为Number:

非数值转换为数值:Number()、parseInt() 和parseFloat();

Number()可以用来转换任意类型的数据,后两者parseInt(); parseFloat(); 只能用于转换字符串;

  • 注意: 如果对非String使用parseInt()或parseFloat(),它会先将其转换为String然后在操作
js 复制代码
 /**使用Number()函数
  * 字符串 --> 数字
  *      如果是纯数字的字符串,则直接将其转换为数字
  *      如果字符串中有非数字的内容,则转换为NaN
  *      如果字符串是一个空串或者是一个全是空格的字符串,则转换为0
  * 布尔 --> 数字
  *      true 转成 1   false 转成 0
  * null 转成 0
  * undefined 转成 NaN
  */
 //字符串 --> 数字
 var w = Number("");
  console.log(typeof w+": "+w);
 var ww = Number("123");
 console.log(typeof ww+": "+ww);
 var www = Number("123s");
 console.log(typeof www+": "+www);                               //如果不是纯数值则返回NaN
 //布尔 --> 数字
 var wtrue = Number(true);
 console.log(typeof wtrue+": "+wtrue);
 var wfalse = Number(false);
 console.log(typeof wfalse+": "+wfalse);
 //null 转成 0
 var wnull = Number(null);
 console.log(typeof wnull+": "+wnull);
 //undefined 转成 NaN
 var wundefined = Number(undefined);
 console.log(typeof wundefined+": "+wundefined);
 //NaN也是一种数值类型?
 console.log("NaN也是一种数值类型?"+typeof NaN+",看样子是的。");
 ​
 console.log("========================================================================================");
 console.log("parseInt(); parseFloat(); 二者功能类似;");
 var pars =  parseInt("s12s");       
 var pars1 =  parseInt("12s");
 var pars2 =  parseInt("12.2");
 var pars3 =  parseInt("12.6");
 console.log("如果转换字符串非数值类型会返回NAN:"+pars);  
 console.log("paresInt()函数类似于一个个字符判断,不符合的直接截断:"+pars1);      
 console.log("12.2中.符号不是数值,则截断结果:"+pars2);
 console.log("同上:"+pars3);
 //parseFloat() 规则和pareseInt()类似不同的是可以获取浮点值;
 var pars4 =  parseFloat("12.2");
 var pars5 =  parseFloat("12.6");
 console.log(pars4);
 console.log(pars5);
 console.log("paresInt|paresFloat并不会四舍五入");

cmd 输出

sh 复制代码
 number: 0
 number: 123
 number: NaN
 number: 1
 number: 0
 number: 0
 number: NaN
 NaN也是一种数值类型?number,看样子是的。
 ========================================================================================
 parseInt(); parseFloat(); 二者功能类似;
 如果转换字符串非数值类型会返回NAN:NaN
 paresInt()函数类似于一个个字符判断,不符合的直接截断:12
 12.2中.符号不是数值,则截断结果:12
 paresInt并不会四舍五入:12
 12.2
 12.6
 paresInt|paresFloat并不会四舍五入

Boolean布尔类型:

js 复制代码
 //布尔型也被称为逻辑值类型或者真假值类型
 //布尔型只能够取真(true)和假(false)两种数值
 var e = true;
 var ee = false;
类型转换为Boolean:
js 复制代码
 //其它的数据类型转换为Boolean,只能使用Boolean()函数
 //数字 ---> 布尔: 除了0和NaN,其余的都是true
 var b = Boolean(0);
 var bb = Boolean(NaN);
 var bbb = Boolean(123);
 console.log(typeof(b)+": "+b);
 console.log(typeof(bb)+": "+bb);
 console.log(typeof(bbb)+": "+bbb);
 ​
 //字符串 ---> 布尔:除了空串,其余的都是true
 var bs = Boolean("");
 var bbs = Boolean(" ");
 var bbbs = Boolean("123");
 console.log(typeof(bs)+": "+bs);
 console.log(typeof(bbs)+": "+bbs);          //加了空格就不是空字符串
 console.log(typeof(bbbs)+": "+bbbs);
 ​
 //null和undefined都会转换为false,对象会转换为true
 var bo = Boolean({});                       //JS中的对象结构,最基本的;
 var bn = Boolean(null);
 var bu = Boolean(undefined);
 console.log(typeof(bo)+": "+bo);
 console.log(typeof(bs)+": "+bn);
 console.log(typeof(bu)+": "+bu); 

Undefined 和 NULL 数据类型

Null 和 Undefiend 都只有一个值的数据类型。分别是:null 和 undefiend

Undefiend:在使用 var 声明变量但未对其加以初始化时,这个变量的值就是 undefined,使用typeof对没有初始化和没有声明的变量,会返回"undefined"

Null:可以被手动赋值,如果这个对象不在被使用将值设置Null,则程序会进行自动回收,节省程序开销

js 复制代码
 console.log("undefined值实际上是由null值衍生出来的,所以如果比较undefined和null是否相等: ");
 console.log(undefined==null);       //:== 双等号比较值;
 console.log(undefined===null);      //:=== 三等号,恒等比较值加数据类型;
 ​
 console.log("从语义上看null表示的是一个空的对象{},所以使用typeof检查null会返回一个Object");
 console.log(typeof null);

JavaScript 是一种弱语音 所以变量不需要定义类型,就可以直接赋值

  • 因为,声明变量不需要定义变量,则数据类型,根据赋值来进行判断;
  • 所以,一个变量上一秒还是Number类型,下一步集可能是String数据类型,因此为了避免后续开发的一些问题

运算符

下面的代码就不贴运行结果了,可以copy到自己的本地进行运算

运算符也叫操作符,通过运算符可以对一个或多个值进行运算并获取运算结果,typeof就是运算符,它会将该值的类型以字符串的形式返回。和Java类似

算术运算符: 算术运算符用于表达式计算

js 复制代码
 /**
  * 算数运算符:+加 -减 *乘 /除 %取模(求余数) ++加加 --减减 
  * 都是和Java的算数运算符也差不多.
  */
 console.log(1+1);
 console.log(1-1);
 console.log(1*1);
 console.log(1/1);
 console.log("% 取模就是求余数,10除以3不整除还余: "+(10%3));
 ​
 var a = 1;
 console.log("++ -- 操作符号类似,都是自增1或自减1,需要注意是在++ --使用时候还会根据前后有区别");
 console.log((++a)+" ++在前则先计算在返回值所以1+1等于"+a);
 console.log((a++)+" ++在后则先输出当前a的值在进行+1的操作所以,在次输出a等于"+a);
 console.log((--a)+" --在前则先计算在返回值所以3-1等于"+a);
 console.log((a--)+" --在后则先输出当前a的值在进行-1的操作所以,在次输出a等于"+a);

关系运算符:

js 复制代码
 /**
  * 关系运算符: 在逻辑语句中使用,以测定变量或值是否相等,最终会返回一个boolean类型的值;
  * 大于 >
  * 小于 <
  * 等于 ==
  * 恒等 ===
  * 大于或等于 >=
  * 小于或等于 <=
  * 常用的运算符,都是和Java也很类似,就不一一介绍了注意一下 == 和 ===
  * */
 console.log("大部分程序中 = 都是赋值操作");
 console.log("== 和 === 都可以用来比较一个数据类型结果是否相等");
 console.log(1==1);
 console.log(1=='1');
 console.log(1==='1');  
 console.log('1'==='1');     // === 使用恒等号进行比较的时候,不仅只要一样,数据类型也要一样才可以.

赋值运算符:

=、+=、-=、*=、/=

js 复制代码
 /**
  * 赋值运算符: 赋值运算符用于给 JavaScript 变量赋值
  * = :将右边的值,赋于左边的变量举例: x = 5; 将5赋值给变量x,
  * 对于数值类型还可以在等号前加算数运算符将结果直接赋值变量:
  * +=、-=、/=、%=
  */
 var w = "今天天气真好";
 console.log(w);
 console.log(w+="适合方风筝.");  //+= 可以用于字符类型的拼接,数值类型的计算。
 ​
 var a = 1;
 console.log("数值类型则先进行计算在赋值:")
 console.log(a+=1);
 console.log(a-=1);
 console.log(a*=10);
 console.log(a/=2);

逻辑运算符:

逻辑运算符用于测定变量或值之间的逻辑,一般在条件语句中使用:if...else 与或非

&& 与:&&可以对符号两侧的值进行与运算并返回结果,运算规则如下:

  • 两个值中只要有一个值为false,就返回false,只有两个值都为true时,才会返回true
  • JS中的"与"属于短路的与,如果第一个值为false,则不会检查第二个值
  • 非布尔值时:如果两个都为true,则返回第二个值,如果两个值中有false,则返回靠前的false的值

|| 或:||可以对符号两侧的值进行或运算并返回结果,运算规则如下:

  • 两个值中只要有一个true,就返回true,只有两个值都为false,才会返回false
  • JS中的"或"属于短路的或,如果第一个值为true,则不会检查第二个值
  • 非布尔值时:如果两个都为false ,则返回第二个值,如果两个值中有true,则返回靠前的true的值

! 非:!可以用来对一个值进行非运算

  • 所谓非运算就是对一个布尔值进行取反操作,true变false,false变true

  • 非布尔值时:先会将其转换为布尔值,然后再取反

    所以我们可以利用该特点,来将一个其它的数据类型转换为布尔值,可以为一个任意数据类型取两次反,来将其转换为布尔值,原理和Boolean()函数一样

    sh 复制代码
     console.log(!!1);       //结果等于 true

比较运算符:

比较运算符用来比较两个值是否相等,如果相等会返回true,否则返回false

==: 进行相等比较,使用 ==进行比较时候,如果两个值类型不同则会自动进行类型转换,将其转换为相同的类型。

!= : 不等,如果两个变量的值不相等则返回 true,否则返回false。和 == 类似如果数据类型不同也会进行类型转化。

===: 全等运算,它和相等类似,不同的是它不会做自动的类型转换,如果两个值的类型不同,直接返回false

!==: 用来判断两个值是否不全等,它和不等类似,不同的是它不会做自动的类型转换,如果两个值的类型不同,直接返回true

条件语句:

if...else

if...else 是一种最基本的控制语句,它让JavaScript可以有条件的执行语句

基础语法:

js 复制代码
 //简单if
 //if(): 可以用于控制程序的逻辑分支.如果满足表达式则执行{}代码块中的代码;
 if(表达式){
     //执行的代码体
 }
 ​
 //if...else if: 相当于多个if()的一种组合,程序自上而下如果满足则执行对应代码块;
 if(表达式1){
     //执行的代码体
 }else if(){
     //执行的代码体     
 }
 ​
 //if...else if...else if...else; 比上面多了一个else{}如果没有一个if|else if成立则执行else{}的方法;
 if(表达式1){
     //执行的代码体
 }else if(){
     //执行的代码体     
 }else{
     //执行的代码体 
 }
  • 如果if(){} else if(){} 代码块中仅有一行语句则可以省略{}

    scss 复制代码
     if() //一行代码体;

switch...case

  • 和 if 一样也是程序一种控制分支的结构语法:
js 复制代码
 switch (表达式) {
     case value1:
         语句...
         break;
     case value2:
         语句...
         break;
     default:
         语句...   
 }
 //case value: 当switch()表达式获取的值与对应的case匹配则执行对应case的代码;
 //注意建议给每个case语句后面都加上一个break; 
 //不然会往后传递下一个case无论是否匹配vaule当然一定程度可以实现某些功能。
         
 //default相当于一个默认执行的case
 //如果没有任何一个case满足条件才执行,注意default并不是一定在最后一个可以是在上面.但要注意加上break;       

循环语句:

循环语句和条件语句一样,也是基本的控制语句,只要满足一定的条件将会一直执行,最基本的循环语句:几乎和Java类似

for

js 复制代码
 /*语法格式:
     初始化表达: 定义循环的起始值
     条件表达式: 定义循环的起始条件,每次循环开始执行判断,满足则开始循环
     更新表达式: 每次循环结束则执行,一般是更新起始值,用于控制循环的结束
 */ 
 for(初始化表达式 ; 条件表达式 ; 更新表达式){
     //代码循环体...
 }
 //案例演示:输出1-10
 for (var i = 1; i <= 10; i++) {
     console.log(i);
 }

while

js 复制代码
 /**
  * while语句在执行时:
  *   先对条件表达式进行求值判断,
  *   如果值为true,则执行循环体,
  *   循环体执行完毕以后,继续对表达式进行判断如果为true,则继续执行循环体,以此类推
  * 如果值为false,则终止循环
  */
 while(条件表达式){
     语句...
 }
 //案例演示:死循环,永远无法结束的循环被称为死循环,可以使用break跳出循环结构;
 var i=1;
 while(true){ console.log(i++); }
 ​
 //案例演示:输出1-10,创建一个循环通常需要三个步骤;
 //1创建一个变量
 var i = 1;
 //2定义一个循环的条件表达式
 while (i <= 10) { 
     //3定义一个更新表达式,并且最终会使循环条件false
     console.log(i++); 
 }

do...while

do...while和while非常类似,只不过它会在循环的尾部而不是顶部检查表达式的值

因此,do...while循环会至少执行一次,相比于while,do...while的使用情况并不是很多。

js 复制代码
 //语法结构
 /**
  * do...while语句在执行时,
  *  会先执行循环体,循环体执行完毕以后,
  *  在对while后的条件表达式进行判断,如果结果为true则继续执行循环体,执行完毕继续判断以此类推
  * 如果结果为false则终止循环
  */
 do{
     语句...
 }while(条件表达式);
     
 //案例演示:输出1-10
 var i = 1;
 do {
     console.log(i++); 
 } while (i <= 10);

break、contine 跳转控制

  • break: 结束当前循环开始下一次循环,可以在循环和switch语句case中使用,不然会传递下一个case结构的代码执行;
  • contine: 结束本次循环,执行下一次循环,只能在循环中使用

JavaScript对象

数据类型

JS中的数据类型分为两种:基本数据类型、引用数据类型 和Java很相似

JS 5中基本数据类型:

  • StringNumberBooleanUndefinedNull
  • 基本数据数据类型值,是无法修改的,存储在栈中,基本数据类型比较是值的比较;

引用数据类型:

  • 可以说除了基本数据类型,JS中其他的都是引用数据类型引用数据类型也分为三种:

  • 内建对象: 属于JS自带的对象,ECMAScript标准定义的对象。

    比如:Math String Number Boolean Function Object console 在任何的环境中都可以使用.

  • 宿主对象: 由JS运行环境提供的对象,JS常见的运行环境有:浏览器 node

    浏览器提供的对象有:DOM BOM,所以在node中并不可以使用BOM DOM,node中也存在自己的宿主对象:global

  • 用户自定义对象: 由开发人员自己创建的对象,最常用也是开发人接触最多的

为什么需要对象

因为基本数据类型仅能表示单一的值,值和值之间没有任何的联系,无法为我们定义表示一个复杂的信息;

如果,我想表示一个人的信息普通的基本数据类型很难满足需求,变量之间没有联系不方便管理。

js 复制代码
 //JS中表示一个人的信息,创建变量不属于一个整体不方便管理.
 var name = "张三";
 var age = 18;
 var sex = 无;

对象属于一种符合的数据类型,在对象中可以保存多个不同数据类型的属性

如果学过Java其实就是类,只不过JS没有类的概念(弱语言),所以这里也是最难的地,JS的规范弱也导致学起来会感觉乱七八糟的

创建对象new Object()

  • 建议尽量以初学者心态来学习JS

    对于学过其他编程语言Java,这种写法我刚开始也是难以接受:对象、构造函数、new的概念都了解过,但是在Js里面仿佛都不认识了

  • JavaScript中,new 函数() 那么这个函数就是构造函数

    new Object(),大部分编程语言都有Object类型对象,是所有对象的父类,所有的对象都属于Object

    普通函数也可以new,那么就是创建普通函数的对象.构造函数就可以理解为类的概念。没关系如果还不理解可以先用着慢慢感受.

js 复制代码
 //new 函数创建对象 
 //JS中使用new 调用的函数,就是constructor构造函数,构造函数就是用来创建对象的函数{};
 var obj = new Object();
 console.log(obj);
 console.log("obj的数据类型"+typeof obj);         
 console.log("console的数据类型"+typeof console);         //所有的对象都属于Object类型,console属于内置对象: .log()、.info()...等输出方式
sh 复制代码
 {}
 obj的数据类型object
 console的数据类型object

添加对象属性:

添加对象属性: 属性名遵循变量的命名规范,可以赋值基本数据类型、引用数据类型.

  • 语法: 对象.属性名;
  • 赋值: 对象.属性名 = xxx; 对象的属性其实就一个个变量,可以是基本数据类型也可以是一个引用数据类型
js 复制代码
 //new形式创建对象如果属性未赋值则不会保存;
 obj.name ="张三";
 obj.sex = '无';
 obj.age = 18;
 obj.isok;                                                    
 console.log(obj);
js 复制代码
 { name: '张三', sex: '无', age: 18 }

注意: 如果给new Object() 对象创建对象,需立刻赋值则无值则添加不上;

读写对象属性:

  • 读语法: 对象.属性名;
  • 写|改语法 其实就是重新|赋值: 对象.属性名 = xxx;
js 复制代码
 //操作对象属性: 对象.属性名 修改|读取属性值;
 obj.name = "张一三";
 console.log("读取obj的name属性:"+obj.name);
 console.log("如果读取一个obj中不存在的属性:"+obj.name1);    //则返回undefined

删除对象属性:

  • 语法: delete 对象.属性名 删除要删除的属性名.
js 复制代码
 //删除对象中的属性: delete 对象.属性
 delete obj.name;
 delete obj.name1;
 console.log(obj.name);
 console.log(obj.name1);                                    //无论是否存在都删除,在使用就是undefined;

in 运算符

  • 可以检查一个对象中是否含有指定的属性,存在true,不存在则false

  • 语法: '属性名' in 对象

    判断对象中是否存在'A属性名'

js 复制代码
 //检查对象里面是否含有某个属性 in运算符
 //检查 obj 是否含有name、name1
 console.log("name" in obj);
 console.log("name1" in obj);

对象['xxx']操作:

上面操作对象属性,对于咱们学过Java等编程的小伙伴很熟悉,除此之外JS还有一个更灵活的操作方式:创建对象|赋值|获取...

js 复制代码
 //new Object()创建对象
 //使用对象['']进行属性调用赋值操作...
 var obj2 = new Object();
 obj2['name'] = '李四';
 obj2['age'] = 18; 
 console.log(obj2);
  
 //对象['']操作:赋值|读|写|删除对象.属性使用一致;
 obj2['@E$!F'] = '@E$!F'; 
 obj2['123456'] = 123456; 
 delete obj2['name'];
 console.log(obj2);
 console.log('是否包含 @E$!F 属性: '+('@E$!F' in obj2 ));
 console.log('是否包含 @E$!F1 属性: '+('@E$!F1' in obj2 ));
sh 复制代码
 { name: '李四', age: 18 }
 { age: 18, '@E$!F': '@E$!F', '123abc': 123 }
 是否包含 @E$!F 属性: true
 是否包含 @E$!F1 属性: false
  • 如果我们想使用特殊的属性名:

    JS不支持使用 对象.特殊属性名 的操作,所以提供了 对象['属性名']形式进=行使用。

对象[变量]:

对象[]的写法最厉害的地方在它支持传入一个变量: 变量的值作为属性名进行查询对象;

js 复制代码
 var a = 123456;
 var b = '@E$!F';
 console.log("变量a作为参数: "+obj2[a]);       //变量的值作为属性名进行查询对象;
 console.log("变量b作为参数: "+obj2[b]);
sh 复制代码
 变量a作为参数: 123456
 变量b作为参数: @E$!F

随口一提: 上述代码在不同的运行环境可能会不同效果不必太在意,浏览器会自动检查JS:重排队列

JS弱语言,所以很多情况都不会报错,删除|获取|修改不存在的变量都不会报错就是一个没有任何结果提示信息. 所以小白排错超级痛苦.

创建对象{ ... } ✨

JS 提供字面量创建对象形式: 本质上和new Object()没有任何区别,不过 {...}形式更加的方便.

  • 语法: { 属性名:属性值, 属性名:属性值... }

  • 属性名和属性值是一组一组的名值对结构:

    名和值之间使用:连接

    多个属性之间使用,隔开如果一个属性之后没有其他的属性了就不要写,

    对象字面量的属性名可以加引号也可以不加,建议不加,如果要使用一些特殊的名字,则必须加"引号";

js 复制代码
 //定义全局属性:
 var wsm = "张三爸爸";
 ​
 //字面量形式创建对象 
 var obj = {
     name:'张三',
     "@#!":"特殊属性名", 
     
     //赋值外界的的值:
     father:wsm,
     //属性赋值引用数据类型:
     obj2:{
         name:"张三妻子"
     },
 }
 console.log(obj);
css 复制代码
 { name: '张三', '@#!': '特殊属性名', father: '张三爸爸', obj2: { name: '张三妻子' } }

JavaScript函数:✨

函数是一段可重复使用的代码块

  • 它接受输入参数并根据这些参数执行特定的任务或计算,并返回一个结果。
  • 函数可以帮助我们将复杂的问题分解为更小的部分。
  • 只有在调用函数时才会执行函数 体内部的代码。

如何使用函数:

  • 声明|定义函数:

    函数也是一个对象,所以也是在堆内存中保存的,使用function关键字声明;JS有很多方式:👇

  • 调用函数:

    声明之后的函数需要调用才可以使用,遵循JS代码自上而下执行的。

注意:函数也是一个对象,万物皆对象。 简直和Java一毛一样😶‍🌫️

创建函数方式一:

构造函数形式创建函数: 实际开发中并不建议使用(了解即可);

new Function() 是 JavaScript 中的内置构造函数,它接受一个或多个字符串参数,表示函数的参数和函数体

  • 声明|定义函数语法: new Function('',''...);

    前面几个参数表示函数的参数,最后一个参数字符串表示函数要执行的代码,这种写法不方便读所以实际开发中并不建议使用。

js 复制代码
 //构造函数创建函数 new Function()
 //接受两个参数 a和b 这两个参数表示函数的两个参数
 //函数体为: 'console.log(a+b);' 输出两个参数的和。
 var myFunction = new Function('a','b', "console.log(a);"
                                             +"console.log(b);"
                                             +"console.log(a+b);");
 ​
 //调用函数
 //JS弱语言代码规范弱,没有指定默认传递unidefind
 myFunction();
 myFunction(1,1);
 console.log("函数本质也是对象所以检查myFunction类型:"+typeof myFunction);         //返回 function函数类型;
  • 调用函数语法: 函数名(参数,参数...);

    多个参数之间使用逗号, 进行分隔

    JS代码规范弱,调用函数,参数没有指定类型要求根据传参下标进行匹配,如果没传默认unidefind值;

  • 构造函数形式了解即可,实际开发几乎不会使用,不方便写,也不方便读的

创建函数方式二:✨

function 函数声明形式创建函数:语法👇

js 复制代码
 //function 函数声明创建函数:
 // function 函数名([形参1,形参2...形参N]){
 //     语句...
 // }
 ​
 //定义无参函数:
 function fun1(){
     console.log("使用function创建函数~~~");
     console.log("哈哈哈");
 }
 //定义带参函数,计算参数和:
 //使用return将结果返回,但没有高级语言严格的控制返回值类型;
 function fun2(a,b,c){
     return a+b+c;
 }
 ​
 //调用函数:
 fun1();
 console.log(fun2(1,2,3));
 ​
 //function定义: 快速声明定义函数、函数名、参数、代码体 推荐使用;
 var a = fun2;
 console.log("函数也是对象可以之间赋值,比较的是堆地址:"+(a===fun1)+"\t结果:"+a(1,2,3));

推荐使用: 快速声明定义函数、函数名、参数、代码体...

创建函数方式三:

匿名函数,JS一种快速声明函数的方法:

函数表达式(匿名函数): 与上面函数声明机会没有本质的区别;

js 复制代码
 //语法:var 函数名  = function([形参1,形参2...形参N]){ ... }
 ​
 //创建无参函数:
 var nfun = function(){
     console.log("函数表达式创建函数;");
 }
 ​
 //创建带参函数:
 var nfun2 = function(a,b){
     return a+b;
 }
 ​
 //调用函数;
 nfun();
 console.log("调用带参的函数:"+nfun2(1,2)); 

函数的参数

函数的参数是在函数定义中用来接收传入值的变量,参数可以帮助函数接收外部的数据,并在函数体内进行处理或操作。

形式参数(也称为形参)

  • 在函数定义时声明的参数,用于接收函数调用时传递的值。
  • 形参是函数内部的局部变量,只在函数内部可见。

实际参数(也称为实参)

  • 在函数调用时传递给函数的值。实参可以是常量、变量、表达式等,它们会被赋值给对应的形参。

JavaScript 中的函数参数传递是按值传递的

  • 当一个函数被调用时,参数的值会被复制到函数的局部变量中,函数内部对参数进行修改不会影响到原始的参数值.
  • 但,当参数是引用类型(例如对象或数组),传递的是引用的副本,因此在函数内部修改引用的属性会影响到原始对象。

JavaScript 函数小知识🔖 因为JS语法规范不强

  • 函数的参数没有规定参数类型,所以调用函数传递的时候需要注意;

  • 定义函数参数------> 调用函数参数:

    根据一一匹配原则如果没有传递则默认传递值 undefined

    传参数 > 定义参数数量,不会报错,多余参数也没有使用影响;

  • 函数的参数可以是一个引用数据类型(对象),而函数也是一个对象 所以函数也可以作为参数传递,有一点点抽象不过可行。

js 复制代码
 //基本数据类型: 基本数据类型参数传递的是值;
 //定义变量和函数
 var a = "a";
 function fun(a){
     a="aa";
     console.log(a);
 }
 ​
 //调用函数、属性判断是否发生改变;
 fun(a);
 console.log(a);
 ​
 ///////////////////////////////////////////////////////////////////////////////
 ​
 //引用数据类型: 引用数据类型传递的是地址;
 var user = { name:"张三",age:18 };
 function fun2(user){
     user.age = 19;
     console.log(user);
 }
 //调用函数、属性判断是否发生改变;
 fun2(user);
 console.log(user);

函数的返回值

麻雀虽小五脏俱全,虽然是若语言但是和大部分语言一样具有函数返回值;

JS 函数的返回值是指函数执行完后返回给调用函数的值: 关键字: return

  • 语法: return xx;

    return后的值将会会作为函数的执行结果返回,可以定义一个变量来接受函数返回值;

JS的检查规范不强烈所以很多情况不会有报错提示但和很多语言一样:

  • return 后的语句都不会执行
  • return 后可以跟任意类型的值
  • return 语句后不跟任何值就相当于返回一个undefined,如果函数中不写return,则也会返回undefined。
js 复制代码
 //无返回值函数
 function fun(){
     console.log("无返回值函数");
     return;
 ​
     console.log("return 后面的语句就不会执行,好的编辑器会进行提示!!");
 }
 //有返回值函数
 function fun2(a,b){
     return a+b;
 }
 ​
 ​
 //调用函数并用参数接受:
 var a = fun();
 var b = fun2(1,1);
 console.log("无返回值的结果:"+a);
 console.log("无返回值的结果:"+b);

立即执行函数

立即执行函数是JavaScirpt的一个特殊函数,指的是函数在定义之后就立即执行,通常也只会执行一次。一般在很多框架中出现使用

  • 语法: (匿名函数)(函数参数); 好吧稍微有一点抽象.

    在立即执行函数的定义周围使用括号是为了将其视为一个表达式,而不是一个函数声明。

    这样做是因为 JavaScript 解析器会将以 function 关键字开头的语句解析为函数声明,而报语法错误;

js 复制代码
 //1 当我们直接定义匿名函数发现如果不赋值会报错.
 // function(){
 //     console.log("匿名立即执行函数");
 // }
 ​
 //2 如果使用()进行包括就是一个整体就详单于是一个函数
 //3 (将匿名函数作为一个整体)(调用匿名函数并传递参数)
 (function(){
     console.log("匿名立即执行函数");
 })();
 ​
 //带参匿名函数
 (function(name){
     console.log("立即执行函数参数:"+name);
 })("123");

立即执行函数的主要作用是创建一个独立的作用域,避免变量的污染

  • 通过将代码封装在一个函数中,并立即调用该函数,可以确保其中定义的变量和函数只在该函数内部有效,不会影响外部的全局作用域。

  • 立即执行函数还常用于模块化开发

    将需要共享的变量和函数放在立即执行函数的内部,并通过返回值或闭包来提供对这些私有成员的访问

JavaScript对象(高级)

获取对象中所有属性(枚举)

我们学一个对象,首先要知道对象中的属性...如何获取对象中的所有属性呢?

  • 我知道可以使用:"属性" in "对象" 判断对象是否包含某个属性;
  • 而如何想要知道一个对象中的所有属性可以使用:for in 对象
js 复制代码
 //枚举对象中的属性 
 /*
 * 语法:
 *   for(var 变量 in 对象){ } 
 *
 * for...in语句 
 *   对象中有几个属性,循环体就会执行几次
 *   每次执行时,会将对象中的一个属性的名字赋值给变量;
 *   根据对象调用属性: 对象[""] 可以实现获取属性值;
 */
 ​
 //1.创建一个对象
 var obj = { "name":"张三",sex:'男',age:18,sayName:function(){ console.log("这是一个函数") } }
 ​
 //2.for in枚举对象
 for (var o in obj) {
     console.log("属性名:"+o+",属性值:"+obj[o]);
 }

对象的方法()

我们都知道,对象的属性可以是任何数据类型:基本数据类型 引用数据类型 而函数也是对象,所以👇

通过给对象属性赋值,函数的形式,就是定义对象的方法;

js 复制代码
 //方式一: new Object()创建一个对象,并赋值属性函数|方法;
 var obj = new Object();
 obj.age = 18;
 obj.name = "张三";
 obj.sayName = function(){ console.log("你好我叫:"+obj.name); }
 ​
 //调用对象的方法;
 obj.sayName();
 console.log(obj);
 ​
 ​
 //方式二: {...}创建一个对象,并赋值属性函数|方法;
 var obj2 = {
     name:"李四",
     age:19,
     sayName:function(){
         //这里的this表示当前对象;
         console.log(this);
         console.log("你好我叫:"+this.name);
     }
 }
 obj2.sayName();

函数和方法

JavaScript 函数和方法本质上是一个东西: 仅仅是因为定义在对象中叫方法,定义在非对象中被称为函数,为了区分的一种叫法;

JavaScript作用域:

作用域指一个变量的作用的范围: JS有两种作用域,全局作用域、局部作用域(函数作用域)。

全局作用域

  • JS根据不同的环境有一差异: JS全局作用域对应一个全局对象:windows |global

  • windows: 它由浏览器创建,代表的是一个浏览器的窗口

    前端JS,编写在script标签中的JS代码,都在全局作用域,变量|函数,都会作为windows属性|方法保存。

  • global: 同上👆,类似是JS在node环境中全局作用域对象,不同的是global上全局对象需要手动绑定。

注意:JavaScript中存在windowsWindows 是两个完全不同的概念

windows对象: 它是浏览器环境中的全局对象,提供了与浏览器窗口和页面相关的属性和方法。

Windows对象: Microsoft Windows,由 Microsoft 公司开发,它是广泛使用的桌面操作系统之一。


前端环境:

js 复制代码
 <script>
     var a = "abc";
     console.log(a);
     console.log(window.a);
 </script>

node运行环境:

js 复制代码
 //node中的global全局作用域对象:
 /*并不像windows对象默认所有的对象都会定义在global中,而且需要指定 globale.对象名 = xxx;
     Node中全局对象指的是可以在任何地方访问的对象
     它是所有全局变量和函数的容器,并且可以在任何地方使用,使用 global 对象,我们可以在不同文件之间共享数据和方法;
 */
 var a = "abc";
 console.log(a);
 console.log(global);
 console.log(global.a);  //返回: undefined
 ​
 //在全局对象中定义变量|函数: 没有定义默认全局变量;
 b = "bbb"
 global.c = "ccc";
 console.log(global.b);  //返回: bbb
 console.log(global.c);  //返回: ccc

局部作用域

JavaScript中的局部作用域又称为"函数作用域"

指变量和函数在其被定义的区域内可见和可访问,超出该区域则无法访问,局部作用域的创建方式有两种:函数作用域块级作用域

函数作用域:

在JavaScript中,每当函数被调用时,都会创建一个新的函数作用域。

函数作用域中定义的变量和函数只能在该函数内部访问,外部无法访问,但可以访问全局作用域

  • 当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用

    注意: 函数的参数,也是属于局部作用域,如果调用函数时候没传相当于传入了 undefinde

    js 复制代码
     //参数属于局部作用域: 函数中使用遵循就近原则,结果: undefined
     myfun();
     var a = "123";
     function myfun(a){ console.log(a); }  
  • 如果没有则向上一级作用域中寻找,直到找到全局作用域

  • 如果全局作用域中依然没有找到则:ReferenceError

在函数中要访问全局变量可以使用window|global对象

js 复制代码
 var a = 10;
 //在函数作用域内定义的变量,可以访问全局作用域
 function myFunction() {    
     var x = 1;
     console.log(x);
     console.log(a);
     console.log(window.a);
 }
 //变量 x 在myFunction函数内部定义,只能在该函数内部访问,函数外部访问 x则报错:ReferenceError: x is not defined
 myFunction();
 console.log(x);

函数作用域也有声明提前的特性:

var关键字声明的变量,会在函数中所有的代码执行之前被声明,函数声明同理🤖

js 复制代码
 //声明提前:
 //未定义a但是并不会报错var被声明提前了,函数也支持声明提前不展示了;
 function myFunction2(){
     console.log(a);
     var a = "2333333";
 }
 myFunction2();

不使用var声明的变量都会成为全局变量:

js 复制代码
 function myFunction3(){
     //会报错没有var声明并不会声明提前;
     // console.log(w);
     w = "2333333";
 }
 myFunction3();
 console.log(w);
 console.log(global);    //在global中存在

ES6块级作用域:

块级作用域是由一对花括号 {} 包围的代码块,例如 if{ }语句、循环语句和函数等;

块级作用域中定义的变量和函数只在该代码块内部可见和可访问,并且在代码块外部是无法访问的

ES6 (ECMAScript 2015) 引入之前:

  • JavaScript 只有函数作用域和全局作用域,没有块级作用域
  • 在使用 var 关键字声明变量时,它们的作用域是整个函数或全局范围,导致变量声明冲突和污染全局命名空间;

而使用 let 和 const 关键字声明的变量引入了块级作用域的概念:

  • 在块级作用域中定义的变量只在当前代码块内部有效,并且不会影响到外部的同名变量。
js 复制代码
 //JS代码块: 
 //代码块并不是函数,声明之后会立即执行,相当于正常的JS块中执行,但是内部的let const声明的属于局部变量;
 {  
     a = 1;             
     var b = 10;
     let c = 100;
     const d = 1000;
     //全正常输出
     console.log(a); 
     console.log(b); 
     console.log(c);
     console.log(d);
 }
 //a,b无影响正常使用: c,d属于代码块的局部变量报错;
 console.log(a);
 console.log(b);
 console.log(c); 
 console.log(d);
 console.log(global);
 ​
 ///////////////////////////////////////////////////////////////////////学习时候可以注释上下代码查看效果;
 ​
 //函数中的{  }代码块这个是if...
 function fun(){
     if(true){
         a = 1;             
         var b = 10;
         let c = 100;
         const d = 1000;
     } 
     console.log(a); 
     console.log(b); 
     //a,b无影响正常使用: c,d属于代码块的局部变量报错;
     // console.log(c);
     // console.log(d);
 }
 fun();
 //仅有a可以使用,b属于函数局部变量,cd属于函数中{}代码块的局部变量
 console.log(a); 
 // console.log(b); 
 // console.log(c);
 // console.log(d);

JavaScript声明提前📈

JavaScript 代码某种程度并不是自上而下原则:

JavaScript 解释器执行代码时,会进行两个步骤:变量声明和变量赋值。

变量声明阶段,JavaScript 解释器会扫描代码,将变量和函数声明提前到作用域的顶部,这个过程被称为 "声明提前"

变量的声明提前:

当使用 var 关键字声明变量时,变量的声明会被提升到当前作用域的顶部,

但是变量的赋值仍然保留在原来的位置。这意味着,在变量声明之前就可以使用这个变量,但它的值会是 undefined

js 复制代码
 console.log(x); // 输出:undefined
 var x = 10;
  • 正常情况console.log(x);之前没有声明var x = 10; 会直接报错:ReferenceError: x is not defined 声明提升: 一定程度避免了错误❌

通过JS解释器,翻译之后执行的是:

  • 所有:var声明的属性都会最先执行,而赋值在定义位置执行。
js 复制代码
 var x;
 console.log(x);
 x = 10;  

注意:

letconst 关键字声明的变量不会完全被提前。它们仍然受到块级作用域的限制,称为"暂时性死区"

它们在声明之前不能被访问,会处于"暂时性死区"。只有在变量声明之后才可以使用,在声明之前访问它会抛出 ReferenceError 错误;

函数的声明提前:

函数声明也会被提前到当前作用域的顶部,可以在函数声明之前调用函数。

js 复制代码
 // 可以在函数声明之前调用
 myfun(); 
 ​
 function myfun() {
   console.log("Hello, I'm foo!");
 }

仅有,function声明式函数可以被提前,匿名函数并不会被声明提前,报错: TypeError: myfun is not a function

js 复制代码
 // 报错TypeError: myfun is not a function
 myfun();    
 ​
 var myfun = function(){
   console.log("Hello, I'm foo!");
 }

关于,作用域和提前声明会经常遇到面试题,需要小心谨慎📑

JavaScript 中this的使用:

JavaScript中的this: (简单介绍:随着JS版本迭代有了新的特性)

解析器在调用函数每次都会: 默认向函数内部传递进一个隐含的参数this(上下文对象)

根据函数的调用方式的不同, this会指向不同的对象

  • 以函数的形式调用时this永远都是window|global
  • 以方法的形式调用时this就是调用方法的那个对象
  • 以构造函数形式调用时,this就是创建的那个对象 下述代码详细介绍
js 复制代码
 /** this永远都是window|global,node环境global需要特殊声明并不是var默认绑定... */
 /** node环境var声明并不global, 直接定义则是全局 */    
 name = "张";
 function myfun(){
     console.log(this == global);
     console.log(this.name);
 }
 ​
 //定义obj对象:
 var obj = {
     name:'张三',
     objfun:myfun
 }
 ​
 //在全局中声明的myfun被称作:函数
 //在对象中声明的myfun被称为:方法,对象中objfun和全局实际上指向的是一个地址所以本质是一个函数对象;
 console.log(obj.objfun === myfun);  //结果: true
 //全局调用myfun()无参函数:
 myfun();
 //obj调用objfun()无参方法:
 obj.objfun();

myfun()运行结果:

  • true函数调用this 其实就是全局的对象windows|golbal,同上this.name就是从全局对象中获取

obj.objfun();运行结果:

  • false 张三 :方法调用,this指向的是调用函数的对象;

对象.方法(){ 变量默认从全局获取 }

this使: 对象.方法 变量来源于对象本身,而不是全局,避免了变量冲突污染;

js 复制代码
 //定义obj2对象:
 //JS 对象.方法(){ 变量默认从全局获取,为了避免变量冲突this很重要; }
 var a = "123"
 var obj2 = {
     a:'321',
     fun:function(){
         console.log(a);         //输出全局 a:123
         console.log(this.a);    //输出obj2 a:321
     }
 }
 ​
 obj2.fun();

工厂模式创建对象:了解)

对于JavaScript 创建对象,上面已经介绍了:new Object(); { xxx } 但好像有点不妥:

如果我们需要创建很多个相同类型的对象呢:我和我的朋友以程序进行管理,那就需要很多个对象则:

js 复制代码
 //原始情况: 我和盆友们以程序进行管理,则需要创建对应的对象;
 var w = { name:"w",age:18 }
 var a = { name:"a",age:18 }
 var b = { name:"b",age:18 }
 /** var ? = { name:??,age:?,???:??? } */
  • 通过原始方式我们创建三个对象w a b 可是存在一个问题,这些对象拥有类似的:属性 方法() 而定义却要声明多次...

    后期,属性|方法更多更复杂,依然这种情况则代码太过冗余、复杂...

    对于这种需要经常执行类似的代码,我们想到了 函数

  • 函数: 接受输入参数并根据这些参数执行特定的任务或计算,并返回一个结果,将创建对象定义在函数中并返回。

    这种专门为创建对象的函数,我们称为:对象工厂函数()

对象工厂函数()

js 复制代码
 /**
  * 对象工厂函数: 
  *  工厂函数本质是其实就是一个普通的函数,接受参数,执行{ 代码体 },返回结果;
  *      通过函数参数给对象属性值赋值;
  *      执行函数体: new Object(); 创建函数|属性|方法() 最终通过return返回出完整的对象;
  */
 //定义一个专门创建People的工厂函数
 function createPeople(name,age){
     var obj = new Object();
     obj.name = name
     obj.age = age
     obj.sayName = function(){
         console.log("我叫"+this.name+"今年"+this.age+"岁");
     }
     return obj;
 }
 //调用对象构造函数创建对象:
 var w = createPeople("w",18);
 var a = createPeople("a",18);
 var b = createPeople("b",18);
 w.sayName();
 a.sayName();
 b.sayName();

构造函数创建对象:(进阶)🔼

工厂模式:问题⚡

经过上面的学习,我们可以批量的创建对象,但对象工厂创建的对象存在一个问题:无法判断创建对象的类型

  • 因为: 工厂模式创建对象地城都是 new Object();
  • 所以: 对象的本源都是object,对于一个大型的项目,数据类型也必然庞大.

工厂模式创建的对象不方便管理,无法确认对象类型

js 复制代码
 //定义两个对象工厂 人 和 狗工厂进行比较;
 //定义People对象工厂
 function createPeople(name,age){
     var obj = {name:name,age:age};
     return obj;
 }
 //定义Dog对象工厂
 function createdog(dname,dage){
     var obj = {dname:dname,dage:dage};
     return obj;
 }
 //使用不同的工厂创建对象进行比较:
 var peo = createPeople("张三",18);
 var dog = createdog("小黑",3);
 console.log(peo);                       
 console.log(dog);                       
 console.log(typeof peo);                // object
 console.log(typeof dog);                // object
 console.log(typeof dog == typeof peo);  // true

构造函数创建对象:

构造函数,其实本质上就是一个普通函数

  • 建议命名(首字母大写)

  • new Xxxx(...); 与普通函数不同,调用时候需要通过:new 关键字进行调用

    用户:var a = new Xxxx() 每次new都会在 堆内存开辟空间 返回的就是这个堆的指针,JS中new函数,那么这个函数就是构造函数

  • this 以构造函数形式调用时,this就是创建的那个对象

    构造函数中只能使用,this 关键字来定义属性|方法,this指向堆内存,同时是函数创建返回的对象 this又多了一个特性.

稍微有一点抽象,暂时不理解没关系,先学会用吧

js 复制代码
 //定义构造函数,本质是普通函数,建议命名(首字母大写)
 function People(pname,page){
     //通过this设置对象的属性|方法();
     //必须使用this,因为构造函数也是函数,所以默认寻找全局变量,而函数本身没有定义属性|函数,所以全局找不到会报错;
     this.name = pname;
     this.age = page;
     this.sayName = function(){
         console.log("我叫"+this.name+",今年:"+this.age);
     }
 }
 //通过 new Xxxx(...); 调用构造函数创建对象;
 var peo = new People("张三",18); 
 console.log(peo);
 peo.sayName();
yaml 复制代码
 People { name: '张三', age: 18, sayName: [Function (anonymous)] }
 我叫张三,今年:18
  • 🆗 我们发现返回的对象并不是Object了,有了一个特定的类型:People 这让我们更加方便的管理对象

构造函数的执行流程:

new 构造函数,堆开辟空间,创建出新的对象,

执行构造函数中的代码,并通过 this定义属性|方法, this 本质就是堆空间地址,

最后构造函数代码执行完毕,将this地址作为函数返回值, 返回赋值到指定的对象上:var a - new Xxxx(,,,);

instanceof 判断对象类型:

使用instanceof可以检查一个对象是否是一个类的实例

  • 语法: 对象 instanceof 构造函数名 是返回true,否则返回false
  • 注意⚡:JS中所有的对象本质上依然是Object,Object是一切对象的基类(父类)
js 复制代码
 console.log(peo instanceof People);     //返回true
 console.log(peo instanceof Object);     //返回true

构造函数创建对象:(高级)⏫

程序开发就是一个不断优化的过程,世界上没有完美的事情,也不存在没有bug的程序 程序存在bug是正常滴

构造函数内存泄漏问题:

经过上面的学习,我们已经掌握了几乎完美的 构造函数 ,而任然存在,内存泄露的问题:

内存泄漏: 原因发生在,构造函数内定义创建方法()

js 复制代码
 //创建一个构造函数
 //在Person构造函数中,定义一个sayName方法,我们知道方法也是对象的一种;
 function Person(pname,page){
     this.name = pname;
     this.age = page;
     this.sayName = function(){
         console.log("我叫"+this.name+",今年:"+this.age);
     }
 }
 //因为我们的方法是在构造函数内部创建的
 //也就是构造函数每执行一次就会创建一个新的sayName方法,执行100次就会创建100个新的方法,而100个方法都是一摸一样的;
 var per1 = new Person("张三",18);
 var per2 = new Person("李四",180);
 ​
 console.log(per1);
 console.log(per2);
 console.log(per1 === per2);
 console.log(per1.sayName === per2.sayName); //false: 两个对象的方法也是不同的地址;

全局方法解决内存泄漏🚨

因为,构造函数内部定义对象,导致每一次new 构造函数(); 都会创建新的对象占用内存空间。

所以,将需要定义的方法,提前定义在全局中,构造函数中引用全局的函数,则可以保证构造函数方法重复创建问题

js 复制代码
 //全局定义函数: this在构造函数中指向的创建的对象;
 function gsayName(){ console.log("我叫"+this.name+",今年:"+this.age); }
 ​
 //创建一个构造函数
 function Person(pname,page){
     this.name = pname;
     this.age = page;
     this.sayName = gsayName;
 }
 //创建构造函数的对象
 var per1 = new Person("张三",18);
 var per2 = new Person("李四",180);
 ​
 //调用全局函数,构造函数对象的方法,构造函数方法之间比较;
 gsayName();
 per1.sayName();
 per2.sayName();
 console.log(per1.sayName === per2.sayName); //true: 两个对象方法相同地址避免了内存溢出;

ok,上述这种全局的方式解决了,内存溢出的问题,不过~~可以继续优化:

  • 一定程度上解决了内存溢出,但同时也带来了,污染全局作用域命名空间⚠️

    函数内部的方法名,定义在全局,多个不同的构造函数、全局本身的函数名...之间难免产生碰撞重名不方便管理😵

原型对象解决内存泄漏

什么是原型对象:

  • JavaScript中每一个函数对象都存在一个隐藏的对象属性: prototype原型对象

  • 函数以普通函数调用,prototype没有任何作用

  • 函数以构造函数调用,new 构造函数(...);

    所创建的每一个对象都具有一个隐含属性 __proto__ 该属性地址指向构造函数的原型对象:prototype

js 复制代码
 /**原型对象prototype:
  * JavaScript中每一个函数对象都存在一个隐藏的对象属性: prototype原型对象
  *      函数以普通函数调用,prototype没有任何作用 
  *      函数以构造函数调用,所创建的每一个对象都有一个隐含属性__proto__指向构造函数的原型对象;
 */
 ​
 //创建函数,并以构造函数形参创建对象: p1、p2、p3
 function Person(pname,page){
     this.name = pname;
     this.age = page;
 }
 var p1 = new Person("张三",1);
 var p2 = new Person("李四",2);
 var p3 = new Person("王五",3);
 ​
 //获取、比较原型对象
 console.log(Person.prototype);      //输出结果并不是 undefined 所以函数是存在prototype属性的;
 console.log(p1.__proto__);
 console.log(p2.__proto__);
 console.log(p3.__proto__);
 //构造函数prototype 和 创建对象的__proto__属于一个地址
 console.log(Person.prototype === p1.__proto__);
 console.log(p1.__proto__ === p2.__proto__);
 console.log(p2.__proto__ === p3.__proto__);
  • 所以: 由同一个构造函数创建的对象的 __proto__ 指向的是同一个内存空间
  • 而: 万物皆对象原则:__proto__ 是一个对象,可以给其设置:属性|方法,被所有的构造函数对象共享~

原型对象解决内存泄漏:

🆗,了解了原型对象的特性:

  • 我们可以将:函数定义在原型对象中,属于公共属性

JavaScript 中的原型对象,就有点像Java中的 static 静态属性方法一样

突然问题:Java在类的内部定义方法会不会导致内存泄漏

  • 不会 Java 和 JavaScript 在对象和方法的处理上有很大的区别

  • Java 中,类的方法是类的行为的一部分,它们只在类加载时被加载一次

    Java 中,类的方法都是共享的,它们被加载到 JVM 中的方法区(Method Area)中,所有对象实例都可以调用相同的方法代码;

js 复制代码
 function Person(pname,page){
     this.name = pname;
     this.age = page;
 }
 //给原型对象赋值属性|方法;
 Person.prototype.a = 123;
 Person.prototype.afun = function(){
     console.log(this.name+"调用了原型对象中的函数|属性:"+this.a);
 }
 ​
 var p1 = new Person("张三",18);
 var p2 = new Person("李四",188);
 var p3 = new Person("王五",1888);
 ​
 p1.afun();
 p2.afun();
 p3.afun();
 console.log(p1.a === p2.a);
 console.log(p2.a === p3.a);

运行结果:

arduino 复制代码
 张三调用了原型对象中的函数|属性:123
 李四调用了原型对象中的函数|属性:123
 王五调用了原型对象中的函数|属性:123
 true
 true

🆗,以上就是JavaScript中对象定义目前方式,可能后续一些框架对此进行了优化不过就基于此升级。 还需要继续学习啊;

JS中的Constructor属性:

网上看了很多Constructor的解释,不同的人有不同的解释,有点花里胡哨,因为本人学过Java所以解释起来也不一定通俗易懂

我们都知道JS的函数也是对象,用来创建对象的函数就是构造函数,万事万物皆对象,所以: 每个对象都有一个属性 constructor 指向对象的'构造函数'

js 复制代码
 <script>
     /**JS中的 constructor */
     function Person(pname, page) { this.name = pname; this.age = page; }
     var p1 = new Person("西宫结弦", 18);
     console.log(p1.constructor === Person);     //true 每个对象都有一个属性 constructor 指向对象的'构造函数'
     console.log(p1.constructor);                //Person(xxx){ xxx }
     console.log(Person.constructor);            //Function() { [native code] }
     console.log(Object.constructor);            //Function() { [native code] }
     console.log(Function.constructor);          //Function() { [native code] }  
     //Function函数是Person函数,同时是自己和Object的构造函数;
     //Function函数和Object函数是JS内置对象,很多官方动作,所以莫名其妙、意想不到的设定无需过分纠结.
 </script>

__proto__constructorprototype 三者之间的区别: 上述Person为例子:

对象的__proto__属性 ,和构造函数的prototype属性 指向一块内存地址

每个对象都具有constructor属性 主要用于表明当前对象是属于具体的基类,涉及到对象的继承,但是JavaScript的继承太复杂,后期有更优化的实现

xml 复制代码
 <script>
     /**
     * 对象的`__proto__`属性 ,和构造函数的`prototype`属性向一块内存地址
     * 对象的`constructor`属性本质来源于`构造函数.prototype.constructor属性`,对象自身没有该属性实例来源原型对象
     */
     console.log(Person.prototype === p1.__proto__);         //true
     console.log(Person.prototype.constructor === Person);   //true
     console.log("instanceof 判断对象类型:".concat(p1 instanceof Person));
 </script>

上述代码,对象自身没有 constructor属性实例来源原型对象: 并不是每个对象具有constructor

原型对象的作用是解决:同一个构造函数创建对象,导致对象的函数内存泄漏问题,而在给对象声明函数时候可能误操作导致,丢失constructor

js 复制代码
 <script>
     //正常构造函数创建对象
     Person.prototype.show = function () { console.log("my name " + this.name); }
     var p2 = new Person("西宫结弦", 18);
     console.log(Person.prototype);
     p2.show();
 ​
     //而,如果需要添加多个函数,则需要频繁的 Person.prototype.xxx 所以: 可能有的人直接这样赋值多个函数
     Person.prototype = {
         constructor: Person,
         show: function () { console.log("我叫" + this.name); },
         sing: function () { console.log("我会唱歌"); },
     }
     var p3 = new Person("西宫结弦", 18);
     console.log(Person.prototype);
     p3.__proto__.show();
     p3.__proto__.sing();        //直接赋值不符合JS的语法规范,所以最好不建议这样使用!!!
 ​
     //instanceof 底层是使用 constructor 进行判断数据类型
     console.log("instanceof 判断对象类型:".concat(p2 instanceof Person));     //false
     console.log("instanceof 判断对象类型:".concat(p3 instanceof Person));     //true
 </script>

hasOwnProperty方法:

实际开发中,我们经常需要判断对象中是否含有某个属性,避免引用对象中没有属性,导致程序报错:

常用判断方式:

  • in 关键字: 上面学习👆👆

  • hasOwnProperty()函数: 和in 的功能类似但是又一点点的区别👇👇

    hasOwnProperty 是 JavaScript 中的一个对象方法

    用于检查一个对象是否拥有特定的属性(不包括从原型链继承而来的属性)

    这个方法可以用来判断一个属性是对象自身的属性,还是继承自原型链的属性

    hasOwnProperty 是 Object.prototype 上的方法因此所有的 JavaScript 对象都可以通过原型链访问到这个方法

js 复制代码
 //初始化一些函数对象信息:
 function Person(pname){
     this.name = pname;
 }
 Person.prototype.gender = '女'
 var p1 = new Person("西宫结弦");
 ​
 //如何判断一个对象中是否存在某个属性呢?
 ​
 /**方式一: in关键字
  *  语法: "属性名" in 对象
  *  in判断对象本身|整个原型链是否含有某个属性
  */
 console.log("p1 对象中是否存在name: "+("name" in p1));      //true
 console.log("p1 对象中是否存在gender: "+("gender" in p1));  //true
 ​
 /**方式二: hasOwnProperty()函数;
  *  语法: 对象.hasOwnProperty("属性名");
  *  hasOwnProperty() 仅判断对象本身是否存在某个属性,并不会判断整个原型
  */
 console.log("p1 对象中是否存在name: "+p1.hasOwnProperty("name"));       //true
 console.log("p1 对象中是否存在gender: "+p1.hasOwnProperty("gender"));   //false

当我们需要判断一个对象,本身是否含有某个对象属性时候,就可以使用:hasOwnProperty()

JavaScript 中的原型链:

上面我们学习,hasOwnProperty() 中提到了原型链:那么什么是原型链呢?

JavaScript是一个基于原型的面向对象语言:

  • 原型链是一种对象之间继承关系的模型,它允许对象通过原型链接共享属性和方法。
  • 每一个对象都有一个隐藏属性: __proto__ 这就是该对象的原型属性

JavaScricp 获取原型对象:

  • 对象.__proto__

    每一个对象的隐藏属性,指向构造函数的原型对象;

  • 构造函数.prototype

    每一个函数对象的隐藏属性,在函数定义时候就存在的原型对象;

  • 对象.constructor.prototype

    一种投机方法,对象.constructor 获取该对象的构造函数 .prototype 可以说和上面无异

  • Object.getPrototypeOf(对象)

    ES5 引入的Object类的方法,比较旧的 JavaScript 环境可能不支持,方法传入对象参数返回该对象的原型对象。

以上述代码为例:

js 复制代码
 /** JavaScript中获取原型对象几种方式 */
 console.log(p1.__proto__);
 console.log(Person.prototype);
 console.log(p1.constructor.prototype);
 console.log(Object.getPrototypeOf(p1));
 console.log(p1.__proto__ === Person.prototype);
 console.log(Person.prototype === p1.constructor.prototype);
 console.log(p1.constructor.prototype === Object.getPrototypeOf(p1));

我们可以使用 hasOwnProperty() 进行验证:

基于 hasOwnProperty() 可以用于判断对象自身是否存在某个属性:

js 复制代码
 /**原型链: 
  *  我们都知道 hasOwnProperty() 可以判断当前对象是否含有某个属性,
  *  而 hasOwnProperty 也是一个对象属性,所以让我们来找一找 p1 对象的原型链吧
 */
 console.log("原型链:");
 //true  通过in确认p1中存在has...属性
 console.log("hasOwnProperty" in p1);
 //false p1中没有has...属性
 console.log(p1.hasOwnProperty("hasOwnProperty"));
 //false p1原型中也没有has...属性
 console.log(p1.__proto__.hasOwnProperty("hasOwnProperty"));
 //true  p1原型的原型中存在has...属性
 //__proto__.__proto__ 原型对象也是对象所以存在 __proto__属性无限套娃^^
 console.log(p1.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));
 ​
 //🆗 打印看一看所有的属性信息:
 console.log(p1);
 console.log(p1.__proto__);
 console.log(p1.__proto__.__proto__);    //p1原型的原型是Object,中存在has...属性
 console.log(p1.__proto__.__proto__.__proto__);  //null: Object的原型已经没有原型了,JS中所有的对象最终都是Object

JavaScript 和 Java面向对象语言类似,一切的起始都是Object

当我们使用一个对象的属性或方法时,会现在自身中寻找

自身中如果有,则直接使用

如果没有则去原型对象中寻找,如果原型对象中有,则使用

如果没有则去原型的原型中寻找,直到找到Object对象的原型

Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined

toString 方法:

和 hasOwnProperty(); 方法类似,该方法也源于:

ObJect的原型对象, 所以JS所有的对象都具有 .toString() 方法;

  • 语法: 对象.toString(); 进行调用

    所有的对象都有 toString() 无参方法,方法会输出对象的详细信息,

    console.log(对象); 默认调用的就是对象的 toString(); 方法.

JavaScript的许多内置对象都重写了该函数,以实现更适合自身的功能需要:

类型 行为描述
Date 返回日期的文本表示。
String 返回 String 对象的值。
Number 返回 Number 的字符串表示。
Error 返回一个包含相关错误信息的字符串。
Boolean 如果布尔值是true,则返回"true"。否则返回"false"。
Object (默认) 返回"[object ObjectName]",其中 ObjectName 是对象类型的名称。
Array 将 Array 的每个元素转换为字符串,并将它们依次连接起来,两个元素之间用英文逗号作为分隔符进行拼接。
Function 返回如下格式的字符串, 其中 xxx 是一个函数的名称 此函数的 toString 方法被调用: "function xxx() { [native code] }"
js 复制代码
 //JavaScript 中常见的内置对象的toString方法...
 //因为: JS本身已经重写了所以输出的值比较适合直接使用;
 var num = 123;
 var blo = true;
 var str = "123";
 var data = new Date();
 ​
 console.log(num);
 console.log(blo);
 console.log(str);
 console.log(data);
 ​
 //JavaScript 中自定义对象类型的toString方法
 //自定义对象并没有重写所以默认输出的都是[object Object],但目前部分浏览器为了方便调试会做处理。
 //JavaScript 中自定义对象类型的toString方法
 //自定义对象并没有重写所以默认输出的都是[object Object],目前部分浏览器为了方便调试会做处理.
 function fun(param){
     this.xxx = param
 }
 var obj = new fun("llll");
 console.log(obj);
 console.log(obj.toString());    //console.log(对象)就调用对象的toString()方法进行输出;

而很多情况为了方便开发,我们需要对象有结构的进行输出展示:

  • 于是,我们可以对自定义对象的,toString() 方法进行重写,
  • 其实就是在构造函数,原型属性中重新定义toString(); 覆盖Object默认方法
js 复制代码
 Fun.prototype.toString = function(){
     return "我是Fun构造函数定义的对象"+this.xxx;
 }
 console.log(obj);
 console.log(obj.toString());    //我是Fun构造函数定义的对象llll

目前一些浏览器运行环境修改了console.log(); 输出的对象以JSON进行展示,所以不方便看到效果,这里也是介绍可以重写原型上的方法();

函数对象的函数:

我们都知道JS中函数也是一种对象,对象具有属性|方法.

函数对象常用方法: call()、apply():用于函数在不同对象上调用,并确保函数内部的this指向正确的对象。

call(o,...)

  • o : [可选],设置的函数上下文,也就是函数内部指向的this对象;
  • ... : [可选],是传递给函数的参数列表,... 表示多参数.
js 复制代码
 //初始化属性|函数数据:
 sysname = "系统计算机";
 function counter(){
     console.log("这是一个:"+this.sysname);
 }
 function counterSay(a,b){
     console.log(this.sysname+"计算结果: "+(a+b));
 }
 //普通调用:
 counter();
 counterSay(1,2);
 ​
 //////////////////////////////////////////////////////////////////////////////////////////////////////
 ​
 //初始化一个默认对象: 为当前要指向的this
 var wsm = { sysname:"wsm的计算机" }
 /**call(o,...):
  * 空参就相当于普通调用
  * call函数用于在不同对象上调用,并确保函数内部的this指向正确的对象
  *      o   :[可选], 设置的函数上下文,也就是函数内部指向的this对象
  *      ... :[可选], 是传递给函数的参数列表,... 表示多参数
  */
 counter.call();             //空参就相当于普通调用
 counter.call(wsm);          //call指定第一个参数对象,为函数内部的this引用:
 counterSay.call(wsm,1,2);
  • Call 确保函数内部的this指向正确的对象

apply(o,[数组])

和Call 函数基本无区别,仅仅是对于参数传递,以数组进行传递(更加灵活方便了吧)

  • o :[可选],设置的函数上下文,也就是函数内部指向的this对象;
  • [数组] : [可选],是传递给函数的参数列表
js 复制代码
 var awsm = { sysname:"awsm的计算机" }
 /**apply(o,[数组])
  * 和Call 函数基本无区别,仅仅是对于参数传递,以数组进行传递.
  *      o     :[可选], 设置的函数上下文,也就是函数内部指向的this对象
  *      [数组] :[可选], 是传递给函数的参数列表
  */
 counter.apply();              //空参就相当于普通调用
 counter.apply(awsm);          //call指定第一个参数对象,为函数内部的this引用:
 counterSay.apply(awsm,[1,2]);

bind(o,...) 改变

arguments 和 this:

我在调用函数时,浏览器每次都会默认传递进隐含的参数: this, 好吧现在又多一个 arguments

函数的上下文对象: this 这里就不详细介绍了

封装实参的对象: arguments:

  • arguments是一个类数组对象
  • 它也可以通过索引来操作数据,也可以获取长度
  • arguments 对象虽然类似于数组,但它并不具有数组的所有方法

我们所传递的实参都会在arguments中保存,我们即使不定义形参,也可以通过arguments来使用实参。

js 复制代码
 function fun(){
     console.log("参数数量: "+arguments.length);
     console.log("第一个参数值: "+arguments[0]);
     console.log("第二个参数值: "+arguments[1]);
     console.log("callee属性就表示函数对象本身: "+arguments.callee==fun);
 }
 fun();
 fun(1,2);
 ​
 //运行结果: 
 参数数量: 0
 第一个参数值: undefined
 第二个参数值: undefined
 true
 ​
 参数数量: 2
 第一个参数值: 1
 第二个参数值: 2
 true

arguments 对象在一些情况下非常有用例如:

当你不确定函数会接收多少个参数时,当你想编写一个可接受不定数量参数的函数时。

js 复制代码
 //arguments可以用于判断实参对象: 实参是方法调用真实传递的参数;
 function fun2(x,xx,xxx){
     console.log(x);
     console.log(xx);
     console.log(xxx);
     console.log("可以准确获取实参数量: "+arguments.length);
 }
 ​
 fun2(1);
 fun2(1,2,3,4);
sh 复制代码
 1
 undefined
 undefined
 可以准确获取实参数量: 1
 ​
 1
 2
 3
 可以准确获取实参数量: 4

this 小总结:

经过上面学习我们又对this,有了新的认识:

  • 以函数形式调用时,this永远都是全局对象 window|global
  • 以方法的形式调用时,this是调用方法的对象
  • 以构造函数的形式调用时,this是新创建的那个对象
  • 使用call()和apply()调用时,this是指定的那个对象

上面说了这么多数组,数组,那么数组到底是什么呢?👇👇👇

JavaScript中的常用对象

我们都知道JS中对象类型有三种: 内建对象、宿主对象、自定义对象;

这里介绍的就是,JavaScript中的内建对象.

数组对象:

简单介绍一下吧,和很多编程语言类似:

数组也是对象的一种,数组是一种用于表达有顺序关系的值的集合的语言结构,也就是同类数据元素的有序集合。

数组的存储性能比普通对象要好,在开发中我们经常使用数组来存储一些数据。

  • 但是在JavaScript中是支持数组可以是不同的元素

    这跟JavaScript的弱类型有关,此处不用纠结,我们大多数时候都是相同类型元素的集合

  • 数组内的各个值被称作元素,每一个元素都可以通过索引(下标)来快速读取,索引是从零开始的整数

new Array创建数组:

JS中以构造函数形式创建数组: 这个构造函数可以接受多种不同的参数,以满足不同的创建需求

  • 不带参数创建空数组

    当你不传递任何参数给构造函数时,它将创建一个空数组。

    js 复制代码
     var arr = new Array();
  • 使用单个参数创建指定长度的空数组

    传递一个单独的参数(整数),构造函数将初始化一个指定长度的空数组,所有的元素都 undefined

    js 复制代码
     // 创建一个长度为5的空数组
     // 虽然这里指定了数组的长度,因为弱语言没有很强的规范,后期依然可以新增|删除,而改变数组长度
     var arrs = new Array(5);
  • 传递多个参数,创建具有初始元素的数组

    js 复制代码
     var arrinit = new Array(1,2,3,4,5);
     console.log(arrinit);

操作数组中的元素: 一下展示的方式比较原始,所以如果已经学习过的小伙伴可以选择跳过;

  • 添加|访问|修改数组元素:

    语法: 数组对象[下标] = 值;

    数组对象[下标] 访问数组下标的元素,如果没有值则返回 undefined

    数组对象[下标] = 值; 如果下标,不存在元素则新增,下标存在元素则进行修改;

    跳跃赋值: 如果我的数组最后一个下标是5,而 数组对象[10] = 值; 则数组的长度直接到10,中间的元素就是 undefined

  • 删除元素: 数组删除元素需要函数删除稍微有一点曲折。

    数组.pop(): 删除数组中首个元素,并返回删除的元素;

    数组.shift(): 删除数组中的末尾元素,并返回删除的元素;

    delete 数组[下标]: 并不能完整删除元素,相当于给该下标的元素赋值,undefined

    数组.splice(x,y,...): 是一个非常强大的数组操作方法,可以用于在数组中执行插入、删除和替换操作 详细介绍👇👇

js 复制代码
 //new Array()初始化空数组
 var arr = new Array();
 arr[0] = "1";
 arr[1] = "2";
 arr[2] = "3";
 console.log(arr);
 console.log(arr.length);
 console.log("获取数组中的第一个元素:"+arr[2]);
 console.log("typeof 查看数组类型:"+(typeof arr));
 ​
 arr[2] = "33";
 console.log("同一个数组[下标]重新赋值就是修改:"+arr[2]);
 arr[10] = "10";
 console.log("跳跃赋值"+arr.length+"因为下标是0开始所以是11,过程下标则是:"+arr[9]);
 ​
 //new Array(x)初始化数组长度数组,但所有的元素都是 undefined
 var arrs = new Array(5);
 console.log(arrs);
 console.log(arrs[0]);
 console.log(arrs.length);
 ​
 //new Array(x,x,x,x)多参初始化,初始元素数组: 删除管理元素;
 var arrinit = new Array(1,2,3,4,5);
 console.log(arrinit.length);
 console.log(arrinit);
 ​
 arrinit.shift();
 console.log(arrinit);           // [ 2, 3, 4, 5 ]
 console.log(arrinit.length);    // 4
 console.log("删除元素,但仅可以删除首位元素并返回删除元素");
 ​
 arrinit.pop();
 console.log(arrinit);           // [ 2, 3, 4 ]
 console.log(arrinit.length);    // 3
 console.log("删除元素,但仅可以删除末位元素并返回删除元素");
 ​
 delete arrinit[1];  
 console.log(arrinit);           // [ 2, <1 empty item>, 4 ]
 console.log(arrinit.length);    // 3
 console.log("并不可以完整删除元素,相当于赋值undefined");
 ​
 /** splice从数组中添加或删除元素 */
 arrinit.splice(1,1);
 console.log(arrinit);           // [ 2, 4 ]
 console.log(arrinit.length);    // 2
 console.log("它接受两个参数,第一个参数是起始索引,第二个参数是要删除的元素数量");

遍历数组中的元素: 循环是数组最常用操作,循环方式也很多:JS原生、数组函数...

js 复制代码
 //原生数组的循环: 
 //本篇就举一个例子吧大差不差,下面还有更简单的数组函数循环 forEach(callback);
 var arrs = ['w','I','l','o','v','e'];
 for (var i = 0; i < arrs.length; i++) {
     console.log(arrs[i]);
 }

字面量创建数组:

目前比较常用的创建方式: 我们都知道数组也是对象的一种,对象可以 new Object();字面量;

本质上二者没有任何区别,后者定义数组更加方便快捷;

  • 语法: var 数组名 = [元素,元素,元素,...]
js 复制代码
 /**字面量形式创建数组: 
  *      你可以直观地定义数组中的元素,使代码更易于阅读和编写. */
 ​
 //创建一个空数组
 var arr = [];
 ​
 //创建一个包含元素的数组
 var arrs = [1,,,4];
 ​
 //创建一个混合类型元素的数组: 数组中的元素可以是任何数据类型;
 var allarr = [1, "apple", true, null, undefined]; 
 ​
 console.log(arr);
 console.log(arrs);
 console.log(allarr);

多维数组:

数组中的元素可以是任何数据类型:数字、字符串、布尔值、对象(而数组也是对象的一种) 所以:

js 复制代码
 /**多维数组:有时候真的觉得JS挺霸道的... */
 var manyarr = [[1,2,3],["1","2","3"],[[],[true,false]]];
 console.log("数组中数组中数组...: "+manyarr);
 console.log("获取多维数组一维第一个元素数组中第一个元素: "+manyarr[0][0]);
 console.log("获取多维数组一维第三个元素维度中第二个数组元素: "+manyarr[2][1][0]);   //实际开发中可能会接触到多用用.

JS数组常用属性|方法:

本篇文章记录的不详细,可以参考官方文档:

JavaScript 数组常用的属性: 已经用过了不详细介绍了

属性 描述 示例
length 返回数组中元素的数量 var numbers = [1, 2, 3]; console.log(numbers.length); // 输出: 3

JavaScript 数组常用的方法:

新增|查询...常用方法:

方法 描述 示例
push(element1,...) 在数组末尾添加一个或多个元素 numbers.push(4); console.log(numbers); // [1, 2, 3, 4]
unshift(element1,...) 在数组开头添加一个或多个元素 numbers.unshift(0); console.log(numbers); // [0, 1, 2, 3, 4]
indexOf(element) 返回指定元素的第一次出现索引 var index = numbers.indexOf(0); console.log(index); // 0
lastIndexOf(element) 返回指定元素的最后一次出现索引 var lastIndex = numbers.lastIndexOf(0); console.log(lastIndex); // 0
slice(start,end) 返回数组的子数组,从索引 start(包含)end - 1 var subArray = numbers.slice(0,2); console.log(subArray); // 0,1
concat(array1,...) 合并一个或多个数组为新数组,并不会拆分内部多维数组 如下👇
join(separator) 将数组元素用,separator分隔符连接为字符串 如下👇

删除常用方法:

方法 描述 示例
pop() 删除并返回数组末尾的元素 var removedElement = numbers.pop();
shift() 删除并返回数组首位的元素 var removedElement = numbers.shift();
js 复制代码
 //初始化数组:
 var numbers = [1,2,3];
 numbers.push(4); 
 numbers.unshift(0);
 console.log(numbers);   // [0, 1, 2, 3, 4]
 console.log("返回指定元素的第一次出现索引: "+numbers.indexOf(0));
 console.log("返回指定元素的最后一次出现索引: "+numbers.lastIndexOf(0));
 console.log("将数组元素用,separator分隔符连接为字符串: "+numbers.join("^"));
 console.log("返回数组的子数组,从索引 start 到 end - 1: "+numbers.slice(0,2));
 ​
 //删除数组前后元素:
 numbers.pop();          //删除末尾元素
 numbers.shift();        //删除首位元素
 console.log(numbers);   //[ 1, 2, 3 ]
 ​
 //多个数组合并新数组: 并不会多维拆分组合...
 var newarr = numbers.concat(["q","qq",["w","ww"]],[true,false]);
 console.log(newarr);

JS数组高级方法使用:

方法 描述
forEach(callback) 遍历数组并执行回调函数
reduce(callback, initialValue) 累积数组元素到单一值
filter(callback) 创建一个新数组,包含满足条件的元素
map(callback) 创建一个新数组,对原数组元素应用回调函数
some(callback) 检测数组中至少有一个元素满足条件,返回boolean类型;
every(callback) 检测数组中是否所有元素满足条件,返回boolean类型;
splice(start, deleteCount, item1, ...) 插入、删除或替换元素,根据参数而进行不同的操作
js 复制代码
 /**数组函数forEach(callback)
  *      方法用于遍历数组中的每个元素,并为每个元素执行提供的回调函数;
  *      回调函数三个参数: 当前元素、[索引]、[当前数组];
 */
 arrs.forEach(function(element,index){
     console.log("当前遍历的元素是: "+element+" ,元素下标: "+index);
 });
 ​
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 ​
 /**reduce(callback, initialValue): 累积数组元素到单一值
  *  实际上是遍历数组中的元素,将它们逐步累积到initialValue值中,
  *  所以: 建议操作的数组元素是有规律的,可以达到你的预期效果.
  **方法接受两个参数: 回调函数,初始值
  *      回调函数callback它接受四个参数: 
  *          初始值、当前遍历元素、[索引]、[当前数组]
  *      初始值initialValue: 
  *          可选值,用作累积的初始值,
  *          如果没有,第一个元素会被当作初始值.
  */ 
 var numbers = [1, 2, 3, 4, 5];
 var sum = numbers.reduce(function(element, currentValue) {
     console.log("初始累计值: "+element+" 当前元素:"+currentValue);
     return element + currentValue;
 },0);
 console.log(sum);                                           //输出: 15
 ​
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 ​
 /**filter(callback): 创建一个新数组,包含满足条件的元素
  *  回调函数接受三个参数: 
  *      当前元素的值、当前元素的索引、整个数组;
  */
 var numbers = [1, 2, 3, 4, 5];
 var evenNumbers = numbers.filter(function(element) {
     return element % 2 === 0;
 });
 console.log(evenNumbers); //输出: [2, 4]
 ​
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 ​
 /**map(callback): 创建一个新数组,其中的每个元素是对原数组中元素应用提供的回调函数的结果
  *  回调函数接受三个参数: 
  *      当前元素的值、当前元素的索引、整个数组;
  */
 //给数组中每个元素进行2次幂提升👆👆
 var numbers = [1, 2, 3];
 var squaredNumbers = numbers.map(function(element) {
     return element * element;
 });
 console.log(squaredNumbers); // 输出: [1, 4, 9]
 ​
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 ​
 /**some(callback): 检测数组中至少有一个元素满足条件,返回boolean类型;
  *  回调函数接受三个参数: 
  *      当前元素的值、当前元素的索引、整个数组;
 */
 //判断数组中是否存在整除2的值;
 var numbers = [1, 2, 3, 4, 5];
 var issome = numbers.some(function(element) {
     return element % 2 === 0;
 });
 console.log(issome); // 2、4满足条件输出: true
 ​
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 ​
 /**every(callback): 检测数组中是否所有元素满足条件,返回boolean类型; 
  *  回调函数接受三个参数:
  *      当前元素的值、当前元素的索引、整个数组;
 */
 //判断数组中是否存在整除2的值;
 var numbers = [1, 2, 3, 4, 5];
 var issome = numbers.every(function(element) {
     return element % 2 === 0;
 });
 console.log(issome); // 1、3、5未满足条件输出: false 

splice(?, ?, ?, ...) 函数:

JavaScript 数组中的一个重要方法: 在指定位置对数组进行插入、删除或替换元素的操作,根据传入的参数来执行不同的操作。

语法: 数组.splice(start, deleteCount, item1, item2, ...);

  • start:必需,指定操作开始的索引位置。
  • deleteCount:可选,要删除的元素数量。如果设置为 0 则不删除任何元素。
  • item1, item2, ...:可选,要插入到数组中的新元素,如果不写则不进行新增元素。
js 复制代码
 /**splice(start,deleteCount,item1, ...)
  * 插入、删除或替换元素,根据参数而进行不同的操作
  * 语法:
  *      数组.splice(start, deleteCount, item1, item2, ...);
  *      start: 必需,指定操作开始的索引位置.
  *      deleteCount: 可选,要删除的元素数量.如果设置为 0则不删除任何元素.
  *      item1,item2,...: 可选,要插入到数组中的新元素,如果不写则不进行新增元素.
  */
 ​
 //插入元素: 在索引2位置插入新元素
 var numbers = [1, 2, 3, 4, 5];
 numbers.splice(2, 0, 'x','xx','xxx');     //最新数组: [1,2,'x','xx','xxx',3,4,5];
 ​
 //删除元素: 将 deleteCount参数设置为要删除的元素数量:下标2,往后3个元素;
 numbers.splice(2,3);                      //返回数组: [1,2,3,4,5]
 ​
 //替换元素: 将 deleteCount参数设置为要删除的元素数量,并在后面添加新的元素;
 //替换元素3,4,5------>'x','xx','xxx'
 numbers.splice(2,3,'x','xx','xxx');       //[1,2,'x','xx','xxx']
  • [] 表示可选值;
  • callback 表示回调函数,一个函数对象,对数组内每个元素进行操作;

Date对象

JavaScript 中使用Date对象来表示时间,允许你创建、表示、操作和格式化日期和时间;

以下是关于 Date 对象的一些重要信息:

创建 Date 对象:

建议按照规范创建时间,符合函数;

js 复制代码
 ​
 /**创建Date对象: */
 var currentDate = new Date();                            // 当前时间
 var specificDate = new Date('2023-08-16');               // 特定日期
 var specificDateTime = new Date('2023-08-16T12:00:00');  // 特定日期和时间
 console.log(currentDate);
 console.log(specificDate);
 console.log(specificDateTime);
 // 使用毫秒数创建,从格林威治标准时间的1970年1月1日开始计算毫秒
 var glwzseconds = new Date(0);   
 var glwzseconds2 = new Date(1629097200000);   
 console.log(glwzseconds);       //1970-01-01T00:00:00.000Z
 console.log(glwzseconds2);      //2021-08-16T07:00:00.000Z

获取日期和时间信息:

使用 Date 对象的方法可以获取年、月、日、小时、分钟、秒等时间信息

因为:JS是外国开发的,所以对于日期获取,他们认为一切从 0 开始所以,0表示1月~

js 复制代码
 /**获取日期和时间信息: */
 var date = new Date();
 var year    = date.getFullYear();     // 当前年份
 var month   = date.getMonth();        // 当前月份 (0-11)
 var day     = date.getDate();         // 当前日期
 var hours   = date.getHours();        // 当前小时
 var minutes = date.getMinutes();      // 当前分钟
 var seconds = date.getSeconds();      // 当前秒数
 console.log(formatDateString(date));
 console.log(cnFormatDateString(date));
 ​
 //因为不同国家的日期格式不同,而又是一个平凡需要转行的操作,所以可以提前定义函数;
 function formatDateString(date) {
     return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
 }
 function cnFormatDateString(date) {
     return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日 ${date.getHours()}时${date.getMinutes()}分${date.getSeconds()}秒`;
 }

日期操作:

使用 Date 对象的方法可以进行日期和时间的加减操作

Date 对象提供了一系列方法,允许你对日期和时间进行加减、设置和获取不同部分的值:

js 复制代码
 /**日期操作:
  * 使用 Date 对象的方法可以进行日期和时间的加减操作 */
 var date = new Date();      // 设置我的生日: 2000-09-09...
 date.setFullYear(2000);     // 设置年份
 date.setMonth(8);           // 设置月份 (0-11)
 date.setDate(9);            // 设置日期
 date.setHours(0);           // 设置小时
 date.setMinutes(0);         // 设置分钟
 date.setSeconds(0);         // 设置秒数
 console.log(cnFormatDateString(date));
 ​
 /**加减日期和时间(就是重新赋值): 我喜欢5:40因为是下班时间...*/
 date.setHours(date.getHours() + 5);         // 增加5小时
 date.setMinutes(date.getMinutes() + 40);    // 增加40分钟
 console.log(cnFormatDateString(date));

时间戳:

时间戳是一种表示日期和时间的方式,它通常是一个数字.

通常是协调世界时(UTC)的1970年1月1日午夜,开始经过的毫秒数、秒数或其他单位的时间量.

在计算机领域,使用时间戳有几个重要的优点:

  • 统一表示: 时间戳提供了一种统一的方式来表示日期和时间,无论你身处不同的时区,时间戳都是相对于一个共同的起点。
  • 方便比较: 时间戳允许你在不同的时间点之间进行比较,因为它们都是基于相同的起点进行计算的。
  • 精确性: 时间戳通常使用毫秒或秒为单位,提供了非常高的精确性,适用于需要精确计时的应用。
  • 时间差计算: 通过比较不同时间戳之间的差值,你可以计算时间间隔、持续时间等。

利用时间戳来测试代码的执行的性能: 获取时间戳的几种方式:

  • getTime()Date 对象的方法,直接表示获取时间的操作
  • valueOf() 方法也是 Date 对象的方法, JavaScript 内部用于类型转换的通用方法
  • Date.now() 是一个 Date 对象的静态方法,它直接返回当前时间的时间戳,不需要先创建一个 Date 对象,常用⭐
js 复制代码
 /**时间戳: */
 var currentDate = new Date();
 var timestampUsingGetTime = currentDate.getTime();  // 使用 getTime() 方法
 var timestampUsingValueOf = currentDate.valueOf();  // 使用 valueOf() 方法
 console.log(Date.now());  // 输出时间戳
 console.log(timestampUsingGetTime);  // 输出时间戳
 console.log(timestampUsingValueOf);  // 输出时间戳
 ​
 /**利用时间戳来测试代码的执行的性能: */
 var start = Date.now(); 
 for(var i=0 ; i<100 ; i++){ console.log(i); } 
 var end = Date.now();
 console.log("执行了:"+end+"-"+start+"="+(end - start)+"毫秒");

Math数学对象:

Math和其它的对象不同,它不是一个构造函数,它属于一个工具类不用创建对象,它里边封装了数学运算相关的属性和方法。

js 复制代码
 /*固定值*/
 console.log("圆周率 π 的近似值: "+Math.PI);
 console.log("自然对数的底数 e 的近似值: "+Math.E);
 console.log("===============");
 ​
 /*基本数学方法*/
 console.log(Math.abs(1));        //可以用来计算一个数的绝对值
 console.log(Math.round(1.4));    //可以对一个数进行四舍五入取整
 console.log(Math.ceil(1.1));     //可以对一个数进行向上取整,小数位只有有值就自动进1
 console.log(Math.floor(1.99));   //可以对一个数进行向下取整,小数部分会被舍掉
 console.log(Math.min(1,2,3,4,5,6)); //返回传入参数的最小值
 console.log(Math.max(1,2,3,4,5,6)); //返回传入参数的最大值
 console.log("===============");
 ​
 /*随机数*/
 //Math.random():可以用来生成一个0-1之间的随机数
 //生成一个0-x之间的随机数:Math.round(Math.random()*x)
 //生成一个x-y之间的随机数:Math.round(Math.random()*(y-x)+x)
 console.log(Math.round(Math.random() * 10));            //生成一个0-10之间的随机数
 console.log(Math.round(Math.random() * (10 - 1) + 1));  //生成一个1-10之间的随机数
 console.log("===============");
 ​
 /*指数和对数方法*/
 console.log(Math.pow(2,2));         //Math.pow(x,y)返回 x 的 y 次幂.
 console.log(Math.sqrt(9));          //Math.sqrt(x) 返回 x 的平方根.
  • Math.sign(x) JS中 Math 对象提供的一个方法,它用于判断一个数 x 的符号;

    如果 x 是零,返回 0

    如果 x 是正数,返回 1

    如果 x 是负数,返回 -1

    如果 x 不是一个有效的数字(NaN),返回 NaN

  • 方法在处理数值时非常有用,可以帮助我们判断一个数的正负性.

自然对数的底数:

自然对数的底数 "e"

  • "e" 是一个无理数,它的小数部分是无限不循环的,所以通常我们使用它的近似值 2.71828 来进行计算
js 复制代码
 console.log(Math.exp(1));           //Math.exp(x)  返回 e 的 x 次幂(e^1)
 console.log(Math.log(9));           //Math.log(x)  返回 x 的自然对数(e^y = 9)
 ​
 //也就是说:console.log(Math.exp(Math.log(x)));  结果就是 x

三角函数:

实际开发过程中用的不多,这里就简单介绍一下吧,需要在进行研究:

  • Math.sin(x):返回 x 的正弦值
  • Math.cos(x):返回 x 的余弦值
  • Math.tan(x):返回 x 的正切值
  • Math.atan(x):返回 x 的反正切值

JavaScript中的包装类:

包装类Wrapper Classes)是一种特殊的对象,将基本数据类型:数字、字符串、布尔值转换为对象.

允许基本数据类型在某些情况下可以像对象一样进行操作:

Number包装类

js 复制代码
 /**Number 
  * Number 包装类用于将基本的数值类型转换为对象,允许你在数值上调用一些方法*/
 var num = 5;
 var numObject = new Number(num);    // 使用构造函数创建 Number 对象
 console.log(numObject.toFixed(2));  // 将数字转为字符串并按指定小数位数四舍五入
 console.log(numObject.toString(10)) // 将数字转为字符串并可以指定进制例如:二进制、八进制、十进制(默认)、十六进制)
 console.log(numObject.toString(2));
 ​
 //Number.parseFloat(str): 将字符串转换为浮点数(小数);
 var strn = "3.14";
 var nstr = Number.parseFloat(strn);
 console.log("转换前的值:"+strn+"数值类型:"+(typeof strn));
 console.log("转换后的值:"+nstr+"数值类型:"+(typeof nstr));
 ​
 //Number.parseInt(str,base): 方法将字符串转换为整数,同时可以指定字符串所表示的进制base:默认十进制)
 //123的二进制字符串
 var strbinary = "01111011";
 var nbinary = Number.parseInt(strbinary);
 var nbinary2 = Number.parseInt(strbinary,2);
 console.log("转换前的值:"+strbinary+"数值类型:"+(typeof strbinary));
 console.log("转换后的值:"+nbinary+"数值类型:"+(typeof nbinary)+"默认进制展示:"+nbinary);        //1111011
 console.log("转换后的值:"+nbinary2+"数值类型:"+(typeof nbinary2)+"二进制转换后返回:"+nbinary2);  //123

常用的构造函数:

  • 语法: new Number(x);

常用的方法:

  • Number.toString(base):将数字转为字符串,并可以指定进制(例如,二进制、八进制、十六进制)
  • Number.toFixed(digits):将数字转为字符串,并按指定小数位数四舍五入
  • Number.parseFloat(str):将字符串转为浮点数
  • Number.parseInt(str, base):将字符串转为整数

String包装类:

简单介绍一下🙃🙃🙃...

js 复制代码
 /**String 
  * 包装类用于将基本的字符串类型转换为对象,允许你在字符串上调用一些方法 */
 var str = new String("Hello World");
 console.log("String.length返回字符串的长度:"+str.length);
 console.log("toUpperCase字符串转为大写:"+str.toUpperCase());
 console.log("toLowerCase字符串转为小写:"+str.toLowerCase());
 console.log("charAt(index)返回指定索引位置的字符:"+str.charAt(0));
 console.log("indexOf(searchValue,startIndex)"+
     "searchValue: 要查找的子字符串."+
     "startIndex(可选): 从指定索引开始查找,默认从字符串开头开始查找."+str.indexOf("lo",0));

Boolean包装类:

Boolean 包装类提供的方法相对较少,因为布尔值本身不需要太多的处理。其中,最常用的方法是:

  • Boolean.valueOf():返回布尔对象的基本布尔值(true 或 false)
js 复制代码
 /**Boolean 
  *  包装类用于将基本的布尔类型转换为对象,允许你在布尔值上调用一些方法*/
 var boolObjt = new Boolean(true);
 var boolObjf = new Boolean(false);
 //获取布尔对象的基本布尔值
 console.log(boolObjt.valueOf());    //true
 console.log(boolObjt.valueOf());    //false
 ​
 //注意new Boolean 返回的对象并没有false|true区别所以:
 //if(只要有对象就会返回true指向)
 var a = "123";
 if(a) console.log(a);
 if(boolObjt) console.log(boolObjt);
 if(boolObjf) console.log(boolObjf);

自动类型转换:

JavaScript 允许你在基本数据类型上使用包装类的方法

因为:底层JavaScript 会自动将基本数据类型转换为对应的包装对象,然后执行操作,最后将结果再转换回基本数据类型。

js 复制代码
 var num = 5;
 var rounded = num.toFixed(2);  // 自动转换为 Number 对象,并执行操作.
 console.log(rounded);
相关推荐
前端小小王15 分钟前
React Hooks
前端·javascript·react.js
迷途小码农零零发25 分钟前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀1 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪1 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef3 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6413 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻4 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云4 小时前
npm淘宝镜像
前端·npm·node.js
dz88i84 小时前
修改npm镜像源
前端·npm·node.js
Jiaberrr4 小时前
解锁 GitBook 的奥秘:从入门到精通之旅
前端·gitbook