this
在JavaScript中,关键字this指向当前执行上下文的对象。具体来说,this的指向取决于它是如何被调用的。以下是一些常见情况下this的指向:
- 在全局作用域中,this指向全局对象(在浏览器中通常是window对象)。
- 在函数中,this的值取决于函数是如何被调用的。如果函数作为对象的方法被调用,this指向调用该函数的对象。如果函数被独立调用,this通常指向全局对象(在严格模式下是undefined)。
- 在构造函数中,this指向将要创建的新实例。
- 在事件处理程序中,this通常指向触发事件的元素。
需要注意的是,箭头函数中的this与普通函数不同,它没有自己的this值,而是继承自外层作用域的this。因此,箭头函数中的this是在定义时确定的,而不是在调用时确定的。
this指向
windows.test全局
obj函数
事件绑定this
改变this指向
call apply bind
在JavaScript中,call、apply和bind是用于改变函数执行上下文(this指向)的方法。
1. call() 方法
call() 方法允许您调用一个具有给定this值和参数的函数。它接受一个this值和一个参数列表。当使用call()方法调用函数时,第一个参数将成为函数内部的this值,后续参数将被传递给函数作为参数。
例如:
javascript
function greet(name) {
console.log(`Hello, ${name}! I am ${this.name}.`);
}
const person = { name: 'Alice' };
greet.call(person, 'Bob');
// 输出: Hello, Bob! I am Alice.
2. apply() 方法
apply() 方法与call()方法类似,它也允许您调用一个具有给定this值和参数的函数。不同之处在于,apply()方法接受一个this值和一个参数数组。
例如:
javascript
function greet(name) {
console.log(`Hello, ${name}! I am ${this.name}.`);
}
const person = { name: 'Alice' };
greet.apply(person, ['Bob']);
// 输出: Hello, Bob! I am Alice.
3. bind() 方法
bind() 方法创建一个新的函数,该函数在调用时将指定的this值和参数传递给原始函数。与call()和apply()方法不同,bind()方法不会立即执行函数,而是返回一个新函数,该函数在调用时将具有指定的this值。
例如:
javascript
function greet(name) {
console.log(`Hello, ${name}! I am ${this.name}.`);
}
const person = { name: 'Alice' };
const greetPerson = greet.bind(person);
greetPerson('Bob');
// 输出: Hello, Bob! I am Alice.
总结:call()和apply()方法可以立即调用函数并改变函数的this值,而bind()方法则创建一个新的函数,该函数在调用时具有指定的this值。
ES6
let vs var
在JavaScript中,let
和var
都是用来声明变量的关键字,但它们之间有一些区别。
- 作用域:
var
声明的变量的作用域是整个函数,而let
声明的变量的作用域是块级作用域,比如{}
内部。 - 变量提升:使用
var
声明的变量存在变量提升,即在声明变量之前就可以访问该变量,而使用let
声明的变量不存在变量提升,只有在声明之后才能访问该变量。 - 重复声明:使用
var
可以重复声明同一个变量,而使用let
在同一个作用域内不能重复声明同一个变量。 - 全局对象属性:使用
var
声明的全局变量会成为全局对象的属性,而使用let
声明的全局变量不会成为全局对象的属性。
let vs const
在JavaScript中,let
和const
都是用来声明变量的关键字,但它们之间有一些区别。
-
可变性:使用
let
声明的变量是可变的,即可以重新赋值。而使用const
声明的变量是不可变的,即一旦赋值就不能再改变。 -
块级作用域:
let
和const
都有块级作用域,即在{}
内部声明的变量只在该块内有效。 -
变量提升:
let
声明的变量不存在变量提升,而const
也不存在变量提升。 -
重复声明:在同一个作用域内,使用
let
和const
都不能重复声明同一个变量。
案例-块级作用域
以下是一个简单的 JavaScript 示例,演示了块级作用域的概念:
javascript
function blockScopeExample() {
var x = 10;
if (true) {
var y = 20; // y在整个函数作用域内都是可见的
let z = 30; // z只在if语句块内部可见
console.log(x); // 10
console.log(y); // 20
console.log(z); // 30
}
console.log(x); // 10
console.log(y); // 20
console.log(z); // Uncaught ReferenceError: z is not defined
}
blockScopeExample();
在这个示例中,变量 x
在整个函数作用域内都是可见的,而变量 y
使用 var
声明也在整个函数作用域内可见,但变量 z
使用 let
声明只在 if
语句块内部可见。当我们尝试在 if
语句块外部访问变量 z
时,会收到一个 ReferenceError
,因为 z
只在 if
语句块内部有效,这展示了块级作用域的概念。
箭头函数
ES6箭头函数是一种简洁的函数定义语法,它使用箭头符号(=>)来声明函数。箭头函数具有以下特点:
1. 只有一个形参时省略小括号
2. 只有只有一句代码,返回值时省略{}
3. map示例
4. 对象特殊情况
5. 没有arguments
在箭头函数中,没有自己的 arguments 对象。箭头函数的参数是固定的,它们不会像普通函数那样具有自己的 arguments 对象。如果需要访问参数,可以直接使用参数的名称来获取参数的值,而不是通过 arguments 对象。
例如:
ini
const sum = (a, b) => {
console.log(a + b);
};
sum(2, 3); // 输出 5
在上面的例子中,箭头函数直接使用参数 a 和 b 来获取传入的值,而不是使用 arguments 对象。
6. 箭头函数没有this
例如:
在下面的例子中,箭头函数内部的 this 指向的是定义该箭头函数时的上下文中的 this,而不是在调用时的上下文中的 this。
javascript
function Person(name)
{
this.name = name;
this.greet = function()
{
setTimeout(() =>
{
console.log('Hello, my name is ' + this.name);
}, 1000);
};
}
const person1 = new Person('John');
person1.greet(); // 输出 "Hello, my name is John"(在1秒后)
在这个例子中,箭头函数内部的 this 指向的是 Person 函数内部的 this,而不是 setTimeout 函数的上下文中的 this。
ES6的解构赋值
ES6的解构赋值是一种方便的语法,用于从数组或对象中提取数据,并赋值给变量。它可以让我们更快速地获取和使用数组或对象中的数据。
1. 数组解构赋值:
ini
// 基本数组解构赋值
const numbers = [1, 2, 3];
const [a, b, c] = numbers;
console.log(a); // 输出 1
console.log(b); // 输出 2
console.log(c); // 输出 3
// 交换变量的值
let x = 1;
let y = 2;
[x, y] = [y, x];
console.log(x); // 输出 2
console.log(y); // 输出 1
2. 对象解构赋值:
arduino
// 基本对象解构赋值
const person = { name: 'John', age: 30 };
const { name, age } = person;
console.log(name); // 输出 'John'
console.log(age); // 输出 30
// 使用不同的变量名
const { name: personName, age: personAge } = person;
console.log(personName); // 输出 'John'
console.log(personAge); // 输出 30
ES6的解构赋值能够简化代码,使得从数组和对象中提取数据更加方便和直观。
ES6的对象简写
ES6引入了对象字面量的简写语法,使得在创建对象时更加简洁和方便。这种简写语法可以让我们更快速地定义对象,尤其在属性名和变量名一致的情况下非常实用。
1. 基本对象简写:
ini
const name = 'John';
const age = 30;
// 使用变量名作为属性名
const person = { name, age };
console.log(person); // 输出 { name: 'John', age: 30 }
在这个例子中,我们使用变量 name 和 age 直接作为对象的属性名,而不需要再写成 { name: name, age: age } 的形式。
2. 方法简写:
javascript
// 使用箭头函数作为方法
const person = {
name: 'John',
greet() {
console.log('Hello, my name is ' + this.name);
}
};
person.greet(); // 输出 "Hello, my name is John"
在这个例子中,我们可以直接在对象字面量中使用箭头函数来定义方法,而不需要再写成 greet: function() { ... } 的形式。
ES6展开运算符
ES6引入了展开运算符(Spread Operator),它是一种方便的语法,用于展开数组和对象。展开运算符可以在创建数组和对象、函数调用、数组拷贝等场景中非常有用。
1. 展开数组:
ini
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5];
console.log(arr2); // 输出 [1, 2, 3, 4, 5]
在这个例子中,展开运算符...用于将arr1数组中的元素展开,然后将4和5添加到新数组arr2中。
2. 合并数组:
ini
const arr1 = [1, 2, 3];
const arr2 = [4, 5];
const mergedArray = [...arr1, ...arr2];
console.log(mergedArray); // 输出 [1, 2, 3, 4, 5]
在这个例子中,我们使用展开运算符来合并两个数组,创建一个新的数组mergedArray。
3. 展开对象:
ini
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 };
console.log(obj2); // 输出 { a: 1, b: 2, c: 3 }
在这个例子中,展开运算符...用于将obj1对象中的属性展开,然后添加属性c到新对象obj2中。
对原没有影响
ES6模块化语法
私密不漏
导出export
导入 import
重名不怕
在ES6模块化语法中,可以使用as
关键字给导入的模块成员(变量、函数、类等)进行重命名,以解决重名的问题。
例如,假设我们有两个模块 math.js
和 utils.js
,它们都导出了一个名为 add
的函数:
javascript
// math.js
export function add(a, b) {
return a + b;
}
// utils.js
export function add(a, b) {
return a + b;
}
在另一个模块中,我们可以使用as
关键字给导入的函数进行重命名,以区分它们:
javascript
import { add as mathAdd } from './math.js';
import { add as utilsAdd } from './utils.js';
console.log(mathAdd(2, 3)); // 输出:5
console.log(utilsAdd(2, 3)); // 输出:5
在上述示例中,我们通过as
关键字将 math.js
中的 add
函数重命名为 mathAdd
,将 utils.js
中的 add
函数重命名为 utilsAdd
,以避免重名冲突。
依赖不乱
当一个模块依赖于其他模块时,可以使用import
关键字引入所需的模块。通过指定模块的路径,可以将其他模块中导出的功能引入到当前模块中使用。
例如,假设我们有两个模块 math.js
和 utils.js
,其中 math.js
导出了一个名为 add
的函数,而 utils.js
依赖于 math.js
中的 add
函数:
javascript
// math.js
export function add(a, b) {
return a + b;
}
// utils.js
import { add } from './math.js';
export function multiply(a, b) {
return add(a, b) * 2;
}
在上述示例中,utils.js
使用import
关键字引入了 math.js
中的 add
函数,并在 multiply
函数中使用了它。这样,utils.js
就解决了对 math.js
的依赖。
在另一个模块中,我们可以直接使用 utils.js
中导出的功能,而不需要关心它与 math.js
的依赖关系:
javascript
import { multiply } from './utils.js';
console.log(multiply(2, 3)); // 输出:10
需要注意的是,模块之间的依赖关系应该通过import
语句进行明确声明,以确保模块的正确加载顺序。这样可以确保在使用某个模块时,它所依赖的模块已经被正确加载和执行。
默认导出
javascript
// math.js
export default function multiply(a, b) {
return a * b;
}
javascript
// main.js
import multiply from './math.js';
console.log(multiply(2, 3)); // 输出:6
总结
月色真美