一、this定义
this是一个对象,在不同情况在指向不同的对象
当一个函数被调用的时候回产生一个对象(调用方式,调用地点,参数等等)
一般来说我们用this指向全局作用域或者局部作用域来代替当前使用的对象。
使用的用途主要有:
1,作为对象方法来调用
2,作为构造函数来调用
3.使用call或者apply改变this方向后调用
二、this指向
先上结论
1、对象调用this,调用那个对象this指向那个对象
2、没有定义就直接调用this函数 ,this指向全局作用域
3、通过new的方式调用时,this永远指向new的新对象。
4、箭头函数中的this,this指向定义函
对象调用
this对象调用比较简单,前面调用了那个对象,this就指向谁
数的继承上下文
var person ={
name:'十九'
age:‘22’
print:function(){
console.log(this)
console.log(this.nmae+‘:’+this.age)
}
}
person.print();
//this 指向的就是当前对象person
直接调用的函数
直接调用函数的时候this指向的是全局window函数
function print(){
cnsole.log(this);
}
print();
//this 指向全局作用域
通过new方式调用的函数
new方法调用的函数 this永远指向新创建的对象
function person(name,age){
this.name = name ;
this.age = age ;
console.log (this);
var shijiu = new person (‘十九’,22);
//this指向的就是新穿件的new函数
}
箭头函数中的this
箭头函数中的this要注意的没有单独的this值,箭头函数中的this与定义函数的上下文相同。
const person = {
a:() => {
console.log(this);
}
}
//对象调用箭头函数,
person.a();//this指向的是window
三、this指向改变
改变this指向有三种方法:
call
apply
bind
call
call中第一个参数是this指向,后面的参数是this的传参
function fn(x,y){
console.log(this);
}
var obj = {
name:"pc"
}
fn(1,2);
fn.call(obj,1,2);
apply
apply第一个参数是this指向,后面的参数用数组表示
function fn(x,y){
console.log(this);
}
var obj = {
name:"pc"
}
fn(1,2);
fn.apply(obj,[1,2]);
bind
bind只改变this指向,参数需要手动传递
function fn(x,y){
console.log(this);
}
var obj = {
name:"zs"
}
fn(1,2);
fn.bind(obj,1,2)();
三种方法相同点和不同点
共同点:
三者都能改变this指向,且第一个传递的参数都是this指向的对象,都是采用后续传参的形式
不同点:
call的传参是单个传递的,而apply传递的是数组,bind没有规定,单的参数和数组都可以。
call和apply的函数都是直接执行的,而bind函数会返回一个函数,调用的时候才会执行。
下面的内容是扩展内容:
手写call apply bind 源码
手写call
首先 context 为可选参数,如果不传的话默认上下文为 window ;
接下来给 context 创建一个 fn 属性,并将值设置为需要调用的函数;
因为 call 可以传入多个参数作为调用函数的参数,所以需要将参数剥离出来;
然后调用函数并将对象上的函数删除。
// this 为调用的函数
// context 是参数对象
Function.prototype.myCall = function(context){
// 判断调用者是否为函数
if(typeof this !== 'function'){
throw new TypeError('Error')
}// 不传参默认为 window
context = context || window
// 新增 fn 属性,将值设置为需要调用的函数
context.fn = this
// 将 arguments 转化为数组将 call 的传参提取出来 [...arguments]
const args = Array.from(arguments).slice(1)
// 传参调用函数
const result = context.fn(...args)
// 删除函数
delete context.fn
// 返回执行结果
return result;
}
// 普通函数
function print(age){
console.log(this.name+" "+age);
}
// 自定义对象
var obj = { name:'pc' }
// 调用函数的 call 方法
print.myCall(obj,1,2,3)
手写apply
首先 context 为可选参数,如果不传的话默认上下文为 window
接下来给 context 创建一个 fn 属性,并将值设置为需要调用的函数
因为 apply 传参是数组传参,所以取得数组,将其剥离为顺序参数进行函数调用
然后调用函数并将对象上的函数删除
// 手写一个 apply 方法
Function.prototype.myApply = function(context){
// 判断调用者是否为函数
if(typeof this !== 'function'){
throw new TypeError('Error')
}
// 不传参默认为
window context = context || window
// 新增 fn 属性,将值设置为需要调用的函数
context.fn = this // 返回执行结果 let result;
// 判断是否有参数传入
if(arguments[1]){
result = context.fn(...arguments[1])
}else{
result = context.fn()
}
// 删除函数 delete context.fn
// 返回执行结果 return result;
}
// 普通函数
function print(age,age2,age3){
console.log(this.name+" "+ age + " "+ age2+" "+age3);
}
// 自定义对象
var obj = {
name:'pc'
}
// 调用函数的 call 方法
print.myApply(obj,[1,2,3])
手写bind
判断调用者是否为函数。
截取参数,注意:这里有两种形式传参。
返回一个函数,判断外部哪种方式调用了该函数(new | 直接调用)
// 手写一个 bind 函数
Function.prototype.myBind = function (context) {
// 判断调用者是否为函数
if(typeof this !== 'function'){
throw new TypeError('Error')
}
// 截取传递的参数
const args = Array.from(arguments).slice(1)
// _this 指向调用的函数
const _this = this;
// 返回一个函数
return function F(){
// 因为返回了一个函数,我们可以 new F(),所以需要判断
// 对于 new 的情况来说,不会被任何方式改变 this
if(this instanceof F){
return new _this(...args,...arguments)
}else{
return _this.apply(context,args.concat(...arguments))
}
}
}
// 普通函数
function print(){
// new 的方式调用 bind 参数输出换做 [...arguments]
console.log(this.name);
}
// 自定义对象
var obj = { name:'pc' }
/ 调用函数的 call 方法
let F = print.myBind(obj,1,2,3);
// 返回对象
let obj1 = new F();
console.log(obj1);
//this用法总结:
// 当以函数调用时this是window
// 当以方法的形式调用时,谁调用方法this就是谁
// 当以构造函数的形式调用时,this就是新创建的那个对象
// 用函数的方式调用时this指向的是window
// 用方法调用this时执行的是调用方法的对象
// this指向的是一个对象 这个对象称为函数执行的上下文对象
// 根据函数调用方式不同,this指向不同的对象