全局上下文
非严格模式和严格模式,this都是指向顶层对象的(window)
函数上下文
普通函数调用
// 非严格模式
var name = 'window';
var doSth = function(){
console.log(this.name);
}
doSth(); // 'window'
// 使用var 全局变量挂在在window上
// 非严格模式
let name2 = 'window2';
let doSth2 = function(){
console.log(this === window);
console.log(this.name2);
}
doSth2() // true, undefined
// let 没有给顶层对象window 添加属性,所以window.name2和window.doSth2 都是undefined
再看看严格模式下
// 严格模式
'use strict'
var name = 'window';
var doSth = function(){
console.log(typeof this === 'undefined');
console.log(this.name);
}
doSth(); // true,// 报错,因为this是undefined
// 默认绑定的原因
doSth.call(undefined);
doSth.apply(undefined);
call,apply作用之一就是用来修改函数中的this指向为第一个参数的。第一个参数是undefined或者null,非严格模式下,只想window,严格模式下,指向第一个参数。
例如回调函数
var name = '若川';
setTimeout(function(){
console.log(this.name);
}, 0);
// 语法
setTimeout(fn | code, 0, arg1, arg2, ...)
// 也可以是一串代码。也可以传递其他函数
// 类比 setTimeout函数内部调用fn或者执行代码`code`。
fn.call(undefined, arg1, arg2, ...);
对象中的函数(方法)调用模式
var name = 'window';
var doSth = function(){
console.log(this.name);
}
var student = {
name: '若川',
doSth: doSth,
other: {
name: 'other',
doSth: doSth,
}
}
student.doSth(); // '若川'
student.other.doSth(); // 'other'
// 用call类比则为:
student.doSth.call(student);
// 用call类比则为:
student.other.doSth.call(student.other);
// 但是又有以下场景
var studentDoSth = student.doSth;
studentDoSth(); // 'window'
// 用call类比则为:
studentDoSth.call(undefined);
call apply bind
fun.call(thisArg, arg1, arg2, ...)
- thisArg
在fun函数运行时指定的this值。注意
this 值不一定是函数真正执行的this 值,如果在非严格模式下,指定undefined 的值会自动指向全局变量
同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象
var doSth = function(name){
console.log(this);
console.log(name);
}
doSth.call(2, '若川'); // Number{2}, '若川'
var doSth2 = function(name){
'use strict';
console.log(this);
console.log(name);
}
doSth2.call(2, '若川'); // 2, '若川'
严格模式下,thisArg是原始值的值类型,也就是原始值。
call 和 apply 基本一致,参数不一致
bind 的返回值时心函数,新函数也能当做构造函数调用(new)
bind()方法创建一个新的函数, 当这个新函数被调用时this键值为其提供的值,其参数列表前几项值为创建时指定的参数序列。
语法: fun.bind(thisArg[, arg1[, arg2[, ...]]])
参数: thisArg 调用绑定函数时作为this参数传递给目标函数的值。 如果使用new运算符构造绑定函数,则忽略该值。 当使用bind在setTimeout中创建一个函数(作为回调提供)时,作为thisArg传递的任何原始值都将转换为object。
如果没有提供绑定的参数,则执行作用域的this被视为新函数的thisArg。 arg1, arg2, ...
当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。
返回值 返回由指定的this值和初始化参数改造的原函数拷贝。
构造函数调用模式
function Student(name){
this.name = name;
console.log(this); // {name: '若川'}
// 相当于返回了
// return this;
}
var result = new Student('若川');
使用new调用函数,会执行一下步骤
- 创建全新对象
- 这个对象执行[[prototype]]链接
- 生成新对象绑定到调用函数的this
- 通过new 创建的每个对象将最终被[[prototype]]链接到这个函数的prototype对象上
- 如果函数没有返回对象类型object,那么new表达式中的函数会自动返回新的对象
由此可见,new操作符调用时。this只想新生成的对象。特别提醒一下,new调用时的返回值,如果没有显式返回对象或者函数,才是返回生成的新对象。
function Student(name){
this.name = name;
// return function f(){};
// return {};
}
var result = new Student('若川');
console.log(result); {name: '若川'}
// 如果返回函数f,则result是函数f,如果是对象{},则result是对象{}
原型链中的调用
function Student(name){
this.name = name;
}
var s1 = new Student('若川');
Student.prototype.doSth = function(){
console.log(this.name);
}
s1.doSth(); // '若川'