JavaScript有几种方式声明函数?

  1. 函数声明(Function Declaration)

    1
    2
    3
    function functionName(parameters) {
    // 函数体
    }
  2. 函数表达式(Function Expression)

    1
    2
    3
    var functionName = function(parameters) {
    // 函数体
    };
  3. 箭头函数(Arrow Function)(ES6引入):

    1
    2
    3
    var functionName = (parameters) => {
    // 函数体
    };
  4. Function构造函数

    1
    var functionName = new Function('parameters', 'function body');

这些方式各有特点,函数声明和函数表达式是最常见和推荐的方式,而箭头函数是在ES6中引入的一种更简洁的写法,而Function构造函数则较少使用,因为它会在运行时解析字符串,有一定的性能开销和安全风险。

img

原生Javascript获取DOM节点有哪些方式?

document.getElementById

获取具有指定的ID,ID唯一。

1
leta=documentgetElementById('id');

document.getElementByTagName

返回一个包含所有给定标签名元素的HTML

1
let a=document.getElementByTagName('div');

1document.getElementByClassName

返回一个包含所有给定类名的元素的 HTMLCollection

1
let a=document.getElementByClassName('myclass');

在原生 JavaScript 中,有多种方式可以获取或选择 DOM (Document Object Model) 元素。这些方法提供了从简单到复杂的不同级别的选择功能,可以让你根据 ID、类名、标签名、CSS 选择器等多种方式选择元素。以下是一些最常用的方法:

1. document.getElementById

获取具有指定 ID 的一个元素。ID 在一个文档中应该是唯一的。

1
var element = document.getElementById('myId');

2. document.getElementsByTagName

返回一个包含所有给定标签名的元素的 HTMLCollection

1
var elements = document.getElementsByTagName('div');

3. document.getElementsByClassName

返回一个包含所有给定类名的元素的 HTMLCollection

1
var elements = document.getElementsByClassName('myClass');

4. document.querySelector

返回文档中匹配指定 CSS 选择器的第一个元素。如果没有找到匹配项,返回 null

1
2
3
var element = document.querySelector('.myClass');
var element = document.querySelector('#myId');
var element = document.querySelector('div[name="myElement"]');

5. document.querySelectorAll

返回一个 NodeList,其中包含文档中所有符合指定 CSS 选择器的元素。

1
2
3
var elements = document.querySelectorAll('.myClass');
var elements = document.querySelectorAll('div');
var elements = document.querySelectorAll('div.myClass');

6. document.forms

这是一个比较老的方法,用来获取文档中的表单元素。

1
2
var form = document.forms[0]; // 获取第一个表单
var myForm = document.forms['myFormName']; // 通过名称获取表单

7. document.getElementsByName

这个方法返回一个 NodeList,其中包含所有具有指定的 name 特性的元素。

1
var elements = document.getElementsByName('name');

8. 使用 CSS 属性选择器

你也可以使用 querySelectorquerySelectorAll 方法配合属性选择器来选择具有特定属性的元素。

1
2
var element = document.querySelector('input[type="checkbox"]');
var elements = document.querySelectorAll('input[type="text"]');

使用建议:

  • 如果你只需要选择一个元素,并且该元素具有 ID,那么 getElementById 是最快的选择。
  • 如果需要根据类名、标签名或者更复杂的 CSS 选择器选择多个元素,querySelectorAll 是非常强大的工具。
  • 对于需要兼容性考虑,所有上述方法除了较新的 querySelectorquerySelectorAll,其他都有很好的兼容性。querySelectorquerySelectorAll 主要不支持 IE8 及以下版本。

这些方法都是原生 JavaScript 提供的,无需依赖任何库或框架即可在现代浏览器中使用。

Javascript的this绑定

在JavaScript中,this 关键字是非常核心的一个概念,它引用的是函数执行时的上下文对象。理解this如何绑定到不同的上下文是理解和掌握JavaScript非常重要的一部分。this的绑定规则可以通过以下几种方式确定:

默认绑定

当函数独立调用时(即不作为某个对象的方法或未被显式绑定到某个对象),this 默认绑定到全局对象。在非严格模式下,this 指向全局对象(浏览器中的window,Node.js中的global);在严格模式下(函数或全局代码中使用'use strict';),this 会被绑定到undefined

1
2
3
4
5
function show() {
console.log(this);
}

show(); // 在非严格模式下,输出 window/global;在严格模式下,输出 undefined

隐式绑定

当函数作为对象的方法被调用时,this 隐式绑定到该对象。

1
2
3
4
5
6
7
8
const obj = {
name: 'Example',
show: function() {
console.log(this.name);
}
};

obj.show(); // 输出 'Example'

如果存在多层对象嵌套,this 将绑定到最近一层的对象上。

显式绑定

使用call()apply()bind() 方法可以显式地指定this 的绑定对象。

1
2
3
4
5
6
7
8
9
10
11
function show() {
console.log(this.name);
}

const obj = { name: 'Explicit Example' };

show.call(obj); // 输出 'Explicit Example'
show.apply(obj); // 输出 'Explicit Example'

const boundShow = show.bind(obj);
boundShow(); // 输出 'Explicit Example'

new绑定

当一个函数通过new 关键字被作为构造函数调用时,this 被绑定到新创建的对象上。

1
2
3
4
5
6
function Person(name) {
this.name = name;
}

const person = new Person('New Person');
console.log(person.name); // 输出 'New Person'

箭头函数绑定

箭头函数不使用以上四种规则,而是捕获其所在上下文的this 值,作为自己的this 值,也称为词法绑定。

1
2
3
4
5
6
7
8
9
10
const obj = {
name: 'Arrow',
show: function() {
setTimeout(() => {
console.log(this.name);
}, 100);
}
};

obj.show(); // 输出 'Arrow'

在箭头函数中,this 绑定到外围函数的上下文中,即使是在setTimeout这样的异步函数中。

总结

JavaScript的this 绑定是动态的,除了箭头函数外,其绑定取决于函数调用的上下文。理解这些绑定规则对于编写可预测的JavaScript代码非常重要。

JS主线程有哪些

在JavaScript中,特别是在浏览器环境下,存在一个称为“主线程”的概念,通常也被称为“UI线程”。JavaScript 是单线程运行的,意味着在任一时刻只能执行一个任务。主线程负责执行代码、渲染界面、处理用户的交互操作等任务。这里主要解释的是JavaScript在浏览器中的运行环境:

JavaScript 主线程的职责

  1. 执行代码

    • JavaScript 主线程执行所有的JavaScript代码。无论是从<script>标签引入的代码,还是通过事件触发的函数,都在这个单一的线程上执行。
  2. UI 渲染

    • 浏览器使用主线程来渲染页面。这包括HTML的解析、CSS的应用、DOM的操作以及最终的画面渲染。这也是为什么在执行重计算或大量DOM操作时,页面可能会感觉卡顿或冻结,因为这些操作会占用主线程的资源,影响到UI的更新。
  3. 用户交互

    • 主线程还处理来自用户的所有交互,如点击、滚动、键盘输入等。这意味着如果JavaScript代码执行耗时过长,它可以阻塞用户交互,导致不良的用户体验。

与主线程交互的其他组件

尽管JavaScript是单线程执行的,但现代浏览器和Node.js环境提供了多种机制来处理异步事件和后台任务,以避免阻塞主线程,如:

  1. Web Workers

    • 提供一种在浏览器背景下运行脚本的方法,不影响主线程。Web Workers运行在与主线程完全独立的线程上,可以执行复杂计算或处理大量数据,不会导致界面卡顿。
  2. 事件队列和事件循环

    • 浏览器维护一个事件队列,所有异步事件,如网络请求、定时器触发、用户输入等,都会被排到这个队列中。主线程在执行完当前代码后,会查看这个队列,并处理队列中的事件。
  3. 异步API

    • 浏览器提供了许多异步API,如setTimeoutsetIntervalfetch(网络请求)等,这些API的回调不会立即执行,而是在合适的时机被推入事件队列,待主线程空闲时执行。

注意事项

由于主线程的多重职责,作为开发者在编写JavaScript代码时,需要注意不要执行过于复杂或耗时的同步代码,这可能会阻塞主线程,影响到UI的渲染和用户的交互体验。在处理大量数据或复杂计算时,应考虑使用Web Workers或其他异步处理方法,以提高应用性能和响应性。

事件捕获、目标、冒泡

在Web开发中,事件冒泡是一种事件处理机制,其中从一个元素发起的事件会逐层向上传播到其父元素,直至根元素。有时候,我们可能需要阻止这种冒泡行为,以避免触发父元素上的事件处理函数。这可以通过JavaScript中的事件对象提供的方法来实现。

以下是如何在不同情况下阻止事件冒泡的方法:

使用 event.stopPropagation()

这是阻止事件冒泡的标准方法。当在事件处理函数中调用此方法时,当前事件将不会进一步传播到父元素。

1
2
3
4
element.addEventListener('click', function(event) {
event.stopPropagation();
// 事件处理代码
});

返回 false

在使用jQuery时,你可以通过在事件处理函数中返回false来同时阻止事件冒泡和默认行为。在原生JavaScript中,这种方法只适用于通过HTML属性添加的事件处理器。

1
2
3
4
5
6
7
8
9
10
11
12
// 使用 jQuery
$('#element').on('click', function(event) {
// 事件处理代码
return false; // 阻止冒泡并阻止默认行为
});

// 在HTML元素中直接使用
<button onclick="doSomething(); return false;">Click me</button>

function doSomething() {
// 事件处理代码
}

使用 event.stopImmediatePropagation()

这个方法不仅阻止事件继续冒泡到更高的父元素,还阻止任何当前元素上的其他事件监听器被调用。这是一个比stopPropagation()更强大的方法。

1
2
3
4
element.addEventListener('click', function(event) {
event.stopImmediatePropagation();
// 事件处理代码
});

应用场景

  • 阻止链接默认打开新页面:阻止<a>标签的默认行为。
  • 防止表单提交:阻止表单的自动提交行为。
  • 组织事件传播到其他元素:如在弹出菜单中阻止点击事件传播到背景页面。

注意

虽然阻止事件冒泡可以解决一些问题,但过度使用它可能会导致维护困难,因为这改变了事件的正常流动。合理使用这一特性,并确保理解其对整体交互逻辑的影响。

JavaScript的对象方法

JavaScript的对象(Object)有许多内置的方法,这些方法可以帮助我们操作和管理对象。以下是一些常见的对象方法及其示例:

Object.keys()

返回一个数组,包含对象自身可枚举属性的键。

1
2
3
4
5
6
7
8
const person = {
name: "John",
age: 30,
city: "New York"
};

const keys = Object.keys(person);
console.log(keys); // 输出: ["name", "age", "city"]

Object.values()

返回一个数组,包含对象自身可枚举属性的值。

1
2
3
4
5
6
7
8
const person = {
name: "John",
age: 30,
city: "New York"
};

const values = Object.values(person);
console.log(values); // 输出: ["John", 30, "New York"]

Object.entries()

返回一个数组,包含对象自身可枚举属性的键值对数组。

1
2
3
4
5
6
7
8
const person = {
name: "John",
age: 30,
city: "New York"
};

const entries = Object.entries(person);
console.log(entries); // 输出: [["name", "John"], ["age", 30], ["city", "New York"]]

Object.assign()

将所有可枚举的自身属性从一个或多个源对象复制到目标对象。它返回目标对象。

1
2
3
4
5
6
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);
console.log(returnedTarget); // 输出: { a: 1, b: 4, c: 5 }
console.log(target); // 输出: { a: 1, b: 4, c: 5 }

Object.freeze()

冻结对象:一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。该对象的原型也不能被修改。

1
2
3
4
5
6
7
8
9
const person = {
name: "John",
age: 30
};

Object.freeze(person);

person.age = 40; // 这行代码不会生效
console.log(person.age); // 输出: 30

Object.seal()

密封对象:一个密封的对象不能再添加新的属性,且所有现有属性将变为不可配置的。现有属性的值仍然可以修改。

1
2
3
4
5
6
7
8
9
10
const person = {
name: "John",
age: 30
};

Object.seal(person);

person.age = 40; // 这行代码会生效
person.city = "New York"; // 这行代码不会生效
console.log(person); // 输出: { name: "John", age: 40 }

Object.create()

使用指定的原型对象及其属性创建一个新对象。

1
2
3
4
5
6
7
8
9
const personPrototype = {
greet() {
console.log(`Hello, my name is ${this.name}`);
}
};

const john = Object.create(personPrototype);
john.name = "John";
john.greet(); // 输出: Hello, my name is John

Object.defineProperty()

直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。

1
2
3
4
5
6
7
8
9
10
11
12
const person = {};

Object.defineProperty(person, 'name', {
value: 'John',
writable: false, // 不能修改
enumerable: true,
configurable: true
});

console.log(person.name); // 输出: John
person.name = 'Jane'; // 这行代码不会生效
console.log(person.name); // 输出: John

Object.getOwnPropertyDescriptor()

返回指定对象上一个自有属性对应的属性描述符。

1
2
3
4
5
6
7
8
9
10
11
12
13
const person = {
name: "John"
};

const descriptor = Object.getOwnPropertyDescriptor(person, 'name');
console.log(descriptor);
// 输出:
// {
// value: 'John',
// writable: true,
// enumerable: true,
// configurable: true
// }

Object.getPrototypeOf()

返回指定对象的原型(即,内部[[Prototype]]属性的值)。

1
2
3
4
5
6
7
8
9
10
const personPrototype = {
greet() {
console.log(`Hello, my name is ${this.name}`);
}
};

const john = Object.create(personPrototype);
john.name = "John";

console.log(Object.getPrototypeOf(john) === personPrototype); // 输出: true

总结

JavaScript对象有许多内置方法,可以帮助我们操作和管理对象。上述列举的只是其中的一部分,实际开发中可以根据需要选择合适的方法来处理对象