1、默认绑定
// "use strict";
var a = 2;
function foo(){
console.log(this.a);
}
// 1、非严格模式下 this 指向 window
// 2、严格模式下 this 指向 undefined
foo()
// 3、只在严格模式下调用foo(),则不影响默认绑定
(function(){
"use strict";
foo();
})()
2、隐式绑定 & 只和执行时所在的上下文相关
隐式绑定
function foo(){
console.log(this.a);
}
var obj = {
a:2,
foo:foo
}
obj.foo(); // 2 foo执行时上下文为 obj
隐式丢失:重新赋值
function foo(){
console.log(this.a);
}
var obj = {
a:2,
foo:foo
}
var a = "ops, global"
var bar = obj.foo;
bar(); // ops, globa 等同于直接调用了foo()
隐式丢失:隐式赋值( 函数传参 )
function foo(){
console.log(this.a);
}
function doFoo(fn){
fn(); // 只看函数调用的位置 - this默认指向window
}
var obj = {
a:2,
foo:foo
}
var a = "ops, global"
4、new方法调用构造函数
- this 指向创建的实例
- new 的作用
- 调用这个函数
- 创建一个空对象( 函数对象 )
- 让函数中的this指向这个新对象
- 默认返回这个实例对象,如果手动返回值
- return 'aaaa'; // 返回基础值,不影响this指向
- return {}; // 返回一个对象,this指向新对象
function Fn(a) {
this.a = a;
}
var bar = new Fn( 2 );
console.log( bar.a );// 2 this指向当前实例
function fn(){
//构造函数上的num
this.num = 10;
//默认返回当前对象
//return this;
}
fn.num = 20;// 函数上的静态属性
fn.prototype.num = 30;// 原型属性
fn.prototype.method = function(){// 原型方法
console.log(this.num)
}
var prototype = fn.prototype; //将一个对象赋值给变量prototype
var method = prototype.method; //将一个方法赋值给变量method
// 1、new fn()返回对象实例
// 2、依次向上查找 ( 实例 ---> 原型 )
new fn().method();//10
// prototype被返回一个对象,this指向上下文
prototype.method();//30
// method被返回一个函数,指向window
method();//undefined
5、Class类
class Father{
constructor(){
// 使用bind改变eat方法中的this指向
// 始终指向Father中的fruit
this.eat = this.eat.bind( this )
}
get fruit(){
return "apple";
}
eat(){
console.log("I am eating a" + this.fruit);
}
}
class Son{
get fruit(){
return "pear";
}
}
const father = new Father();
const son = new Son();
//1、直接调用 father.eat
//2、内部this指向 father 实例化对象
//3、所以打印:"I am eating aapple"
father.eat();
//1、使用 bind 绑定this到father上
//2、所以打印:"I am eating aapple"
son.eat = father.eat;
son.eat()
class Father {
//1、在 new Father 的时候才会被调用
//2、在子类继承调用 super 的时候也会被调用
constructor() {
this.age = 36;
}
swim() {
console.log("go swinging");
}
}
class Son extends Father {
constructor() {
//1、调用super执行父类中的constructor
//2、this指向 Son 的实例
//3、this可以获取父类上的属性和方法
//4、子类中必须先调用super才能使用this,否则报错
super();
console.log(this);
this.hobby = "traval";
}
study() {
this.swim();
}
}
const son = new Son();
6、事件绑定
; (function (doc) {
var btn = doc.getElementById("btn");
function Plus(a, b) {
this.a = a;
this.b = b;
}
Plus.prototype.init = function () {
this.bindEvent();
}
Plus.prototype.bindEvent = function () {
btn.addEventListener(
"click",
this.handlerBtnClick.bind(this), false
)
}
Plus.prototype.handlerBtnClick = function () {
//事件绑定中的this默认指向,当前元素
//如果使this绑定到Plus的实例上,需手动使用bind绑定
console.log(this.a, this.b)
}
window.Plus = Plus;
})(document)
let plus = new Plus(3, 4)
7、其他情况绑定
- setTimeout & setInterval
- 默认 指向全局对象window
- 箭头函数时,this指向函数定义时作用域
- 通过 bind 改变的this指向( 可以自定义指向对象 )
function Person() {
this.age = 0;
setTimeout(function() {
console.log(this);//window
}, 3000);
}
// 通过bind绑定
function Person() {
this.age = 0;
setTimeout((function() {
console.log(this);//0
}).bind(this), 3000);
}
// 直接使用箭头函数
function Person() {
this.age = 0;
setTimeout(()=> {
console.log(this);//0
}), 3000);
}
var p = new Person();
8、改变this指向
箭头函数中的this
- 箭头函数根本 :没有自己的this和独立作用域
- this 指向 函数定义时所在的作用域
var object = {
name: "object1",
getName: function () {
return () => {
console.info("val", this.name)
}
}
}
object.getName()()
显示绑定( call、apply、bind )
- 底层原理 : 对象执行上下文
- call与apply的区别在于传参的不同
- call和apply返回的是结果,bind返回的是函数( 链式调用多次,只生效一次)
- call、apply、bind都不能改变箭头函数内的this指向
var object = {
name: "object1",
getName: function () {
return function () {
console.log(this.name);
}.bind(this)
}
}
object.getName()()
使用闭包
var object = {
name: "object1",
getName: function () {
let that = this;
return function () {
console.log(that.name);
}
}
}
object.getName()()