1、什么是 this?
常见的 this是在一个函数中, JS 的函数调用有两种方式,一种是我们直接调用,另外一种就是通过 new 的方式来调用,我们通过两种方式来打印一下 this值是否相同?。
function Dog(name, color) {
this.name = name;
this.color = color;
console.log(this);
}
Dog('豆豆', 'red') // Window
var dog1 = new Dog('豆豆', 'red') // Dog {name: "豆豆", color: "red"}
补充:当你使用浏览器,全局上下文将是window
。当你使用Node.js,全局上下文就是global
。
2、如何判断 this?
三种 this指向情况:
1、对象调用,this 指向该对象(前边谁调用 this 就指向谁)。
var object = {
name: '张三',
age: 21,
print: function() {
console.log('this指向', this); // this指向 {name: "张三", age: 21, print: ƒ()}
console.log(this.name, this.age); // 张三 21
}
}
// 通过对象的方式调用函数
object.print()
2、直接调用的函数,this 指向的是全局 window 对象。
3、通过 new 的方式,this 永远被绑定在新创建的对象上,任何方式都改变不了 this 的指向。
扩展:箭头函数的 this 指向谁?
// 剪头函数
const obj1 = {
a: () => {
console.log(this)
}
}
obj1.a() // Window
this在箭头函数中失效了,因为这是由于箭头函数没有单独的 this值。箭头函数的 this与声明所在的上下文相同。也就是说调用箭头函数的时候,不会隐式的调用 this参数,而是从定义时的函数继承上下文。
3、如何改变 this 的值?
call、apply、bind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向
1、apply 方法
function fn(...args){
console.log(this,args);
}
let obj = {
myname:"张三"
}
fn.apply(obj,[1,2]); // this会变成传入的obj,传入的参数必须是一个数组;
fn(1,2) // this指向window
2、call 方法
function fn(...args){
console.log(this,args);
}
let obj = {
myname:"张三"
}
fn.call(obj,1,2); // this会变成传入的obj,传入的参数必须是一个数组;
fn(1,2) // this指向window
跟apply一样,改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次
同样的,当第一个参数为null、undefined的时候,默认指向window(在浏览器中)
fn.apply(null,[1,2]); // this指向window
fn.apply(undefined,[1,2]); // this指向window
3、bind 方法
改变this指向后不会立即执行,而是返回一个永久改变this指向的函数
function fn(...args){
console.log(this,args);
}
let obj = {
myname: '张三'
}
const bindFn = fn.bind(obj); // this 也会变成传入的obj ,bind不是立即执行需要执行一次
bindFn(1,2) // this指向obj
fn(1,2) // this指向window
4、call、apply、bind 三者的区别是什么?
共同点:
1、都能改变 this 指向。
2、三者都采用的后续传参的形式。
3、三者第一个参数都是this要指向的对象,如果没有这个参数或参数为undefined或null,则默认指向全局window
不同点:
1、call的传参是单个传递的,而 apply后续传递的参数是数组形式,而 bind没有规定,传递值和数组都可以。且apply和call是一次性传入参数,而bind可以分为多次传入
3、call和 apply函数的执行是立即执行的,而 bind函数会返回一个函数,然后我们想要调用的时候才会执行。
/* 在函数原型上封装myBind函数 , 实现和原生bind函数一样的效果 */
Function.prototype.myBind = function(context) {
// 存储要转移的目标对象
let _this = context? Object(context) : window
// 在转移this的对象上设定一个独一无二的属性 , 并将函数赋值给它
let key = Symbol('key')
_this[key] = this
let args = arguments.length > 1 ? [...arguments].slice(1) : []
// 创建函数闭包
return function() {
// 将所有参数先拆分开,再添加到新数组中,以此来支持多参数传入以及数组参数传入的需求
args = args.concat([...arguments])
// 调用函数
let res = _this[key](...args)
// 删除
delete _this[key]
// 返回函数返回值
return res
}
}
// 测试代码
let obj = {
'name': '张三'
}
function showName(first, second, third) {
console.log(first, second, third);
console.log(this.name);
}
showName.myBind(obj, 7)(8, 9)