JS的变量类型
简单数据类型:或值类型,或基本类型。其中包含:String、Number(数值)、Boolean(布尔值)、Undefined、Null、Symbol (ES6)。
布尔类型
布尔表示一个逻辑实体,可以有两个值:true 和 false。更多详情可查看 Boolean 和 Boolean。
Null 类型
Null 类型只有一个值:null,更多详情可查看 null 和 Null。
Undefined 类型
一个没有被赋值的变量会有个默认值 undefined,典型用法是:(1)变量被声明了,但没有赋值时,就等于undefined。(2)调用函数时,应该提供的参数没有提供,该参数等于undefined。(3)对象没有赋值的属性,该属性的值为undefined。(4)函数没有返回值时,默认返回undefined。
数字类型
ECMAScript 标准定义了两种内建数值类型:Number(数字类型)和 BigInt。数字类型除了能够表示浮点数外,还有三个带符号的值:+Infinity、-Infinity 和 NaN
BigInt 类型
BigInt 类型是 JavaScript 中的一个基础的数值类型,可以表示任意精度的整数。使用 BigInt,您可以安全地存储和操作大整数,甚至可以超过数字类型的安全整数限制。
字符串类型
JavaScript 的字符串类型用于表示文本数据。它是一组 16 位的无符号整数值的“元素”。在字符串中的每个元素占据了字符串的位置。第一个元素的索引为 0,下一个是索引 1,依此类推。字符串的长度是它的元素的数量。
null 表示“没有对象”。典型用法是:(1)作为函数的参数,表示该函数的参数不是对象。(2)作为对象原型链的重点。
符号类型
符号(Symbols)类型是唯一且不可修改的原始值,并且可以用来作为对象的键 (key)(如下),在某些语言当中也有与之相似的类型(原子类型,atoms)。
更多详情可查看 Symbol 和 Symbol。
let hd = Symbol("后盾人");
console.log(hd); //Symbol(后盾人)
console.log(hd.description); //后盾人
let hd1 = Symbol("后盾人");
console.log(hd == hd1); //false
let cms = Symbol.for("hdcms");
let edu = Symbol.for("hdcms");
console.log(cms == edu); //true
复杂数据类型:或引用类型 Object(对象)。
函数:
函数是一个附带可被调用功能的常规对象。
日期
当你想要显示日期时,毋庸置疑,使用 JavaScript 内建的 Date 对象。
数组
是一种使用整数作为键(integer-keyed)属性并与长度(length)属性关联的常规对象。
此外,数组对象还继承了 Array.prototype 的一些操作数组的便捷方法。例如,indexOf()(搜索数组中的一个值)或 push()(向数组中添加一个元素),等等。这使得数组是表示列表或集合的最优选择。
使用 typeof 操作符判断对象类型
简单与复杂类型的区别:
1.在赋值时,基本类型将A的值赋值给B;引用类型将A的地址赋值给B
2.基本类型的变量内部存储的是值本身;引用类型的变量中存储的是指向对象的一个地址
3.值类型无法添加属性和方法,引用类型可以添加属性和方法
4.两个变量之间的比较(值,地址)
深拷贝与浅拷贝
首先,深拷贝和浅拷贝是针对对象属性为对象的,因为基本数据类型在进行赋值操作时(也就是拷贝)是直接将值赋给了新的变量,也就是该变量是原变量的一个副本,这个时候你修改两者中的任何一个的值都不会影响另一个,而对于对象或者引用数据来说在进行浅拷贝时,只是将对象的引用复制了一份,也就内存地址,即两个不同的变量指向了同一个内存地址,那么在改变任一个变量的值都是该变这个内存地址的所存储的值,所以两个变量的值都会改变。深拷贝和浅拷贝,主要是对象发生复制的时候,根据复制的层级不同来区分的。
原文链接:
解决办法:
1.使用JSON,不能复制undefined和function
2.使用Object.assign,只能拷贝一级属性;
3.使用扩展运算符,只能拷贝一级属性;
4.使用第三方库
5.使用递归
<script>
let a = {
name: "monica",
age: 18,
hobby: {
tiyu: "paodu",
study: "read",
},
};
//let b = a;
// 1.使用JSON,不能复制undefined和function
//let b = JSON.parse(JSON.stringify(a));
// 2.使用Object.assign,只能拷贝一级属性;
//let b = Object.assign({}, a);
// 3.使用扩展运算符,只能拷贝一级属性;
//let b = {...a};
// 4.使用第三方库
// 5.使用递归
b.name = "lihua";
console.log(a);
console.log(b);
变量计算
类型转换
转换为字符串类型:
var num1 = 1;
console.log(num1.toString());
var num2 = 1;
console.log(String(num2));
var num3 = 1;
console.log(num3 + "我是字符串");
转换为数字类型:
console.log(parseInt("78"));
console.log(Number("12"));
console.log("12" - 0);
转换为布尔类型:
console.log(Boolean(""));
console.log(Boolean(0));
console.log(Boolean(null));
console.log(Boolean(undefined));
console.log(Boolean(NaN));
Var、let、const 的区别
共同点:可以声明变量;
区别:
- var 声明的变量会被提升到函数作用域的顶部,let 和 const 声明的变量不存在提升,且具有暂时性死区特征
console.log(temp);//undefined
var temp = 10;
- var 允许在同一个作用域中重复声明同一个变量,let 和 const 不允许
var num = 1;
var num = 2;
console.log(num);
- var 声明的范围是函数作用域,let 和 const 声明的范围是块作用域
- const 的行为与 let 基本相同,唯一 一个重要的区别是,使用 const 声明的变量必须进行初始化,且不能被修改
- 在全局作用域中使用 var 声明的变量会成为 window 对象的属性,let 和 const 声明的变量则不会
var num = 1;
console.log(window.num);//1
let num1 = 1;
console.log(window.num1);//undefined
函数作用域:
1.例子:
var a = "apple";
function fighting() {
var a = "angle";
}
console.log(a);//apple
var a = "apple";
if (true) {
var a = "angle";
}
console.log(a);//angle 注意还有for、while
作用域链:从里到外找(就近原则)
var a = "apple";
var b = "boy";
function fighting() {
var a = "angle";
console.log(a);//angle
console.log(b);//boy
}
fighting();
console.log(a);//apple
声明提升:函数声明,变量。
var a = "apple";
function fighting() {
console.log(a); //undefined
var a = "angle";
console.log(ss()); //angle
function ss() {
return a;
}
}
fighting();
细节:
1. 形参为局部变量,在{ } 内部访问
2.
var a = c = 8;//var a ; a=c=8; c为全局变量
3.
for (var i = 0; i < 5; i++) {
console.log(i);//0 1 2 3 4
}
console.log(i);//5
块级作用域:
包括在{ }里面的,例如: if for...,除了对象var person = {name:"apple"}
for (let i = 0; i < 5; i++) {
console.log(i);//0 1 2 3 4
}
console.log(i);// 报错
闭包:
什么是闭包(Closure) 简单讲,闭包就是能够读取其他函数内部局部变量的函数。
function fn(){
var num = 10;
function fun(){
console.log(num);
}
fun();
}
fn();// 10
作用 延伸了变量的作用范围,在函数外面的作用域可以访问函数内部的局部变量注意点 局部变量会等所有的函数都调用完毕,才会销毁
性能考量 如果不是某些特定任务需要使用闭包,在其它函数中创建函数是不明智的,因为闭包在处理速度和内存消耗方面对脚本性能具有负面影响。
js基础:什么是闭包,教育,学校教育,好看视频 (baidu.com)
this:
1. 什么的this?
this,从字面上含义是(指较近的人或事物) 这,这个;
this:表示当前对象的一个引用。 this的指向:this不是固定不变的,是根据调用的上下文(执行时环境)改变而改变。
- 如果单独使用,this 表示全局对象。
- 在方法中,this 表示该方法所属的对象。
- 在函数中,this 表示全局对象。
- 在函数中,在严格模式下,this 是未定义的(undefined)。
- 在事件中,this 表示接收事件的元素。
异步操作:
并发:计算机能够同时执行多项任务。
并行:多核。
异步:不同的任务不需要相互等待,先后进行。(多线程编程)
同步:前一个任务进行完成,进行下一个任务。(无并发或并行概念)
JS本身没有多线程的概念,通过它的函数回调机制,能够做到单线程的并发。
多线程编程:适用于计算量密集的应用、视频图像处理,科学计算等。
单线程的异步编程:I/O密集的应用程序,比如web应用,经常执行网络操作、数据库访问,这种非常实用单线程的异步编程。如果使用多线程编程,浪费资源,因为每一个现场的绝大多数时间都是在等待I/O操作,线程自身也会占用额外的内存,线程的切换也会有额外的开销。
什么是异步操作?
比如任务A、B、C,执行A之后执行B,但是B是一个耗时的工作,所以,把B放在任务队列中,去执行C,然后B的一些I/O等返回结果之后,再去执行B,这就是异步操作。
JavaScript为什么需要异步操作?
JavaScript语言的执行环境是“单线程”, 所谓单线程,就是一次只能完成一件任务, 如果有多个任务就需要排队,一个完成了,继续下一个,这种方式在实现来说是非常简单的,但是如果一个任务耗时很长,那么后面的任务就需要排队等着,会拖延整个程序的执行。 常见的浏览器无响应(假死)就是因为某一段JavaScript代码长时间运行(比如死循环),导致整个页面卡死,其他任务无法执行。
javascript的异步操作方法有:
1、回调函数;2、事件监听;3、“发布/订阅”模式;4、promise;5、generator;6、“async/await”。
利用setTImeout才能做出真正的回调函数
function f1(callback){
setTimeout(function () {
// f1的任务代码
callback();
}, 1000);
}
f1(f2);
f3();
由于是异步的,那么f3()就会很快的得到执行,而不会受到f1和f2的影响。
另一种异步的思路是采用事件驱动模式。
function f1(){
setTimeout(function () {
// f1的任务代码
f1.trigger('done');
}, 1000);
}
f1.on('done', f2);
f3()