this的绑定规则
函数中的this指向
<script>
//定义一个函数
function foo() {
consolo.log(this);
}
//调用方式一:直接调用
foo(); //此时this指向window
//调用方式二:将foo放到一个对象中再调用
var obj = {
name:"why",
foo:foo
}
obj.foo() // 此时this指向的是obj对象
- 函数在调用时,JavaScript会默认给this绑定一个值;
- this的绑定和定义的位置(编写的位置)没有关系
- this的绑定和调用方式以及调用的位置有关系;
- this在运行的时被绑定
this的绑定规则
默认绑定
独立函数调用:没有绑定在任何对象上
//1、普通的函数被独立调用
function foo() {
consolo.log(this);
}
//调用方式一:直接调用
foo(); //此时this指向window
//2、函数定义在对象中,但是独立调用
var obj = {
name:'why',
bar:function(){
console.log('bar:',this)
}
}
var baz = obj.bar
baz() //此时this依旧指向window
//3、严格模式下,独立调用的函数中的this指向的是undefined
// 'use strict'
隐式绑定
function foo() {
console.log("foo函数:", this)
}
var obj = {
bar:foo
}
obj.bar()
new绑定
/* new的执行过程
1、创建新的空对象;
2、将this指向这个空对象;
3、执行函数体中的代码;*/
function foo() {
console.log("foo函数:", this)
}
new foo()
显示绑定
var obj = {
name:"why"
}
function foo() {
console.log("foo函数:",this)
}
// 执行函数,并且强制this就是obj对象
foo.call()
apply/call/bind
function foo(name, age, height) {
console.log("foo函数:",this)
}
//apply
//第一个参数:绑定this
//第二个参数:传入额外的实参,以数组的形式
func.apply(thisArg,[argsArray])
foo.apply('apply',['catherine',20,1.66])
//call
//第一个参数:绑定this
//参数列表:后续的参数以多参数的形式传递,会作为实参
function.call(thisArg,arg1,arg2,...)
foo.call('call','james',25,2.05)
//bind
//
function foo(name, age, height) {
console.log("foo函数:",this)
}
var obj = {name:"Jack"}
//1.bind函数的基本使用
var bar = foo.bind(obj)
内置函数的调用绑定
内置函数(第三方库):无法明确知道,根据经验
//1、定时器
setTimeout(function() {
console.log('定时器函数:',this)
},1000)
//2、按钮的点击监听
var btn = document.querySelector('button')
btn.onclick = function() {
console.log("btn的点击:",this)
}
btn.addEventListener("click",function(){
console.log("btn的点击:",this)
})
this绑定的优先级
1、默认规则的优先级最低
2、显示绑定的优先级高于隐式绑定
3、new不可以和apply/call一起使用,new绑定也高于隐式函数
4、new绑定的优先级高于bind
5、bind的优先级高于apply/call
function foo() {
console.log("foo函数:",this)
}
var obj = {foo:foo}
obj.foo.apply("123")//此时this指向"123",apply为显示绑定优先级更高
this绑定之外的情况
1、显示绑定中,我们传入一个null/undefined,那么显示绑定会被忽略,执行默认绑定
function foo() {
console.log("foo:",this)
}
foo.apply('abc')
foo.apply(null) //this指向Windows,严格模式下指向null
foo.apply(undefined)//this指向Windows,严格模式下指向undefined
箭头函数(es6)
1、箭头函数不能绑定this、arguments;
2、箭头函数不能作为构造函数来使用(不能和new一起使用)
// Function expression
const calcAge2 = function (birthYear) {
return 2037 - birthYear;
}
// Arrow function
//没有参数
const foo = () => {}
// 只有一个参数
const calcAge3 = birthYear => 2037 - birthYear;
//use
const age3 = calcAge3(1996);
// 函数中超过一个表达式时:
const yearUntilRetirement = birthYear => {
const age = 2037 - birthYear;
const retirement = 65 - age;
return retirement
}
// 函数中有两个参数时:
const yearUntilRetirement = (birthYear,firstName) => {
const age = 2037 - birthYear;
const retirement = 65 - age;
return '${firstName} retires in '${retirement}' years.'
}
//如果箭头函数默认返回值是一个对象,那么这个对象必须加()
var arrFn = () => ({name:"TOM"})
//箭头函数实现nums的所有偶数平方的和
var nums = [20,30,11,15,111]
var result = nums.filter(item => item % 2 === 0)
.map(item => item * item)
.reduce((prevValue,item) => prevValue + item)
箭头函数中的this使用
- 箭头函数中的 this 是在箭头函数定义时就决定的,而且不可修改(call, apply, bind)
- 默认指向定义它时,所处上下文的对象的this指向。即ES6箭头函数里this的指向就是上下文里对象this指向,偶尔没有上下文对象,this就指向window
面试题练习
var name = "window";
var person = {
name: "person",
sayName: function () {
console.log(this.name);
}
};
function sayName() {
var sss = person.sayName;
sss();// 独立函数调用,使用默认绑定,指定window -> window
person.sayName(); // 隐式绑定,this指向person对象 -> person
(person.sayName)(); // 与上一行完全一样:隐式绑定,this指向person对象 -> person
(b = person.sayName)(); // 间接函数引用,this指向window
}
sayName();
var name = "window"
var person1 = {
name: "person1",
foo1: function () {
console.log(this.name)
},
foo2: () => console.log(this.name),
foo3: function(){
return function() {
console.log(this.name)
}
},
foo4: function () {
return () => {
console.log(this.name)
}
}
}
var person2 = {name : 'person2')
person1.foo1(); //隐式绑定:person1
person1.foo1.call(person2);//person2
person1.foo2(); // 箭头函数去上层作用域找,window
person1.foo2.call(person2); // call无法绑定箭头函数,还是去上层作用域找,window
person1.foo3()(); // 默认绑定:window
person1.foo3.call(person2)(); //默认绑定 :window
person1.foo3().call(person2); // 显示绑定:person2
person1.foo4()(); // person1
person1.foo4.call(person2)(); // person2
person1.foo4().call(person2); // person1