1 链接
个人博客: alex-my.xyz
CSDN: blog.csdn.net/alex_my
2 this
- 对于顶层对象的概念:
- 在浏览器中是window,但是node和Web Worker里面没有window。
- 浏览器和Web Worker中self也指向顶层对象,但node中没有。
- 在node里面,顶层对象是global,但其它环境不支持。
- 在严格模式下,未指定环境对象而调用函数,则 this 值不会转型为 window/global等。 除非明确把函数添加到某个对象或者调用call,apply,bind,否则 this 值将是 undefined。
- 这里使用的是node,支持ES6。运行测试用例
node test.js
。 -
三种调用模式来判断this的值。
// 方法调用
// 当一个函数被保存为对象的一个属性时,成为方法。调用时,this指向这个对象
var handle = {
name: 'Handle Name',
init: function() {
console.log(this.name, this);
}
}
handle.init(); // 输出 Handle Name { name: 'Handle Name', init: [Function: init] }
// 普通函数调用(非ES6的箭头函数)
// 在严格模式下,this为undefined,输出 undefined false
// 在非严格模式下,this指向全局,输出 global, true
var normal = function () {
console.log(this, this === global);
}
normal();
// ES6箭头函数
// this指向调用它的对象
function Timer() {
this.s1 = 0,
this.s2 = 0,
// 箭头函数,this指向调用其的Timer,这里会改变Timer.s1
setInterval(() => {
this.s1++;
console.log('箭头函数: ', this); // this: Timer { s1: 11, s2: 0 }
}, 1000);
// 指向全局,这里并不会改变Timer.s2
setInterval(function () {
this.s2++;
console.log('普通函数', this); // this: global
}, 1000);
}
var timer = new Timer();
setTimeout(() => { console.log('s1: ', timer.s1) }, 3500) // 输出 s1: 3
setTimeout(() => { console.log('s2: ', timer.s2) }, 3500) // 输出 s2: 0
3 call与apply
-
二者作用差不多,会修改函数体内的
this
指向。function log() {
console.log(this === global, this === undefined, this);
}
var foo = {
name: 'Foo'
}
log();
log.call(foo);
log.apply(foo);
// 严格模式下输出
// log(): false true undefined
// log.call(foo): false false { name: 'Foo' }
// log.apply(foo): false false { name: 'Foo' }
// 非严格模式下输出
// log(): true false global
// log.call(foo): false false { name: 'Foo' }
// log.apply(foo): false false { name: 'Foo' }- 以上表明经过call/apply处理后,this均指向了foo。
-
二者传入参数的方式不同
- 第一个参数做为当前对象,也就是this对象。
- 不传或者传null, undefined, 会使得this指向global(非严格模式下)。
- call: 参数要一个一个全部传入,不许使用arguments对象。
- apply: 参数通过组成数组传入,或使用arguments对象。
function log(x, y) {
console.log(this, x, y);
}
var a = function(x, y) {
log.call(a, x, y); // 输出 1 2
log.call(a, arguments); // 输出 { '0': 1, '1': 2 } undefined,不能正确获取参数
log.apply(a, x, y); // 报错,需要组成数组
log.apply(a, arguments); // 输出 1 2
log.apply(a, [x, y]); // 输出 1 2, 通过数组
}
a(1, 2); - 第一个参数做为当前对象,也就是this对象。
4 bind
- 对于给定的函数,会创建一个绑定函数,这个绑定函数的this会指向传入的对象
function log(x, y) {
console.log(this === global, this.name, x, y);
}
var people = {
name: 'People'
}
// 输出 true undefined, log函数在全局上下文中调用, this指向global
log(1, 2);
// 输出 false 'People'
// log中的this被绑定为people
var foo = log.bind(people);
foo(1, 2);
// 也可以这样
var foo2 = log.bind(people, 1, 2);
foo2();
5 一个有意思的示例
- 来源: Alex MacCaw 如何面试前端工程师:GitHub 很重要
-
关于apply
function log() {
var args = Array.prototype.slice.call(arguments);
args.unshift(new Date().toLocaleString());
console.log.apply(console, args);
}
log('hello', 'world'); // 输出 2017-8-12 18:11:26 hello world
log('hello'); // 输出 2017-8-12 18:11:26 hello -
关于bind
var User = {
count: 1,
getCount: function () {
return this.count;
}
};
// 函数在User的上下文中执行,this指向User
console.log(User.getCount()); // 输出 1
// func在全局上下文中执行,this指向global(非严格模式下)
var func = User.getCount;
console.log(func()); // 输出 undefined
// 绑定了User,this指向User
var func2 = User.getCount.bind(User);
console.log(func2()); // 输出 1