学习笔记(二) js中的this指向问题总结

1.普通函数中 this指向window
function fn() { console.log('普通函数的this' + this); } window.fn();
2.构造函数中 this指向实例对象
function Star(name) {
this.name
}; Star.prototype.sing = function() { } var ldh = new Star();
在构造函数中,我们new一个实例的时候,为这个函数开辟了一块内存空间,构造函数中的this也指向了那块新开辟的内存空间,然后new Star中存的是对应的内存地址,将这个内存地址赋值了ldh所以这this指向的了ldh这个实例的对象,原型对象的this也是指向了ldh这个实例对象,总结,不管是构造函数上的this还是原型对象上的this都指向了我们的实例对象ldh
关于构造函数的扩展:
es6之前通过构造函数+原型实现面向对象的编程
1.构造函数有原型对象prototype
2.构造函数原型对象prototype里面有constructor指向构造函数本身
3.构造函数可以通过原型对象添加扩张
4.构造函数创建的实例对象有__proto__属性指向构造函数的原型对象
注:构造函数与类并没有本质上的区别,使用的类的语法可以让代码更具有可读性
类的使用方法:
// 1. 类的继承 // class Father { // constructor() { // } // money() { // console.log(100); // } // } // class Son extends Father { // } // var son = new Son(); // son.money(); class Father { constructor(x, y) { this.x = x; this.y = y; } sum() { console.log(this.x + this.y); } } class Son extends Father { constructor(x, y) { super(x, y); //调用了父类中的构造函数 } } var son = new Son(1, 2); var son1 = new Son(11, 22); son.sum(); son1.sum();
// super 关键字调用父类普通函数 class Father { say() { return '我是爸爸'; } } class Son extends Father { say() { // console.log('我是儿子'); console.log(super.say() + '的儿子'); // super.say() 就是调用父类中的普通函数 say() } } var son = new Son(); son.say(); // 继承中的属性或者方法查找原则: 就近原则 // 1. 继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的 // 2. 继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近原则)
但是在es6之前,我们需要使用下面的写法
要去改变子类当中的this的指向,使他指向父类构造函数的this
// 借用父构造函数继承属性 // 1. 父构造函数 function Father(uname, age) { // this 指向父构造函数的对象实例 this.uname = uname; this.age = age; } Father.prototype.money = function() { console.log(100000); }; // 2 .子构造函数 function Son(uname, age, score) { // this 指向子构造函数的对象实例 Father.call(this, uname, age); this.score = score; } // Son.prototype = Father.prototype; 这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化 Son.prototype = new Father(); // 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数 Son.prototype.constructor = Son; // 这个是子构造函数专门的方法 Son.prototype.exam = function() { console.log('孩子要考试'); } var son = new Son('刘德华', 18, 100); console.log(son); console.log(Father.prototype); console.log(Son.prototype.constructor);
3.对象方法中 this指向该方法所属的对象
var o = { sayHi: function() { console.log('对象方法的this:' + this); } }
4.事件绑定方法中 this指向绑定事件对象
// 4. 绑定事件函数 this 指向的是函数的调用者 btn这个按钮对象 var btn = document.querySelector('button'); btn.onclick = function() { console.log('绑定时间函数的this:' + this); };
5.定时器函数和立即执行函数 this指向的是window对象
// 5. 定时器函数 this 指向的也是window window.setTimeout(function() { console.log('定时器的this:' + this); }, 1000); // 6. 立即执行函数 this还是指向window (function() { console.log('立即执行函数的this' + this); })();
this的指向可以被改变:
二. 关于call apply bind的使用总结
call方法:
1.call方法会调用函数
2.call方法会改变this的指向
// call 方法 function fn(x, y) { console.log('我想喝手磨咖啡'); console.log(this); console.log(x + y); } var o = { name: 'andy' }; // fn();指向的是window对象 // 1. call() 可以调用函数 // fn.call(); // 2. call() 可以改变这个函数的this指向 此时这个函数的this 就指向了o这个对象 fn.call(o, 1, 2);
apply方法:
1.apply方法会调用函数
2.apply方法也会改变内部的this指向,但是他的参数的必须是数组
3.apply主要应用 例:可以利用数学内置对象求最值
var arr=[1,22,3,55,4,66]; Math.max.apply(Math,arr)
# 应用于平铺数组参数
var a = [1,2,3],
b = [4,5];
Array.prototype.push.apply(a, b); #=> a = [1, 2, 3, 4, 5]
a.push(b); #=> a = [1, 2, 3, [4,5]]
Math.math(null, [1,2,3,4,5]) #=> 5
这代码的意思是首先apply函数先调用一下Math.max的方法,让第一个形参中的this指向max这个方法的调用者Math
bind方法:
1.bind不会调用原来的函数,但是会改变原来函数内部的this指向
2.返回的是原函数改变this只会产生的新函数
3.如果有的函数不需要立即调用 但是又想改变内部的this指向
//bind方法 var btn = document.querySelector('button'); btn.onclick = function(){ this.disabled = true; //这个this指向的是btn这个绑定的按钮 setTimeout(()=>{ this.disabled = false;//这个this指向的是window对象 }.bind(this),3000)//这个this指向的是btn对象 }
在箭头函数中,this指向的是其声明时所在的作用域 的this
总结:
相同的:都可以改变this的指向
不同点:1.call和apply会立即调用函数,并且改变this的指向
2.call和apply传递的参数不一样,call传递的是num1,num2,num3.... apply传递的必须是一个数组
3.bind不会立即调用函数,改变内部this的指向
应用场景:call多用来对父类的继承
apply经常和数组有关系,可以对数组使用扩展的方法,例如借助数学方法对数组进行求最值
bind不调用函数,但改变内部this的指向,比如改变定时器内部的this指向
浙公网安备 33010602011771号