05 点运算符与 This 关键字
点运算符
点运算符可用来操作对象的属性。这里的操作可以分为获取和赋值两种类型。在赋值的情况下,如果对象原来没有所操作的属性则会添加,如果有则会修改其值,例如下面的例子。
1 | var person = { |
this
在 JavaScript 中,this 是一个关键字,用于指向函数的调用上下文。this 的值在函数被调用时确定,而不是在函数被定义时确定。以下是 this 的几种常见用法和规则:
谁直接调用方法,this就指向谁
1. 在全局上下文中
- 在全局作用域中:
- 在非严格模式下,
this指向全局对象(在浏览器中是window,在 Node.js 中是global)。 - 在严格模式下,
this是undefined。
1
console.log(this); // 在浏览器中输出 window
- 在非严格模式下,
2. 在函数调用中
- 普通函数调用:
- 在非严格模式下,
this指向全局对象。 - 在严格模式下,
this是undefined。
1
2
3
4function foo() {
console.log(this);
}
foo(); // 在非严格模式下输出 window,在严格模式下输出 undefined - 在非严格模式下,
- 作为对象的方法调用:
this指向调用该方法的对象。
1
2
3
4
5
6
7const obj = {
name: 'Kimi',
sayName: function() {
console.log(this.name);
}
};
obj.sayName(); // 输出 'Kimi'
3. 在构造函数中
- 作为构造函数调用:
this指向新创建的对象。
1
2
3
4
5function Person(name) {
this.name = name;
}
const person = new Person('Kimi');
console.log(person.name); // 输出 'Kimi'
4. 在箭头函数中
- 箭头函数没有自己的
this:- 箭头函数中的
this是从其定义时的上下文中捕获的。 - 通常指向定义箭头函数时的
this值。
1
2
3
4
5
6
7const obj = {
name: 'Kimi',
sayName: () => {
console.log(this.name); // 输出 'undefined',因为箭头函数捕获了全局上下文的 this
}
};
obj.sayName(); - 箭头函数中的
5. 使用 call、apply 和 bind 方法
call方法:- 显式地设置
this的值,并调用函数。
1
2
3
4
5function greet() {
console.log(`Hello, ${this.name}!`);
}
const user = { name: 'Kimi' };
greet.call(user); // 输出 'Hello, Kimi!'- 显式地设置
apply方法:- 类似于
call,但接受一个参数数组。
1
2
3
4function sum(a, b) {
console.log(a + b);
}
sum.apply(null, [1, 2]); // 输出 3- 类似于
bind方法:- 创建一个新函数,其
this值被永久绑定到指定的对象。
1
2
3
4
5
6function greet() {
console.log(`Hello, ${this.name}!`);
}
const user = { name: 'Kimi' };
const boundGreet = greet.bind(user);
boundGreet(); // 输出 'Hello, Kimi!'- 创建一个新函数,其
注意事项
this的值是动态的:它在函数被调用时确定,而不是在函数定义时确定。- 箭头函数不绑定
this:箭头函数中的this是从其定义时的上下文中捕获的,而不是在调用时确定的. - 使用
call、apply和bind可以显式地控制this的值,这在某些情况下非常有用,例如在回调函数中保持上下文.
理解this的行为对于编写可维护和可靠的 JavaScript 代码非常重要,特别是在面向对象编程和事件处理中.
call和apply的区别
call 和 apply 都是 JavaScript 中用于调用函数的方法,它们的主要功能是显式地设置函数的 this 值。尽管它们的目的相似,但在调用函数时传递参数的方式上有所不同:
call 方法
- 语法:
1
func.call(thisArg, arg1, arg2, ...);
- 功能:
call方法调用一个函数,并显式地设置函数的this值为thisArg。- 可以传递多个参数给函数,参数是按顺序传递的。
- 示例:
1
2
3
4
5function greet(lang, punctuation) {
console.log(`Hello ${this.name} in ${lang}${punctuation}`);
}
const user = { name: 'Kimi' };
greet.call(user, 'English', '!'); // 输出 'Hello Kimi in English!'
apply 方法
- 语法:
1
func.apply(thisArg, [argsArray]);
- 功能:
apply方法调用一个函数,并显式地设置函数的this值为thisArg。- 参数以数组的形式传递给函数。
- 示例:
1
2
3
4
5function greet(lang, punctuation) {
console.log(`Hello ${this.name} in ${lang}${punctuation}`);
}
const user = { name: 'Kimi' };
greet.apply(user, ['English', '!']); // 输出 'Hello Kimi in English!'
区别
- 参数传递方式:
call传递参数是按顺序传递的,每个参数都是单独列出的。apply传递参数是通过一个数组传递的,所有参数都在一个数组中。
- 适用场景:
- 当参数数量固定且已知时,
call更为方便。 - 当参数数量不确定或参数已经以数组形式存在时,
apply更为合适。
- 当参数数量固定且已知时,
其他用途
- 函数继承:
- 可以使用
call和apply来实现构造函数的继承。
1
2
3
4
5
6
7
8
9
10function Parent(name) {
this.name = name;
}
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
const child = new Child('Kimi', 25);
console.log(child.name); // 输出 'Kimi'
console.log(child.age); // 输出 25 - 可以使用
- Math 函数调用:
apply可以用于调用Math对象的方法,特别是当参数是数组时。
1
2
3const numbers = [1, 2, 3, 4, 5];
const max = Math.max.apply(null, numbers);
console.log(max); // 输出 5总之,
call和apply在功能上是相似的,主要区别在于参数的传递方式,选择使用哪一个通常取决于具体的使用场景和参数的形式.
箭头函数的this
箭头函数(Arrow Functions)是 ES6 引入的一种新的函数语法,其特点是简洁的语法和对 this 的特殊处理。以下是关于箭头函数中 this 的一些关键点:
箭头函数的 this 特性
- 词法作用域:
- 箭头函数不绑定自己的
this,而是捕获其所在上下文的this值作为自身的this值。这意味着箭头函数中的this是在其定义时确定的,而不是在调用时确定的。
- 箭头函数不绑定自己的
- 不能用作构造函数:
- 箭头函数不能用作构造函数,因此不能使用
new关键字来创建实例。由于没有自己的this,箭头函数也无法通过call、apply或bind方法来改变this的值.
- 箭头函数不能用作构造函数,因此不能使用
示例
假设有一个对象 user,其中包含一个普通函数和一个箭头函数:
1 | const user = { |
箭头函数的 this 应用场景
- 回调函数:
- 在使用回调函数时,箭头函数可以保持
this的上下文不变,避免了使用bind或self变量来保存this的常见做法。
1
2
3
4
5
6
7
8
9
10const timer = {
seconds: 0,
start() {
setInterval(() => {
this.seconds++;
console.log(this.seconds);
}, 1000);
}
};
timer.start(); // 每秒输出递增的 seconds 值 - 在使用回调函数时,箭头函数可以保持
- 事件处理:
- 在事件处理中,箭头函数可以确保
this指向预期的对象,而不需要额外的绑定操作。
1
2
3
4
5
6
7
8
9
10
11const button = document.getElementById('myButton');
const handler = {
count: 0,
onClick() {
button.addEventListener('click', () => {
this.count++;
console.log(`Clicked ${this.count} times`);
});
}
};
handler.onClick(); - 在事件处理中,箭头函数可以确保
注意事项
- 全局上下文中使用箭头函数:
- 在全局上下文中,箭头函数的
this指向全局对象(在浏览器中是window,在 Node.js 中是global)。
- 在全局上下文中,箭头函数的
- 模块作用域:
- 在 ES6 模块中,箭头函数的
this指向模块的上下文,通常是undefined(严格模式下)或全局对象(非严格模式下).
通过理解箭头函数的this特性,可以更好地利用其简洁的语法和稳定的上下文绑定,编写更清晰和可靠的代码.
- 在 ES6 模块中,箭头函数的
ds
在 JavaScript 中,this 是一个特殊的关键字,它的值取决于函数的调用方式,而不是定义的位置。它的指向是动态的,理解 this 的行为是掌握 JavaScript 的重要部分。以下是 this 在不同场景下的详细说明:
一、默认绑定(全局环境)
当函数在全局作用域中被调用时,this 默认指向全局对象:
- 浏览器环境:
window(非严格模式)或undefined(严格模式)。 - Node.js 环境:
global(非严格模式)或undefined(严格模式)。
1 | function showThis() { |
严格模式下:
1 | ; |
二、隐式绑定(方法调用)
当函数作为对象的方法被调用时,this 指向调用该方法的对象:
1 | const obj = { |
三、显式绑定(call、apply、bind)
通过 call()、apply() 或 bind() 可以强制指定 this 的值:
call和apply:立即调用函数,手动绑定this。1
2
3
4
5function sayHello() {
console.log(`Hello, ${this.name}`);
}
const user = { name: "Bob" };
sayHello.call(user); // 输出 "Hello, Bob"bind:返回一个新函数,永久绑定this。1
2const boundFunc = sayHello.bind(user);
boundFunc(); // 输出 "Hello, Bob"
四、构造函数中的 this
当使用 new 关键字调用构造函数时,this 指向新创建的实例对象:
1 | function Person(name) { |
五、箭头函数的 this
箭头函数没有自己的 this,它的 this 继承自外层作用域(词法作用域):
1 | const obj = { |
六、事件处理函数中的 this
在 DOM 事件处理函数中,this 指向触发事件的元素:
1 | button.addEventListener("click", function() { |
七、回调函数中的 this
回调函数的 this 可能丢失原绑定,常见于 setTimeout、setInterval 或高阶函数:
1 | const obj = { |
八、类中的 this
在 ES6 类中,方法中的 this 默认指向实例,但方法被单独调用时可能丢失绑定:
1 | class User { |
九、其他注意事项
- 严格模式:在严格模式下,未绑定的
this是undefined。 - 模块化环境:在 ES6 模块中,顶层的
this是undefined(而非window)。
总结
this 的指向规则可以简化为:
- 谁调用,
this指向谁(隐式绑定)。 - 箭头函数继承外层
this。 new、call/apply/bind可显式设置this。
理解this的关键在于分析函数的调用方式,而非定义位置。在复杂场景中,推荐使用bind或箭头函数来明确绑定this。