从零开始学习javascript ———— this
本专辑是参考了侯策老师出版的书籍《前端开发核心知识进阶》整理的学习笔记。
关于this
指向的问题,我们可以先记住以下几点,后面会依次论证:
- 在 use strict 模式下this指向
undefined
,在非严格模式下this指向window
。 - 通过
call
、apply
、bind
显式调用函数时,this会被绑定到指定参数对象上。(优先级:bind
大于call
、apply
) - 使用
new
方法调用构造函数时,会创建一个新的对象,并且会将this绑定到新创建对象上面,同时给这个对象设置属性和方法 - 关于
function(){}
:通过上下文对象调用函数时,this会指向到这个对象上面,否则指向全局,并且this可以被显式修改 - 关于
() => {}
:箭头函数的this指向是由外层(函数或者全局)作用域决定的,并且this不能被显式修改
全局函数中的this
看一段代码:
function fn1() {
console.log(this);
}
function fn2() {
"use strict"
console.log(this);
}
fn1(); //Window
fn2(); //undefined
复制代码
通过代码我们可以看到,在非严格模式下this指向Window
这个全局对象,严格模式下this指向undefined
通过call
、apply
、bind
修改this指向,以及优先级的问题
基本使用
var target = {
name: "张三"
}
function fn(arg1, arg2) {
console.log(this.name);
console.log(arg1);
console.log(arg2);
}
//call
fn.call(target, 1, 2) //张三 1 2
//apply
fn.apply(target, [3, 4]) //张三 3 4
//bind
const func = fn.bind(target, 5, 6);
func(); // 张三 5 6
复制代码
优先级的问题
我们通常把apply、call、bind
这种修改this的方式,成为显式绑定。那么,它们之间谁的优先级更高呢?
执行代码:
var target1 = {
name: "张三"
}
var target2 = {
name: "李四"
}
function fn(arg1, arg2) {
console.log(this.name);
console.log(arg1);
console.log(arg2);
}
const func = fn.bind(target1, 5, 6);
func(); // 输出:张三 5 6
// 通过call显式指定this,还是输出原本的值
func.call(target2)// 输出:张三 5 6
复制代码
通过上面的代码我们可以看到,func
是一个通过bind
方法构造的函数,并且自动绑定了this
为target1
,通过call显式绑定this为target2
时,输出值依然不变,所以bind的优先级是最高的。此外还需要注意,如果bind时传入了参数,后续给由bind创建的函数传任何参数都是没用的。
不同点
- call和apply参数设定不一样。但是apply有一个特性,接收一个数组参数,但是会将参数
逐一传递
。 - bind是
创建
一个函数,而call、apply是执行
一个函数。
new
调用构造函数时的this问题
关于构造函数和this的问题,我们先来看一段代码:
function Fn() {
this.name = "张三";
this.log = function () {
console.log("log");
}
}
const instance = new Fn();
console.log(instance); //输出:{name:"张三",log:function(){}}
复制代码
上面的代码,往往涉及到一个问题:new调用构造函数的时候,做了什么操作?
- 创建一个新的对象
- 将构造函数的this指向一个新的对象
- 为新创建的对象设置属性和方法
- 返回这个对象
function(){}
中的this
我们先来总结一下在function(){}
中有哪几种改变this的方式:
- 通过
call、apply、bind
显式绑定this- 通过改变上下文调用对象。(举例:obj.fn() 此时this指向obj)
除过上面俩种情况,this都指向
window
(非严格模式)。
参考上面我们得出的结论:运行以下代码,最终会返回true
const obj = {
name: "杨志强",
fn: function () {
return this;
}
}
console.log(obj === obj.fn());
复制代码
还需要我们注意的就是,当存在更复杂的嵌套关系时,this会指向最后调用他的对象:
var target = {
name: "target",
child: {
name: "child",
fn() {
console.log(this);
}
}
}
target.child.fn();// 输出:{name:"child",fn:function(){}}
复制代码
() => {}
中的this
始终记住:箭头函数的this
是由外层(函数或全局作用域)决定的,并且this的指向不能被显式绑定,不能实例化
看一个例子:
我们目的是要输出target
对象中的count
var target = {
count: 1,
fn: function () {
setInterval(function () {
console.log(this);
console.log(this.count);
}, 1000)
}
}
target.fn();// 输出:window undefined
复制代码
分析代码:通过上面学的知识,我们可以知道function
的this
是由上下文对象决定的,否则就指向window
,要想输出count,我们可以通过箭头函数来解决这个问题。
修改代码
var target = {
count: 1,
fn: function () {
setInterval(() => {
console.log(this);
console.log(this.count);
}, 1000)
}
}
target.fn();// 输出:{count:1,fn:function(){}} 1
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END