05 点运算符与 this 关键字
loyalvi Lv7

05 点运算符与 This 关键字

点运算符

点运算符可用来操作对象的属性。这里的操作可以分为获取和赋值两种类型。在赋值的情况下,如果对象原来没有所操作的属性则会添加,如果有则会修改其值,例如下面的例子。

1
2
3
4
5
6
7
var person = {
name: "maker"
};
person.age = 15; //添加age属性
console.log(person.name);//获得name属性
person.name = "peter";//修改name属性
console.log(person);//{name: 'peter', age: 15}

this

在 JavaScript 中,this 是一个关键字,用于指向函数的调用上下文。this 的值在函数被调用时确定,而不是在函数被定义时确定。以下是 this 的几种常见用法和规则:

谁直接调用方法,this就指向谁

1. 在全局上下文中

  • 在全局作用域中
    • 在非严格模式下,this 指向全局对象(在浏览器中是 window,在 Node.js 中是 global)。
    • 在严格模式下,thisundefined
    1
    console.log(this); // 在浏览器中输出 window

2. 在函数调用中

  • 普通函数调用
    • 在非严格模式下,this 指向全局对象。
    • 在严格模式下,thisundefined
    1
    2
    3
    4
    function foo() {
    console.log(this);
    }
    foo(); // 在非严格模式下输出 window,在严格模式下输出 undefined
  • 作为对象的方法调用
    • this 指向调用该方法的对象。
    1
    2
    3
    4
    5
    6
    7
    const obj = {
    name: 'Kimi',
    sayName: function() {
    console.log(this.name);
    }
    };
    obj.sayName(); // 输出 'Kimi'

3. 在构造函数中

  • 作为构造函数调用
    • this 指向新创建的对象。
    1
    2
    3
    4
    5
    function 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
    7
    const obj = {
    name: 'Kimi',
    sayName: () => {
    console.log(this.name); // 输出 'undefined',因为箭头函数捕获了全局上下文的 this
    }
    };
    obj.sayName();

5. 使用 callapplybind 方法

  • call 方法
    • 显式地设置 this 的值,并调用函数。
    1
    2
    3
    4
    5
    function greet() {
    console.log(`Hello, ${this.name}!`);
    }
    const user = { name: 'Kimi' };
    greet.call(user); // 输出 'Hello, Kimi!'
  • apply 方法
    • 类似于 call,但接受一个参数数组。
    1
    2
    3
    4
    function sum(a, b) {
    console.log(a + b);
    }
    sum.apply(null, [1, 2]); // 输出 3
  • bind 方法
    • 创建一个新函数,其 this 值被永久绑定到指定的对象。
    1
    2
    3
    4
    5
    6
    function greet() {
    console.log(`Hello, ${this.name}!`);
    }
    const user = { name: 'Kimi' };
    const boundGreet = greet.bind(user);
    boundGreet(); // 输出 'Hello, Kimi!'

注意事项

  • this 的值是动态的:它在函数被调用时确定,而不是在函数定义时确定。
  • 箭头函数不绑定 this:箭头函数中的 this 是从其定义时的上下文中捕获的,而不是在调用时确定的.
  • 使用 callapplybind 可以显式地控制 this 的值,这在某些情况下非常有用,例如在回调函数中保持上下文.
    理解 this 的行为对于编写可维护和可靠的 JavaScript 代码非常重要,特别是在面向对象编程和事件处理中.

call和apply的区别

callapply 都是 JavaScript 中用于调用函数的方法,它们的主要功能是显式地设置函数的 this 值。尽管它们的目的相似,但在调用函数时传递参数的方式上有所不同:

call 方法

  • 语法
    1
    func.call(thisArg, arg1, arg2, ...);
  • 功能
    • call 方法调用一个函数,并显式地设置函数的 this 值为 thisArg
    • 可以传递多个参数给函数,参数是按顺序传递的。
  • 示例
    1
    2
    3
    4
    5
    function 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
    5
    function 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 更为合适。

其他用途

  • 函数继承
    • 可以使用 callapply 来实现构造函数的继承。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function 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
    3
    const numbers = [1, 2, 3, 4, 5];
    const max = Math.max.apply(null, numbers);
    console.log(max); // 输出 5

    总之,callapply 在功能上是相似的,主要区别在于参数的传递方式,选择使用哪一个通常取决于具体的使用场景和参数的形式.

箭头函数的this

箭头函数(Arrow Functions)是 ES6 引入的一种新的函数语法,其特点是简洁的语法和对 this 的特殊处理。以下是关于箭头函数中 this 的一些关键点:

箭头函数的 this 特性

  • 词法作用域
    • 箭头函数不绑定自己的 this,而是捕获其所在上下文的 this 值作为自身的 this 值。这意味着箭头函数中的 this 是在其定义时确定的,而不是在调用时确定的。
  • 不能用作构造函数
    • 箭头函数不能用作构造函数,因此不能使用 new 关键字来创建实例。由于没有自己的 this,箭头函数也无法通过 callapplybind 方法来改变 this 的值.

示例

假设有一个对象 user,其中包含一个普通函数和一个箭头函数:

1
2
3
4
5
6
7
8
9
10
11
const user = {
name: 'Kimi',
regularFunction: function() {
console.log(this.name); // 输出 'Kimi'
},
arrowFunction: () => {
console.log(this.name); // 输出 'undefined',因为箭头函数捕获了全局上下文的 this
}
};
user.regularFunction(); // 输出 'Kimi'
user.arrowFunction(); // 输出 'undefined'

箭头函数的 this 应用场景

  • 回调函数
    • 在使用回调函数时,箭头函数可以保持 this 的上下文不变,避免了使用 bindself 变量来保存 this 的常见做法。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const 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
    11
    const 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 特性,可以更好地利用其简洁的语法和稳定的上下文绑定,编写更清晰和可靠的代码.

ds

在 JavaScript 中,this 是一个特殊的关键字,它的值取决于函数的调用方式,而不是定义的位置。它的指向是动态的,理解 this 的行为是掌握 JavaScript 的重要部分。以下是 this 在不同场景下的详细说明:

一、默认绑定(全局环境)

当函数在全局作用域中被调用时,this 默认指向全局对象:

  • 浏览器环境window(非严格模式)或 undefined(严格模式)。
  • Node.js 环境global(非严格模式)或 undefined(严格模式)。
1
2
3
4
function showThis() {
console.log(this);
}
showThis(); // 浏览器中输出 window(非严格模式)

严格模式下:

1
2
3
4
5
"use strict";
function showThis() {
console.log(this); // 输出 undefined
}
showThis();

二、隐式绑定(方法调用)

当函数作为对象的方法被调用时,this 指向调用该方法的对象

1
2
3
4
5
6
7
const obj = {
name: "Alice",
greet: function() {
console.log(this.name); // 输出 "Alice"
}
};
obj.greet(); // this 指向 obj

三、显式绑定(call、apply、bind)

通过 call()apply()bind() 可以强制指定 this 的值:

  1. callapply:立即调用函数,手动绑定 this
    1
    2
    3
    4
    5
    function sayHello() {
    console.log(`Hello, ${this.name}`);
    }
    const user = { name: "Bob" };
    sayHello.call(user); // 输出 "Hello, Bob"
  2. bind:返回一个新函数,永久绑定 this
    1
    2
    const boundFunc = sayHello.bind(user);
    boundFunc(); // 输出 "Hello, Bob"

四、构造函数中的 this

当使用 new 关键字调用构造函数时,this 指向新创建的实例对象:

1
2
3
4
5
function Person(name) {
this.name = name;
}
const alice = new Person("Alice");
console.log(alice.name); // 输出 "Alice"

五、箭头函数的 this

箭头函数没有自己的 this,它的 this 继承自外层作用域(词法作用域):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const obj = {
name: "Alice",
greet: () => {
console.log(this.name); // 输出 undefined(外层可能是全局)
}
};
obj.greet();
// 更典型的用法:保留外层 this
function Timer() {
this.seconds = 0;
setInterval(() => {
this.seconds++; // 正确指向 Timer 实例
}, 1000);
}

六、事件处理函数中的 this

在 DOM 事件处理函数中,this 指向触发事件的元素:

1
2
3
button.addEventListener("click", function() {
console.log(this); // 输出 button 元素
});

七、回调函数中的 this

回调函数的 this 可能丢失原绑定,常见于 setTimeoutsetInterval 或高阶函数:

1
2
3
4
5
6
7
8
9
10
11
12
const obj = {
name: "Alice",
greet: function() {
setTimeout(function() {
console.log(this.name); // 输出 undefined(this 指向 window)
}, 100);
}
};
// 解决方法:使用箭头函数或 bind
setTimeout(() => { ... }, 100);
// 或
setTimeout(this.greet.bind(this), 100);

八、类中的 this

在 ES6 类中,方法中的 this 默认指向实例,但方法被单独调用时可能丢失绑定:

1
2
3
4
5
6
7
8
9
10
11
class User {
constructor(name) {
this.name = name;
}
greet() {
console.log(this.name);
}
}
const user = new User("Bob");
const greet = user.greet;
greet(); // 报错:此时 this 为 undefined(严格模式)

九、其他注意事项

  1. 严格模式:在严格模式下,未绑定的 thisundefined
  2. 模块化环境:在 ES6 模块中,顶层的 thisundefined(而非 window)。

总结

this 的指向规则可以简化为:

  1. 谁调用,this 指向谁(隐式绑定)。
  2. 箭头函数继承外层 this
  3. newcall/apply/bind 可显式设置 this
    理解 this 的关键在于分析函数的调用方式,而非定义位置。在复杂场景中,推荐使用 bind 或箭头函数来明确绑定 this
由 Hexo 驱动 & 主题 Keep
访客数 访问量