文章目录
一、this的绑定规则
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(箭头函数不一样,箭头函数没有自己的this, 它的this是继承而来; 默认指向在定义它时所处的对象(宿主对象))
以下是this绑定的五种规则
1、默认绑定(严格/非严格模式)
2、隐式绑定
3、显式绑定
4、new绑定
5、箭头函数绑定
1.默认绑定(严格和非严格模式)
独立函数调用时,此时this绑定采用默认绑定,this指向window
严格模式下,不能将全局对象用于默认绑定,this会绑定到undefined。只有函数运行在非严格模式下,默认绑定才能绑定到全局对象。
var a = "window";
function foo(){
console.log(this.a)
}
foo();//此时输出的值为:window
"use strict";
var a = "window";
function foo(){
console.log(this.a)
}
foo();//报错,Uncaught TypeError: Cannot read property 'a' of undefined
2.隐式绑定
当函数引用有上下文对象时,隐式绑定规则会把函数中的this绑定到这个上下文对象。对象属性引用链中只有上一层或者说最后一层在调用中起作用。
function fn() {
console.log(this.a);
}
var obj = {
a:100,
fn:fn
}
obj.fn(); //输出结果是100
3.显示绑定
通过call(…) 或者 apply(…)方法。第一个参数是一个对象,在调用函数时将这个对象绑定到this。因为直接指定this的绑定对象,称之为显示绑定。
function fn() {
console.log(this.a)
}
var obj = {
a:100
}
fn.call(obj); //100
fn.apply(obj); //100
4.new绑定
在JS中,构造函数只是使用new操作符时被调用的普通函数,他们不属于某个类,也不会实例化一个类。
包括内置对象函数(比如Number(…))在内的所有函数都可以用new来调用,这种函数调用被称为构造函数调用。
实际上并不存在所谓的“构造函数”,只有对于函数的“构造调用”。
使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
1、创建(或者说构造)一个新对象。
2、这个新对象会被执行[[Prototype]]连接。
3、这个新对象会绑定到函数调用的this。
4、如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
使用new来调用foo(…)时,会构造一个新对象并把它(bar)绑定到foo(…)调用中的this。
function fn(a) {
this.a = a;
}
var obj = new fn(a);
console.log(obj.a)
5.箭头函数绑定
其实大部分情况下可以用一句话来概括,this总是指向调用该函数的对象。
但是对于箭头函数并不是这样,是根据外层(函数或者全局)作用域(词法作用域)来决定this。
看一下例子:
普通函数:
var a = "window"
var obj1 = {
a:"obj1",
fn(){
console.log(this.a)
}
}
var obj2 = {
a:"obj2"
}
obj1.fn() //输出为obj1
obj1.fn.call(obj2) //输出为obj2,call改变了this的指向,指向obj2
箭头函数
var a = "window"
var obj1 = {
a:"obj1",
fn: () => {
console.log(this.a)
}
}
var obj2 = {
a:"obj2"
}
obj1.fn() //输出为window
obj1.fn.call(obj2) //输出为window,call无法改变箭头函数的this的指向
对于箭头函数的this总结如下:
箭头函数不绑定this,箭头函数中的this相当于普通变量。
箭头函数的this寻值行为与普通变量相同,在作用域中逐级寻找。
箭头函数的this无法通过bind,call,apply来直接修改(可以间接修改,改变作用域中this的指向可以改变箭头函数的this。)。
二、call、apply、bind的区别
call()和apply()和bind()共同点都是可以改变this指向
call和apply的区别在于两者接受参数不同,call()接受的是一个个的参数,而apply()接受的是一个包含多个参数的数组
看一下例子:
var fn = function(a,b,c){
...
};
var obj = {...};
fn.call(obj,a,b,c); //call,参数列表
fn.apply(obj,[a,b,c]) //apply,参数为数组
三、call、apply、bind的实现
1.call
Function.prototype.Mycall = function(){
let [obj,...args] = [...arguments];
if(!obj){
obj = typeof window === "undefine"?global:window;
}
obj.fn = this;
let result = obj.fn(...args);
delete obj.fn;
return result;
}
2.apply
Function.prototype.Myapply = function(){
let [obj,args] = [...arguments];
if(!obj){
obj = typeof window === "undefine"?global:window;
}
obj.fn = this;
var result;
if(args){
if(!Array.isArray(args)){
throw new Error("参数应为数组")
}else{
result = obj.fn(...args);
}
}else{
result = obj.fn();
}
delete obj.fn;
return result;
}
3.bind
```Function.prototype.Mybind = function () {
let [ctx,...args] = [...arguments];
const self = this;
return function (...args2) {
return self.apply(ctx, [...args, ...args2])
}
}
总结
本文仅供自己学习保留