js中的数据类型分为基本数据类型和引用数据类型
基本数据类型(原始类型)包括——(存储在栈内存中):
- 数字类型(Number):表示数字,包括整数和浮点数
- 字符串类型(String):表示文本字符串
- 布尔类型(Boolean):表示真或假
- 空类型(Null):表述空值
- 未定义(undefined):表示未定义的值
- 符号(Symbol):唯一的标识符
引用数据类型(对象类型)包括——(存储在堆内存中):
- 对象类型(Object):表示复杂数据类型,包括数组、函数、日期、正则表达式等。
- 数组类型(Array):表示一组有序的数据。
- 函数类型(Function):表示可执行的代码块
- 正则表达式(RegExp):用于匹配字符串的模式
存储的差别?
基本数据类型存储在栈内存中,而引用数据类型存储在堆内存中。
栈内存是一种临时存储区域,用于存储基本数据类型的值和引用数据类型的引用地址。堆内存是一种动态分配的内存区域,用于存储引用数据类型的实际数据。
当一个变量存储的是基本数据类型时,它的值直接存储在栈内存中;当一个变量存储的是引用数据类型时,它的值是一个指向堆内存中实际数据的地址。
使用typeof
运算符: 可以使用typeof
运算符来确定一个值的数据类型。它返回一个表示数据类型的字符串。例如:
console.log(typeof 42); // 输出 "number"
console.log(typeof "Hello"); // 输出 "string"
console.log(typeof true); // 输出 "boolean"
使用instanceof
运算符: instanceof
运算符可以用来检查对象是否属于某个特定的构造函数。例如:
const arr = [1, 2, 3];
console.log(arr instanceof Array); // 输出 "true"
使用Array.isArray()
方法: Array.isArray()
方法用于检查一个值是否为数组类型。例如:
console.log(Array.isArray([1, 2, 3])); // 输出 "true"
使用Object.prototype.toString
方法: 可以通过调用Object.prototype.toString
方法并将要检查的值作为参数传入,来获取其精确的数据类型信息。例如:
console.log(Object.prototype.toString.call(42)); // 输出 "[object Number]"
console.log(Object.prototype.toString.call("Hello")); // 输出 "[object String]"
转换为字符串(String)类型:
使用**toString()和String()**方法:toString不可以转undefined,null
let num = 42;
let str1 = String(num);
let str2 = num.toString();
转换为数字(Number)类型:
使用Number()和parseInt()等方法:
let str = "42";
let num1 = Number(str);
let num2 = parseInt(str); // 解析整数
let num3 = parseFloat("3.14"); // 解析浮点数
转换为布尔(Boolean)类型:
使用Boolean()函数:
let a = 42;
let b = ""; // 空字符串
let bool1 = Boolean(a); // true
let bool2 = Boolean(b); // false
转换为数组(Array)类型:
使用Array.from()方法将类似数组的对象转换为真正的数组:
let arrayLikeObj = { 0: "a", 1: "b", length: 2 };
let arr = Array.from(arrayLikeObj); // ["a", "b"]
转换为对象(Object)类型:
使用对象字面量或构造函数进行对象的创建:
let obj1 = {}; // 空对象
let obj2 = new Object();
变量提升是 JavaScript 中的一种特性,它是指在代码执行前,JavaScript 引擎会将变量和函数的声明提升到其所在作用域的顶部。这意味着可以在声明之前访问这些变量或函数。
在 JavaScript 中,变量提升主要包括两个方面:
变量声明的提升: 变量声明使用 var
、let
或 const
关键字进行,而变量的赋值操作则不会被提升。如果在代码中先使用了一个变量,然后才进行声明,JavaScript 会将该声明提升到作用域的顶部。但是变量的初始值仍然是 undefined
。例如:
console.log(foo); // 输出 undefined
var foo = "Hello";
函数声明的提升: JavaScript 中的函数可以先使用后声明,因为函数声明也会被提升到作用域的顶部。这意味着你可以在函数声明之前调用函数。例如:
greet(); // 输出 "Hello"
function greet() {
console.log("Hello");
}
需要注意的是,变量提升只会提升声明,而不会提升赋值操作。如果变量没有使用 var
、let
或 const
声明,它将被视为全局对象的属性。此外,使用 let
和 const
声明的变量在块级作用域内存在暂时性死区(TDZ),也会影响到变量的提升行为。
添加:
push()
接受任意数量的参数,并且将它们添加至数组的末尾,返回数组的最新长度unshift()
在数组开头添加任意多个值,然后返回新的数组长度splice()
传入三个参数,分别是开始位置、0(要删除的元素数量)、插入的元素,返回空数组concat()
首先会创建一个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新构建的数组,不会影响原始数组删除:
pop()
方法用于删除数组的最后一项,同时减少数组的length 值,返回被删除的项shift()
方法用于删除数组的第一项,同时减少数组的length 值,返回被删除的项splice()
传入两个参数,分别是开始位置,删除元素的数量,返回包含删除元素的数组slice()
用于创建一个包含原有数组中一个或多个元素的新数组,不会影响原始数组修改:
splice()
传入三个参数,分别是开始位置,要删除元素的数量,要插入的任意多个元素,返回删除元素的数组,对原数组产生影响查找:
indexOf()
返回要查找的元素在数组中的位置,如果没找到则返回-1includes()
返回要查找的元素在数组中的位置,找到返回true,否则falsefind()
返回第一个匹配的元素排序:
reverse()
顾名思义,将数组元素方向反转sort()
方法接受一个比较函数,用于判断哪个值应该排在前面转换:
join()
方法接收一个参数,即字符串分隔符,返回包含所有项的字符串迭代方法:
some()
对数组每一项都运行传入的测试函数,如果至少有1个元素返回 true ,则这个方法返回 trueevery()
对数组每一项都运行传入的测试函数,如果所有元素都返回 true ,则这个方法返回 trueforEach()
对数组每一项都运行传入的函数,没有返回值filter()
对数组每一项都运行传入的函数,函数返回 true的项会组成数组之后返回map()
对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组
这里是引用
使用 Set 数据结构:Set 对象存储唯一值的集合,可以将数组转换为 Set,然后再将 Set 转回数组即可去重。例如:
const arr = [1, 2, 2, 3, 3, 4, 5, 5];
const uniqueArr = [...new Set(arr)];
console.log(uniqueArr); // 输出 [1, 2, 3, 4, 5]
使用 filter() 方法结合 indexOf() 方法:利用数组的 filter() 方法和 indexOf() 方法,对数组进行遍历筛选,只保留首次出现的元素。例如:
const arr = [1, 2, 2, 3, 3, 4, 5, 5];
const uniqueArr = arr.filter((item, index) => arr.indexOf(item) === index);
console.log(uniqueArr); // 输出 [1, 2, 3, 4, 5]
使用 reduce() 方法:利用数组的 reduce() 方法,遍历数组,将不重复的元素放入新的数组。例如:
创建一个空对象 (或者使用已存在的对象)。
const arr = [1, 2, 2, 3, 3, 4, 5, 5];
const uniqueArr = arr.reduce((acc, curr) => {
if (!acc.includes(curr)) {
acc.push(curr);
}
return acc;
}, []);
console.log(uniqueArr); // 输出 [1, 2, 3, 4, 5]
遍历数组,对于每个元素进行以下操作:
将数组元素作为对象的属性名。
将任意值(比如 true)作为属性值,以标记该元素已经出现过。
提取对象的所有属性名,组成新的数组,即为去重后的数组。
javascript复制代码const arr = [1, 2, 2, 3, 3, 4, 5, 5];
const obj = {};
const uniqueArr = [];
arr.forEach(item => {
if (!obj[item]) {
obj[item] = true;
uniqueArr.push(item);
}
});
console.log(uniqueArr); // 输出 [1, 2, 3, 4, 5]
在上述代码中,obj
对象用于存储数组元素是否已经出现过。遍历数组时,如果当前元素不在 obj
对象中,则将其添加到 uniqueArr
数组中,并将 obj[item]
设置为 true
标记已经出现过。这样就可以通过对象的属性来实现数组去重。
尾递归是指一个函数在调用自身之后不再执行任何其他操作,而是将返回值直接传递给函数调用的上级,从而避免了新的调用栈帧的创建。换句话说,尾递归是指递归调用发生在函数的最后一个语句中,从而使得函数调用不需要保存多个调用栈帧,而只需一个即可。
数组扁平化是指将多维数组转换为一维数组的操作。在 JavaScript 中,我们可以使用多种方式来实现数组的扁平化。
const arr = [1, 2, [3, [4, 5]], 6]
console.log(arr.flat(Infinity));
const arr = [1, [2, [3, [4, 5],9]], 6]
function flatten(arr) {
// 使用正则表达式匹配字符,并替换
let arr1 = JSON.stringify(arr).replace(/\[|\]/g, '')
return JSON.parse('[' + arr1 + ']')
}
console.log(flatten(arr));
const arr = [1, [2, [3, [4, 5]]], 6]
var array = []
function flatten(arr) {
// 判断是否是数组
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
flatten(arr[i])
}
else {
array.push(arr[i])
}
}
return array
}
console.log(flatten(arr));
const arr = [1, [2, [3, [4, 5]]], 6]
var array = []
function flatten(arr) {
return arr.reduce((sum, value) => {
return sum.concat(Array.isArray(value) ? flatten(value) : value)
}, [])
}
console.log(flatten(arr));
const arr = [1, [2, [3, [4, 5]]], 6]
function flat(arr) {
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
console.log(flat(arr));
1.去除字符串首尾的空格
trim()
2.去除字符串中所有的空格
相当于去除字符串中所有的空字符,可以使用 replace(),
3.使用正则去除你想去掉的空格
正则表达式(RegEx)
- 创建一个空对象,并且
this
变量引用该对象,同时还继承了该函数的原型- 属性和方法被加入到
this
引用的对象中- 新创建的对象由
this
所引用,并且最后隐式的返回this
创建一个新的对象obj,将对象与构建函数通过原型链连接起来,将构建函数中的this绑定到新建的对象obj上,根据构建函数返回类型作判断,如果是原始值则被忽略,如果是返回对象,需要正常处理。
事件委托(event delegation)和事件代理(event delegation)是指同一种概念,在 JavaScript 中常用于处理事件的优化和性能提升。
事件委托/代理基本思想如下:
通过事件委托/代理的方式,可以实现以下几个好处:
事件冒泡:
事件捕获:
addEventListener
)在 JavaScript 中,事件捕获是事件传播的一种阶段,它发生在事件冒泡之前。要开启事件捕获阶段,可以使用 addEventListener
方法的第三个参数,将其设置为 true
。
示例代码如下所示:
var element = document.getElementById('myElement');
element.addEventListener('click', function(event) {
console.log('捕获阶段');
}, true);
在上述示例中,我们通过将 addEventListener
的第三个参数设置为 true
,即开启了捕获阶段。当在 myElement
元素上触发 click 事件时,会先执行在捕获阶段注册的事件处理函数。
需要注意的是,大多数情况下不必显式开启捕获阶段,因为默认情况下事件会在冒泡阶段进行处理。捕获阶段和冒泡阶段共同构成了事件传播的过程。
总结起来:
默认情况下,事件会在冒泡阶段进行处理。如果需要开启捕获阶段,可以将 addEventListener
方法的第三个参数设置为 true
。
在 JavaScript 中,要阻止事件冒泡(即停止事件向父元素的传播),可以使用 event.stopPropagation()
方法。
示例代码如下所示:
var element = document.getElementById('myElement');
element.addEventListener('click', function(event) {
event.stopPropagation(); // 阻止事件冒泡
console.log('点击了子元素');
});
document.addEventListener('click', function(event) {
console.log('点击了文档');
});
在上述示例中,当点击 myElement
元素时,会触发子元素的点击事件处理函数,并输出 “点击了子元素”。由于调用了 event.stopPropagation()
,事件不会继续向上层元素传播,因此不会触发文档上的点击事件处理函数。
需要注意的是,event.stopPropagation()
只能阻止事件在当前元素及其祖先元素之间的传播,无法阻止事件在同级元素之间的传播。如果希望完全取消事件的传播,包括同级元素,可以使用 event.stopImmediatePropagation()
方法。
总结起来:
event.stopPropagation()
用于阻止事件冒泡,只影响当前元素及其祖先元素之间的传播。event.stopImmediatePropagation()
用于完全取消事件的传播,包括同级元素。请注意,以上操作是按照默认的事件冒泡阶段进行处理的。如果在捕获阶段注册了事件处理函数,并且希望阻止捕获阶段中的事件传播,可以在捕获阶段的事件处理函数中使用 event.stopPropagation()
或 event.stopImmediatePropagation()
方法。
JavaScript 中的 number 类型就是浮点型,JavaScript 中的浮点数采用IEEE-754
格式的规定,这是一种二进制表示法,可以精确地表示分数,比如 1/2,1/8,1/1024,每个浮点数占 64 位。但是,二进制浮点数表示法并不能精确的表示类似 0.1 这样 的简单的数字,会有舍入误差。
由于采用二进制,JavaScript 也不能有限表示 1/10、1/2 等这样的分数。在二进制中,1/10(0.1)被表示为 0.00110011001100110011…… 注意 0011 是无限重复的,这是舍入误差造成的,所以对于 0.1 + 0.2 这样的运算,操作数会先被转成二进制,然后再计算
在 JavaScript 中,可以使用 Math.max()
方法或数组的 sort()
方法来获取数组中的最大值。
使用 Math.max()
方法: Math.max()
方法接受一组数字作为参数,并返回其中的最大值。但是,Math.max()
方法不接受数组作为参数,需要使用展开运算符 ...
将数组元素展开为单独的参数传递给该方法。
示例代码如下:
const numbers = [10, 5, 8, 3, 12];
const maxNumber = Math.max(...numbers);
console.log(maxNumber); // 输出:12
使用 sort()
方法: sort()
方法用于对数组进行排序,默认是按照字符编码的顺序排序。通过自定义比较函数,可以实现对数字类型的排序。使用 sort()
方法将数组排序后,最后一个元素即为数组中的最大值。
示例代码如下:
const numbers = [10, 5, 8, 3, 12];
numbers.sort((a, b) => a - b); // 升序排序
const maxNumber = numbers[numbers.length - 1];
console.log(maxNumber); // 输出:12
请注意,使用 sort()
方法会改变原始数组的顺序,如果不想改变原数组,可以先创建副本进行操作。
以上就是获取数组中最大值的方法,根据需求选择合适的方式进行处理。
===:三个等号我们称为等同符,当等号两边的值为相同类型的时候,直接比较等号两边的值,值相同则返回true,若等号两边的值类型不同时直接返回false。
例:
100===“100” //返回falseabc===“abc” //返回false
‘abc’===“abc” //返回true
NaN===NaN //返回false
false===false //返回true
==:两个等号我们称为等值符,当等号两边的值为相同类型时比较值是否相同,类型不同时会发生类型的自动转换,转换为相同的类型后再作比较。
1、原型链继承
2、构造函数继承
3、实例继承
4、拷贝继承
5、组合继承
6、寄生组合继承
浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝。
如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址
即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址
在JavaScript中,存在浅拷贝的现象有:
深拷贝就是开辟一个新的栈,两个对象的属性完全相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。
常见的深拷贝方式有:
同步任务 在主线程上排队执行的任务,只有前一个任务执行完毕之后,才会执行下一个任务
异步任务 不进入主线程,而进入 任务队列
的任务,只有等主线程的任务执行完毕,任务队列
开始通知主线程请求执行任务,该任务才会进入主线程执行。
简单来说,同步是阻塞式的,需要等待操作完成后才能进行下一步操作,而异步是非阻塞式的,不需要等待操作完成就可以进行下一步操作。
当在Javascript中使用一个变量的时候,首先Javascript引擎会尝试在当前作用域下去寻找该变量,如果没找到,再到它的上层作用域寻找,以此类推直到找到该变量或是已经到了全局作用域
如果在全局作用域里仍然找不到该变量,它就会在全局范围内隐式声明该变量(非严格模式下)或是直接报错
typeof运算符和instanceof运算符在JavaScript中用于检测变量的类型,但它们有不同的应用场景和功能。
typeof运算符:
例子:
typeof 42; // "number"
typeof "Hello"; // "string"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof null; // "object" (错误的结果)
instanceof运算符:
例子:
const obj = {};
obj instanceof Object; // true
function Person() {}
const person = new Person();
person instanceof Person; // true
const arr = [];
arr instanceof Array; // true
arr instanceof Object; // true,因为Array继承自Object
const str = "Hello";
str instanceof String; // false,因为str是基本类型而不是字符串对象
总结:
typeof用于判断基本类型。
instanceof用于判断对象的构造函数实例。
两者针对的对象范围不同,typeof适用于原始类型和函数(也是对象),instanceof适用于对象及其派生对象。
<script>
let a = 1
console.log(a++); //1
console.log(a); //2
let b = 1
console.log(++b); //2
console.log(b); //2
</script>
XML(可扩展标记语言)和JSON(JavaScript对象表示)是两种常用的数据格式。它们之间的区别如下:
选择使用XML还是JSON取决于具体的需求和场景。如果需要更好的人类可读性,或者需要使用自定义的数据类型,那么XML可能更适合。如果关注数据传输效率和处理速度,或者与JavaScript密切相关,那么JSON可能更合适。
JavaScript中常用的五个输入输出函数包括:
console.log():用于在浏览器的控制台或服务器端输出信息。可以接受多个参数,并将它们打印到控制台上。例如:
console.log("Hello, world!");
alert():在浏览器中显示一个弹窗,并将指定信息作为提示展示给用户。通常用于简单的消息提示,需要用户点击确认按钮才能关闭。例如:
alert("This is an alert message.");
prompt():在浏览器中显示一个带有输入框的弹窗,要求用户输入信息。用户输入的内容将作为函数的返回值使用。例如:
let name = prompt("Please enter your name:");
console.log("Hello, " + name);
confirm():在浏览器中显示一个带有确认和取消按钮的弹窗,询问用户是否同意某个操作。用户的选择结果将作为函数的返回值使用(true表示确认,false表示取消)。例如:
let result = confirm("Are you sure you want to delete this item?");
if (result) {
console.log("Item deleted.");
} else {
console.log("Delete canceled.");
}
document.write():将指定的内容直接写入到HTML文档中,可以用于动态生成或修改页面内容。注意,当文档已经加载完毕后再使用该函数会覆盖整个文档内容。例如:
document.write("Welcome!
");
以上是JavaScript中常用的五个输入输出函数。根据需要选择适合的函数来实现所需的输入和输出操作。