宁夏区建设厅网站,招聘网站开发需要多长时间,电子商务网站建设的阶段化分析,保定网站建设推广#x1f6a9; 这个专栏是一个 JS 进阶系列#xff0c;当前内容为 JS 执行机制#xff0c;建议按顺序阅读 执行上下文作用域 词法环境变量环境 this#xff08;上下文对象#xff09; #x1f539; 概述 #x1f30d; 前提概要#xff1a; 在上文 执行上下文 这个专栏是一个 JS 进阶系列当前内容为 JS 执行机制建议按顺序阅读 执行上下文作用域 词法环境变量环境 this上下文对象 概述 前提概要 在上文 执行上下文作用域 中我们已经知道 执行上下文的 thisValue 和 this 等价全局执行上下文的 this 指向全局对象 而函数执行上下文中的 thisValue 指向 我却一笔带过 现在打算放在这篇文章帮它整明白 我们每次调用函数时解析器都会将一个 上下文对象 作为 隐含参数 传递进函数。 使用 this 来引用上下文对象根据函数的 调用方式 不同this 的值也不同。
函数中的 this
普通函数调用
在普通函数调用中this 指向全局对象非严格模式或 undefined严格模式。
举个栗子
let a {b: function () {let func function () {console.log(this); //Window}func(); //普通函数调用},}
a.b(); //打印 Window方法调用
当函数作为对象的方法调用时this 指向调用该方法的对象。
举个栗子
const obj {name: Alice,greet: function() {console.log(this.name);}
};obj.greet(); // 输出: Alice构造函数调用
当函数作为构造函数调用使用 new 关键字时this 指向新创建的对象。
举个栗子
function Person(name) {this.name name;
}const alice new Person(Alice);
console.log(alice.name); // 输出: Alice箭头函数中的 this
箭头函数没有自己的 this它会捕获其所在上下文的 this 值。这意味着箭头函数中的 this 在定义时就已经确定不会因为调用方式而改变。
举个栗子
const obj {name: Alice,greet: function() {setTimeout(() {console.log(this.name);}, 100);}
};obj.greet(); // 输出: Alice类中的 this
类本质上是基于构造函数和原型继承的语法糖 , 在类的方法中this 指向类的实例。
举个栗子
class Person {constructor(name) {this.name name;}greet() {console.log(this.name);}
}const alice new Person(Alice);
alice.greet(); // 输出: Alice使用 call、apply 和 bind
call、apply、bind 方法这三种方法可以明确指定 this 的值 , 即显式设置this
call、apply、bind 原理
call
作用
call 方法用于调用一个函数并设置函数执行时的 this 值同时可以传递参数列表。
语法
func.call(thisArg, arg1, arg2, ...)
thisArg函数执行时的 this 值。arg1, arg2, ...传递给函数的参数列表。
原理
将函数的 this 绑定到 thisArg。立即执行函数并传入参数。
举个例子
const person1 {name: 张三,introduce: function (city, country) {console.log(${this.name} is from ${city}, ${country});},
};
const person2 {name: 李四,
};
person1.introduce.call(person2, 上海, 中国)打印李四 is from 上海, 中国
apply
作用
apply 方法与 call 类似用于调用一个函数并设置 this 值但它的参数是以数组或类数组对象的形式传递的。
语法
func.apply(thisArg, [argsArray])
thisArg函数执行时的 this 值。argsArray传递给函数的参数数组。
原理
apply 的原理与 call 几乎相同唯一的区别是参数传递方式。
仍然是上面那个例子
参数传递 必须是参数数组
person1.introduce.apply(person2, [上海, 中国]);bind
作用
bind 方法用于创建一个新函数并将原函数的 this 值绑定到指定的 thisArg。与 call 和 apply 不同bind 不会立即执行函数而是返回一个绑定了 this 的新函数。
语法
func.bind(thisArg, arg1, arg2, ...): newFunc
thisArg新函数执行时的 this 值。arg1, arg2, ...预先传递给新函数的参数可选。return newFunc: 返回一个绑定了 this 的新函数。
原理
bind 的原理可以理解为
返回一个新函数。 bind 不会改变原函数而是返回一个新的函数。 新函数执行时this 被绑定到 thisArg。 新函数的 this 值会被固定为传入的 第一个参数。例如 f.bind(obj) 实际上可以理解为 obj.f()这时f 函数体内的 this 自然指向的是 obj 可以预先传递部分参数柯里化。 可以在调用新函数时传入额外的参数这些参数会在调用时被传递给原函数。
预设参数
案例1
function multiply(a, b) {return a * b;
}
const double multiply.bind(null, 2); // 固定第一个参数为2
console.log(double(5)); // 输出: 10在这个例子中
null 是固定的 this 值因为我们不需要设置 this。2 是预设的第一个参数对应原函数的 a而在调用 double(5) 时5 会作为第二个参数对应原函数的 b传递。double 函数实际上是 multiply 函数的一个“封装”它将第一个参数固定为 2而 this 的值被设置为 null这在这里并不重要因为 multiply 函数并没有使用 this。
案例 2
function f(y, z){return this.x y z;
}
let m f.bind({x : 1}, 2);
console.log(m(3));
//6在这个例子中
参数{x : 1} 这里bind方法会把它的第一个实参绑定给f函数体内的 this所以这里的 this即指向{x : 1}对象 **参数 **2 从第二个参数起会依次传递给原始函数这里的第二个参数 2即是 f 函数的 y参数 **参数 **3 最后调用 m(3)的时候这里的 3 便是最后一个参数 z 了所以执行结果为 1 2 3 6
分步处理参数的过程其实是一个典型的 函数柯里化 的过程Curry
案例
分析代码
let a {b: function () {let func function () {console.log(this.c);//undefined}func(); //普通函数调用},c : Hello!}
a.b(); // undefinedundefined的 原因 func 函数是在 a.b() 方法内定义的调用时是作为一个普通函数调用而不是作为对象的方法调用。这导致 this 的指向变成了全局对象在浏览器中是 window而不是对象 a 。 在学习完所有this指向的场景后你能想出不同的方法去使得this.c能正常访问吗
解决方法
赋值
可以通过赋值的方式将 this 赋值给 that
let a {b: function () {let self this //将 this 赋值给 thatlet func function () {console.log(self.c);//修改成self}func();},c: Hello!}
a.b(); //输出: Hello!使用箭头函数
let a {b: function () {let func () {console.log(this.c);}func();},c: Hello!
}
a.b(); // 输出: Hello!使用call / apply
let a {b: function () {let func function () {console.log(this.c);}func.call(this); //call},c: Hello!
}
a.b(); // 输出: Hello!使用 bind方法
//写法一
let a {b: function() {let func function() {console.log(this.c);}.bind(this); //返回新函数 覆盖 func();},c: Hello!
}
a.b(); // 输出: Hello!//写法二
let a {b : function(){let func function(){console.log(this.c);}func.bind(this)(); //立即执行},c : Hello!
}a.b(); // 输出: Hello!