记不清这是第多少次在总结这个问题了,前端就是这样,知识点繁星漫天,每颗细细研究都有点意思,不过我最终能记住的也就只有那个勺子而已。有些东西时不时就会忘记需要不断巩固记忆。
关于this的指向问题
总结:JavaScript 函数中的 this 指向并不是在函数定义的时候确定的,而是在调用的时候确定的。换句话说,函数的调用方式决定了 this 指向。
javaScript 中,普通的函数调用方式有三种:直接调用、方法调用和 new 调用。除此之外,还有一些特殊的调用方式,比如通过 bind() 将函数绑定到对象之后再进行调用、通过 call()、apply() 进行调用等。而 es6 引入了箭头函数之后,箭头函数调用时,其 this 指向又有所不同。下面就来分析这些情况下的 this 指向。
- 直接调用函数:this 指向window
function test () {
console.log(this)
}
test()
// 或者
(function(){
test()
})()
- 方法调用:this 指向调用对象。
var obj = {
name: 'zhenganlin',
say: function() {
console.log(this.name)
}
}
obj.say() // 'zhenganlin'
- new 调用:this 指向生成后的实例
function Cat () {
this.name = '大能猫';
this.say = function(){
console.log(this.name)
}
console.log(this)
}
4.bind、call、apply这三个方法都能改变this的指向,将 this 绑定到他们的第一个参数上。
let a = {
name: '小a',
say: function () {
console.log(this.name)
}
}
let b = {name: '甄帅帅'}
a.say.call(b) // 甄帅帅
a.say.apply(b) // 甄帅帅
a.say.bind(b)(); // 甄帅帅
- 箭头函数的方式调用:this等于定义时,函数外面的this。也可以理解成箭头函数中没有this,直接是用的定义时函数外面的this。
const obj = {
test() {
const arrow = () => {
// 这里的 this 是 test() 中的 this,
// 由 test() 的调用方式决定
console.log(this === obj);
};
arrow();
},
getArrow() {
return () => {
// 这里的 this 是 getArrow() 中的 this,
// 由 getArrow() 的调用方式决定
console.log(this === obj);
};
}
};
obj.test(); // true
const arrow = obj.getArrow();
arrow(); // true
call、apply、bind的比较
1、apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
2、apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
3、apply 、 call 、bind 三者都可以利用后续参数传参;
4、bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。
apply、call 的应用。
1、比较大小
var numbers = [5, 458 , 120 , -215 ];
var maxInNumbers = Math.max.apply(Math, numbers), //458
2.验证是否是数组
Object.prototype.toString.call(obj) === '[object Array]' ;
3.类数组变数组
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
4.切换传参的方式
// 普通重写log函数
function log(){
console.log.apply(console, arguments);
};
// 添加打印的前缀
function log(){
var args = Array.prototype.slice.call(arguments);
args.unshift('(app)');
console.log.apply(console, args);
};
bind的用法
bind()的另一个最简单的用法是使一个函数拥有预设的初始参数。只要将这些参数(如果有的话)作为bind()的参数写在this后面。当绑定函数被调用时,这些参数会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们后面。
- bind 用来预设参数
// 只要将这些参数(如果有的话)作为bind()的参数写在this后面。当绑定函数被调用时,这些参数会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们后面。
function list() {
return Array.prototype.slice.call(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
// 预定义参数37
var leadingThirtysevenList = list.bind(undefined, 37);
var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
- 在settimeout中绑定 当前this值
function Bloomer() {
this.petalCount = Math.ceil(Math.random() * 12) + 1;
}
// 1秒后调用declare函数
Bloomer.prototype.bloom = function() {
window.setTimeout(this.declare.bind(this), 100);
};
Bloomer.prototype.declare = function() {
console.log('我有 ' + this.petalCount + ' 朵花瓣!');
};
var bloo = new Bloomer();
bloo.bloom(); //我有 5 朵花瓣!
- bind 简化将类数组结构转化成数组
// 之前的方法
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
// 使用 bind 之后
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);
slice(arguments);
bind 的实现原理(上面的几个小节可以看出bind()有很多的使用场景,但是bind()函数是在 ECMA-262 第五版才被加入;它可能无法在所有浏览器上运行。这就需要我们自己实现bind()函数了)
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
// this instanceof fBound === true时,说明返回的fBound被当做new的构造函数调用
return fToBind.apply(this instanceof fBound
? this
: oThis,
// 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
aArgs.concat(Array.prototype.slice.call(arguments)));
};
// 维护原型关系
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
// 下行的代码使fBound.prototype是fNOP的实例,因此
// 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
fBound.prototype = new fNOP();
return fBound;
};
}
网友评论