JavaScript真题合集(一)
前言,JavaScript(简称JS)是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。
1. js中的数据类型?存储上的差异?
在JavaScript中,数据类型主要分为两大类:原始数据类型(也称为基本类型)和引用数据类型(也称为复杂类型或对象类型)。
★ 1.1 数据类型
基本数据类型包括:
1.Number:用于表示整数(常用十进制)和浮点数。存在一种特殊的数值(NaN)。
2.String:用于表示文本数据,即字符序列。
3.Boolean:有两个值,true和false,用于逻辑判断。
4.Undefined:当一个变量被声明了,但没有赋值时,它的值就是undefined。
5.Null:表示一个空值或者不存在的对象引用。
6.Symbol:ES6引入的一种新的数据类型,表示唯一的标识符。通过Symbol()函数生成。
引用数据类型则包括:
1.Object:这是引用类型的基类,它表示一组无序的键值对集合。
2.Array:表示一个有序的值的集合。
3.Function:表示可重复使用的代码块。
1.2 存储上的差异:
- 基本数据类型:它们的值直接存储在栈内存中。每个原始值都占用固定大小的空间,因此它们的访问速度非常快。当你将一个基本类型的值赋给另一个变量时,实际上是创建了这个值的一个副本。
- 引用数据类型:它们的值并不直接存储在栈内存中,而是存储在堆内存中。在栈内存中,只保存了一个指向堆内存中实际对象的引用(即地址)。因此,当你将一个引用类型的值赋给另一个变量时,实际上只是复制了这个引用,而不是对象本身。这两个变量现在指向的是同一个对象。
基础数据类型 例如:
let a = 10; // 声明一个变量a,并初始化为10
let b = a; // 声明一个变量b,并将a的值(即10)赋给b
b = 40; // 将b的值更改为20
console.log(b); // 输出b的值,此时b的值是40
console.log(a); // 输出a的值,此时b的值是10
// 初始栈内中只有 a
// 栈内存中添加 b 并把 a 值赋值给 b 一份
// 栈内存中 b 保存了另一个值
引用数据类型 例如:
var obj1 = {}; // 创建一个新的空对象并赋值给obj1
var obj2 = obj1; // obj2被赋值为obj1的引用,它们指向同一个对象
obj2.age = "18"; // 通过obj2的引用给对象添加一个属性age,并赋值为"18"
console.log(obj1.age); // 由于obj1和obj2指向同一个对象,所以输出"18"
// 初始栈内中只有 obj1
// 栈内存中添加 obj2 并把 obj1 值赋值给 obj2 一份
// obj2添加age属性
// 共同指向同一个堆内存对象
2. js中的数据结构?
是计算机存储、组织数据的方式。JavaScript的基本类型(如Number, String, Boolean, null, undefined, Symbol)和对象类型(如Object, Array, Map, Set, Date等)可以被用来模拟和构建这些数据结构。
2.1 数据结构最常见的如下:
- 1.数组 Array
- 2.栈 Stack
是一种遵循后进先出原则有序集合。在栈里面,新元素在上面,旧元素在下面。每次加入新的元素和拿走元素都在顶部操作。 - 3.队列 Queue
是一种遵循先进先出原则的有序项。队列在尾部添加新的元素,并从顶部移除元素。最新的元素必须在队列的末尾。 - 4.链表 Linked List
- 5.字典
- 6.散列表 Hash table
- 7.树 Tree
- 8.图 Graph
- 9.堆 Heap
- 10.对象 Object
- 11.Map
- 12.Set
2.2 DOM是什么?常见的操作?
2.2.1:DOM(文档对象模型)是一种用于表示和操作HTML和XML文档的标准。在JavaScript中,可以使用DOM API来对DOM进行操作
2.2.2:常见操作
-
1.创建节点
- 使用
document.createElement(tagName)
创建一个指定标签名的元素节点。 - 使用
document.createTextNode(text)
创建一个包含指定文本内容的文本节点。
- 使用
-
2.查询节点
- 通过元素的ID查询:
document.getElementById('id')
。 - 通过元素的类名查询:
document.getElementsByClassName('class')
(注意这个方法返回的是一个类数组对象)。 - 通过元素的标签名查询:
document.getElementsByTagName('tag')
。 - 通过选择器查询:
document.querySelector('selector')
(返回匹配的第一个元素)。 - 通过选择器获取所有匹配的元素:
document.querySelectorAll('selector')
。
- 通过元素的ID查询:
-
3.更新节点
- 设置元素的属性值:
element.setAttribute(name, value)
。 - 获取元素的属性值:
element.getAttribute(name)
。 - 设置或获取元素的HTML内容:
element.innerHTML
。 - 设置或获取元素的文本内容:
element.innerText
。
- 设置元素的属性值:
-
4.添加节点
- 末尾追加:使用
parentElement.appendChild(child)
将新元素添加到父元素的子节点列表的末尾。 - 中间插入:使用
parent.insertBefore(newTarget, oldTarget)
在指定的旧元素之前插入新元素。 - 替换元素:使用
parent.replaceChild(newChild, oldChild)
用新元素替换旧元素。
- 末尾追加:使用
-
5.删除节点
- 使用
parentElement.removeChild(child)
从指定父节点的子节点列表中删除一个子节点。
- 使用
-
6.其他操作
- 访问元素的子节点:使用
element.childNodes
或element.children
(只返回元素节点)。 - 访问元素的父节点:使用
element.parentNode
或element.parentElement
(返回父元素节点)。 - 访问元素的兄弟节点:使用
element.previousSibling、element.nextSibling
(包括文本节点和元素节点)或element.previousElementSibling、element.nextElementSibling
(只返回元素节点)。
- 访问元素的子节点:使用
请注意,在JavaScript中操作DOM时,应尽量减少对DOM树的修改,因为每次修改都可能导致DOM树的重排和重绘,从而影响页面性能。
2.3 BOM是什么?常见的操作?
2.3.1:BOM(浏览器对象模型):提供了独立于内容与浏览器窗口进行交互的对象其作用就是跟浏览器做一些交互效果
2.3.2:常见操作
-
1.window
- 这是浏览器全局对象,代表浏览器窗口或标签页。
- 它包含了许多方法和属性,如:
window.open()
, (打开窗口)window.close()
, (关闭一个窗口)window.self()
(窗口本身)window.focus()
(使当前的窗口在所有窗口之前. )window.status=”内容”
(js中状态栏显示内容:)window.navigate(”http://www.google.com”);
(js中的窗口重定向:)window.print()
(js中的打印:)window.prompt(”message”,”defaultreply”);
(js中的提示输入框:)window.scroll(x,y)
(js中的窗口滚动条)window.scrollby
(js中的窗口滚动到位置:)window.history.back()
返回上一页window.history.forward()
返回下一页,window.history.go
(返回第几页,也可以使用访问过的url) 如果是0那么就是刷新history.lengthwindow.createElement
- 你可以通过
window
对象来访问浏览器提供的所有全局 JavaScript 对象和函数。
-
2.location
- 它是 window 对象的一个属性,提供了与当前窗口中加载的文档相关的 URL 信息。
- 你可以使用 location 对象来获取 URL 的各个部分(如协议、主机名、路径名、查询字符串等),或者通过修改其属性(如 href 或 pathname)来重定向浏览器到新的 URL。
- 属性和方法:
-
3.navigator
-
它也是 window 对象的一个属性,包含了有关浏览器的信息。
-
通过 navigator 对象,你可以获取浏览器的名称、版本、操作系统、用户代理字符串等信息。
navigator.userAgent
:返回包含浏览器用户代理字符串的字符串。可以使用这个属性来检测浏览器的类型和版本。navigator.platform
:返回表示浏览器运行平台的字符串。navigator.language
:返回用户首选的浏览器语言,如 “en-US”、“zh-CN” 等。navigator.cookieEnabled
:返回一个布尔值,表示浏览器是否启用了 cookie。navigator.onLine
:返回一个布尔值,表示设备是否连接到互联网。navigator.geolocation
:提供用于获取设备地理位置信息的相关方法。navigator.sendBeacon()
:用于异步发送数据到服务器的简单方法,特别适用于在页面卸载前发送数据。
-
注意,由于隐私和安全原因,某些浏览器可能限制了对这些信息的访问。
-
-
4.screen
- 它同样是 window 对象的一个属性,提供了关于客户端屏幕的信息。
- 你可以使用 screen 对象来获取屏幕的宽度、高度、颜色深度等信息。
availHeight
:返回屏幕的高度(不包括 Windows 任务栏)availWidth
:返回屏幕的宽度(不包括 Windows 任务栏)colorDepth
:返回目标设备或缓冲器上的调色板的比特深度height
:返回屏幕的总高度pixelDepth
:返回屏幕的颜色分辨率(每像素的位数)width
:返回屏幕的总宽度
- 这些信息对于设计响应式网站或调整页面布局以适应不同屏幕尺寸非常有用。
-
5.history
- 它是 window 对象的一个属性,提供了与浏览器会话历史(即用户访问过的页面)相关的功能。
- 通过 history 对象,你可以导航到会话历史中的前一个或后一个页面(使用 back() 和 forward() 方法),或者向会话历史中添加新条目(使用 pushState() 和 replaceState() 方法)。
- 需要注意的是,出于安全原因,浏览器限制了 history 对象的某些功能,例如直接访问会话历史中的 URL 列表。
★ 2.4 BOM和DOM区分
BOM | DOM |
---|---|
浏览器对象模型 | 文档对象模型 |
把浏览器 当作对象 | 把文档 当作对象 |
顶级对象是window | 顶级对象是document |
主要学习的是 浏览器窗口交互的一些对象 | 主要学习的是 操作页面元素 |
是在各自浏览器上定义的 | 是W3C标准规范 |
★ 3. == 和 === 的区别
区别 | ==(相等运算符) | ===(严格相等运算符) |
---|---|---|
类型转换 | 在比较之前,如果两边的数据类型不同,会先尝试进行类型转换,以使两边的数据类型相同,然后再进行比较 | 它不会进行任何类型转换。只有当两边的数据类型和值都完全相同时,才返回true |
比较方式 | 如果两边的数据类型不同,但它们的值在转换为相同类型后是相等的,那么==会返回true。例如,“” == 0 会返回 true,因为空字符串在转换为数字后变为0 | 它要求两边的数据类型和值都必须完全相同,才会返回true。例如,“” === 0 会返回 false,因为空字符串和0的类型不同 |
用途 | 在一些情况下,使用==可能更方便,因为它会自动处理类型转换。但是,这也可能导致一些不易察觉的错误,因为类型转换可能不是你所期望的 | 为了避免这些潜在的错误,许多开发者推荐始终使用===进行比较,因为它更严格、更可靠 |
4. typeof 和 instanceof 的区别
4.1 typeof
是一个一元操作符,它返回一个表示未计算操作数类型的字符串。它主要用于确定一个变量是原始类型还是对象类型(但不包括对象的具体类型)。
对于原始类型(如 number、string、boolean、undefined、symbol(在 ES6 中引入)和 null),typeof 会返回相应的字符串。
对于对象(包括数组、函数、Date 对象、RegExp 对象等),typeof 会返回 "object"。
console.log(typeof 42); // "number"
console.log(typeof "blubber"); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof Symbol()); // "symbol"
console.log(typeof []); // "object"
console.log(typeof {}); // "object"
console.log(typeof Math.sin); // "function"
4.2 instanceof
操作符用于检测构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。它主要用于确定一个对象是否是一个类的实例。
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
const myCar = new Car('Honda', 'Accord', 1998);
console.log(myCar instanceof Car); // true
console.log(myCar instanceof Object); // true,因为所有的对象都继承自 Object
★ 4.3 区别
相同点:都是判断数据类型的方法
不同点:
① typeof与instanceof用来判断变量是否为空,或者属于什么数据类型
② typeof返回的是一个字符串,用来判断是什么数据类型
③ instanceof返回的是一个布尔值,用来判断一个变量是否属于对象上的实例
④ typeof检测的是简单数据类型,instanceof检测的是引用数据类型
5. JavaScript原型,原型链?有什么特点?
5.1 JavaScript原型
在JavaScript中,每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
原型的作用:
① 数据共享 节约内存内存空间
② 实现继承
★ 5.2 原型链
Javascript 是面向对象的,每个实例对象都有一个proto_属性,该属性指向它原 型对象,这个实例对象的构造函数有一个原型属性 prototype,与实例的proto属性指 向同一个对象。当一个对象在查找一个属性的时,自身没有就会根据proto_ 向它的原型 进行查找,如果都没有,则向它的原型的原型继续查找,直到查到 Object.prototype.proto_为null,这样也就形成了原型链。
5.3 特点
- 共享性:通过原型,我们可以让多个对象共享相同的属性和方法,从而节省内存。
- 动态性:在原型链中的任何位置,都可以添加、修改或删除属性和方法,这些改变会立即影响到所有使用该原型的对象。
- 继承性:原型链是实现JavaScript中继承的主要方式。当一个对象试图访问其不存在的属性或方法时,JavaScript会沿着原型链向上查找,直到找到为止。
- 扩展性:通过修改内置对象的原型,我们可以为所有该类型的对象添加新的功能。但请注意,这种做法可能会引发一些不可预见的问题,因为可能会影响到其他依赖这些内置对象的代码。
- 简化代码:通过原型链,我们可以将通用的属性和方法放在原型上,而只在对象上存储特定的属性和方法,从而简化代码。
- 性能考虑:虽然原型链提供了很大的灵活性,但在某些情况下,它可能会导致性能下降。因为每次访问对象的属性时,JavaScript都需要沿着原型链进行查找。如果原型链很长,或者频繁地进行这种查找,可能会导致性能问题。
6. 作用域链
6.1 作用域
是变量和函数生效的区域或集合。
★ 一般作用域分为:
1.全局作用域:
① 全局作用域是最外层的作用域,在代码的任何地方都能访问到。
② 在全局作用域中声明的变量会成为全局对象(在浏览器中是window对象)的属性。
③ 如果你在函数外部任何地方声明了一个变量,那么它就是在全局作用域中。
var globalVar = "I'm global!"; // 声明一个全局变量
function checkGlobal() {
console.log(globalVar); // 可以访问全局变量
}
checkGlobal(); // 输出 "I'm global!"
2.函数作用域(局部作用域):
① 在ES6之前,JavaScript只有全局作用域和函数作用域(也称为局部作用域)。
② 函数作用域是在函数内部声明的变量的作用域。这些变量在函数外部是不可见的。
function functionScope() {
var localVar = "I'm local!"; // 声明一个局部变量
console.log(localVar); // 可以访问局部变量
}
functionScope(); // 输出 "I'm local!"
console.log(localVar); // ReferenceError: localVar is not defined
3.块级作用域
① 块级作用域是在ES6中引入的,通过 let 和 const 关键字实现。
② 块级作用域指的是在代码块(由{}包围)内部声明的变量的作用域。这些变量在块外部是不可见的。
if (true) {
let blockScopedVar = "I'm block scoped!"; // 声明一个块级作用域的变量
console.log(blockScopedVar); // 可以访问块级作用域变量
}
console.log(blockScopedVar); // ReferenceError: blockScopedVar is not defined
6.2 作用域链
是JavaScript中一个重要的概念,它决定了变量的可访问性和作用域。 具体来说,作用域链是描述函数中变量访问的顺序和范围的链式结构,由一系列的执行上下文对象组成。每个执行上下文对象都有一个指向父级上下文的指针,这就形成了一个链式结构。
在JavaScript中,每个函数都有自己的作用域,当函数被创建时,它的作用域链会被创建此函数的作用域中可访问的数据对象填充。当JS需要查找变量X的值时,它会从链的第一个对象开始查找,如果这个对象有一个名为x的属性,则会直接使用这个属性的值。如果第一个对象中没有名为x的属性,JS会继续查找链上的下一个对象,以此类推。
作用域链的形成是在函数定义的时候就确定的,它是由函数定义的位置决定的。作用域链的作用主要是提高程序逻辑的局部性,增强程序的可靠性,减少名字冲突。
★ 7. this指向问题
它引用的是调用函数的对象。然而,this 的值并不是在函数被定义时确定的,而是在函数被调用时确定的。
- 1.全局上下文: 在全局作用域中(即不在任何函数内),this 指向全局对象。在浏览器中是 window 对象。
console.log(this === window); // 在浏览器环境中为 true
- 2.函数直接调用: 如果函数不是作为某个对象的方法被调用,那么this 默认指向全局对象(在严格模式下为 undefined)。
function myFunction() {
console.log(this === window); // 在浏览器环境中为 true
}
myFunction();
- 3.对象的方法: 当函数作为对象的方法被调用时,this 指向该对象。
var myObject = {
myMethod: function() {
console.log(this === myObject); // 为 true
}
};
myObject.myMethod();
- 4.构造函数: 当函数用 new 关键字调用时,它作为一个构造函数被调用,this 指向新创建的对象实例。
function MyConstructor() {
this.myProperty = "Hello";
}
var instance = new MyConstructor();
console.log(instance.myProperty); // 输出 "Hello"
- 5.显式设置: 可以使用 call、apply 或 bind 方法来显式设置 this 的值。
function myFunction() {
console.log(this.myProperty);
}
var obj = { myProperty: "Hello" };
myFunction.call(obj); // 输出 "Hello"
- 6.箭头函数: 箭头函数不绑定自己的 this,它会捕获其所在上下文的 this 值,作为自己的 this 值。
var obj = {
myMethod: function() {
var arrowFunction = () => {
console.log(this === obj); // 为 true
};
arrowFunction();
}
};
obj.myMethod();
- 7.事件处理器: 在DOM事件处理器中,this 通常指向触发事件的元素。
button.addEventListener('click', function() {
console.log(this === button); // 为 true
});
- 8.定时器回调: 在 setTimeout 或 setInterval 的回调函数中,this 默认指向全局对象(在严格模式下为 undefined)。
8.new操作符
用于创建一个用户自定义的对象类型的实例或具有构造函数的内置对象的实例。
- 创建一个空对象: 首先,new 操作符会创建一个新的空对象。
- 设置原型链: 将这个新对象的 proto(内部属性,某些环境中可以通过 Object.getPrototypeOf() 访问)设置为构造函数的 prototype 对象。这样,新对象就可以继承构造函数原型链上的属性和方法。
- 执行构造函数: 使用新创建的对象作为上下文(即 this 指向它)来调用构造函数。如果构造函数返回一个对象,则 new 表达式的结果就是这个对象;否则,new 表达式的结果就是新创建的对象。
- 返回新对象: 如果构造函数没有返回一个对象(或者返回的是非对象类型的值,如数字、字符串等),则返回新创建的对象。
function Person(name, age) {
this.name = name;
this.age = age;
// 构造函数通常不返回值,但如果返回了一个对象,那么 new 表达式的结果就是那个对象
// 这里我们不返回任何值,所以 new 表达式的结果是新创建的 Person 对象
}
// 使用 new 创建一个 Person 对象
var john = new Person("John", 30);
console.log(john.name); // 输出 "John"
console.log(john.age); // 输出 30
// Person.prototype 上的属性或方法也可以被 john 访问
Person.prototype.greet = function() {
console.log("Hello, my name is " + this.name);
};
john.greet(); // 输出 "Hello, my name is John"
9.call、apply、bind(改变this指向)
(1)call 和 apply立即调用原函数,bind 不会调用而是生成一个改变了 this 指向的新的函数
(2)传参不同,call 调用的时候,参数必须以参数列表的形式进行传递,以逗号分隔的方式依次传递;apply 调用的时候,参数必须是一个数组
(3)第一个参数为要改变的this指向,如果不需要改变this指向 传null
10.事件模型
事件模型主要有三种:DOM Level 0(原始事件模型)、DOM Level 2(也称为 DOM 标准事件模型)和 IE 事件模型(也称为事件冒泡和事件捕获的混合模型)。
10.1 原始事件模型
这是最早的事件模型,主要通过直接在 HTML 元素上设置事件处理函数来使用。
例如:<button οnclick="alert('Hello, World!')">Click Me</button>
这种方式没有事件流(事件冒泡和事件捕获)的概念。
10.2 标准事件模型
引入了事件监听器的概念,允许为同一个事件添加多个处理函数。
支持事件冒泡和事件捕获两个阶段。
使用 addEventListener() 方法添加事件监听器,并可以指定事件处理函数在事件流中的哪个阶段执行。
例如:element.addEventListener('click', function() { ... }, false/true);(其中 false 表示在冒泡阶段处理,true 表示在捕获阶段处理)
大多数现代浏览器都遵循这个模型。
10.3 IE 事件模型
早期版本的 Internet Explorer 使用了与 DOM 标准不同的事件模型。
使用 attachEvent() 方法添加事件监听器,但不支持事件捕获。
事件处理函数通过 window.event 对象来访问事件信息。
由于与 DOM 标准的不一致,这个模型在现代开发中很少使用。
事件流:
描述了当某个事件(如点击、鼠标移动等)在DOM树中的某个元素上被触发时,事件是如何传播的。事件流主要包括三个阶段:捕获阶段、目标阶段和冒泡阶段。
1.事件捕获:与事件冒泡相反,事件捕获是从根元素开始,沿着 DOM 树向下传播到触发事件的元素。在捕获过程中,任何包含触发元素的元素都可以监听并处理该事件。DOM Level 2 事件模型允许开发者指定事件处理函数在冒泡阶段还是捕获阶段执行。
2.目标阶段:当事件到达目标元素时,会触发目标元素上注册的事件监听器。这个阶段通常包含在冒泡阶段之前,但逻辑上并不作为事件流的一个独立阶段。
3.事件冒泡:在事件冒泡阶段,事件从目标元素开始,向上传播到其父元素、祖父元素等,直到到达最外层的祖先元素(通常是document对象或window对象)。在这个过程中,任何注册了事件监听器的元素都可以接收到这个事件,除非事件在传播过程中被阻止(使用Event.stopPropagation()方法)。
// 在JavaScript中,你可以使用addEventListener()方法的第三个参数来指定事件监听器是在捕获阶段还是冒泡阶段被触发。
// 在捕获阶段监听事件
element.addEventListener('click', function() {
console.log('Capturing phase');
}, true);
// 在冒泡阶段监听事件(默认)
element.addEventListener('click', function() {
console.log('Bubbling phase');
}, false);
阻止事件冒泡和捕获
// 使用Event.stopPropagation()方法来阻止事件在DOM树中进一步传播(即阻止冒泡和捕获)。
// 另外,Event.stopImmediatePropagation()方法不仅可以阻止事件传播,还可以阻止同一事件的其他监听器被触发。
element.addEventListener('click', function(event) {
event.stopPropagation(); // 阻止事件冒泡和捕获
// 或者
// event.stopImmediatePropagation(); // 阻止事件冒泡和捕获,并阻止同一事件的其他监听器被触发
}, false);