1,浏览器和node中全局作用域下的this
2.绑定规则
3.默认绑定
4.隐式绑定
5.apply、bind、call的显式绑定及其对应的特殊绑定
6,new绑定
7.特殊绑定(包括箭头函数、间接函数引用(obj1.foo=obj2.foo)()的绑定、内置函数(setTimeout、foreach、div的点击))
8.绑定优先级
9.面试题
1.浏览器和node中全局作用域下的this
浏览器下的this是window,node环境下的this是{},也就是绑定全局对象,在node中全局对象是global,浏览器下的全局对象是window,最新的es里面推出了globalThis,在浏览器里面globalThis和window相等,在nodeglobalThis等于global
2.绑定规则
绑定规则有四种:默认绑定、隐式绑定、显式绑定、new绑定
3.默认绑定
通过以下三个案例,我们可以得知:1.当函数调用的时候,就会给一个this。2,.this和函数的定义位置无关,而是和调用者有关,当没有调用者的时候,指向全局对象,以下代码在node测试,所以指向global
// 默认绑定 三种常见默认
// 1.直接调用
function foo(){
console.log(this);
}
foo()//global
// 2.函数内间接调用
function foo1(){
console.log(this);
}
function foo2(){
foo1()
}
foo2()//global
// 赋值调用
let obj={
foo:function foo3(){
console.log(this);
}
}
let bar=obj.foo
bar() //global
//案例四 函数调用函数内再调用
function foo11(){
function foo12(){
console.log(this);
}
foo12()
}
foo11()//global
4.隐式绑定
调用后都指向对象
// 隐式绑定
// 两种情况:对象.函数()和对象.对象.函数()
// 1.对象.函数()
let obj={
foo:function foo(){
console.log(this);
}
}
obj.foo()//{ foo: [Function: foo] }
// 2.对象.对象.函数()
let obj1={
obj
}
obj1.obj.foo()//{ foo: [Function: foo] }
5.apply、bind、call的显式绑定及其对应的特殊绑定
三种显式绑定的区别,bind是不调用的,其他两种会调用 apply和call的区别在于传参的区别,一个传数组,具体见下
// 显式调用
function foo(x,y){
console.log(this,x,y);
}
foo.apply({a:1},[1,3])//{ a: 1 } 1 3
foo.call({b:2},2,3)//{ b: 2 } 2 3
// 对于bind的使用 不是foo.bind({c:3})后然后foo()即可 那样指向的是全局对象
let bar=foo.bind({c:3})
bar(4,4)//{ c: 3 } 4 4
foo.apply(null)//global
foo.apply(undefined)//global
foo.call(null)//global
foo.call(undefined)//global
let bar1=foo.bind(null)
bar1(undefined)//global
let bar2=foo.bind(undefined)
bar2(undefined)//global
6.new绑定
// new的绑定
// 当new的时候会执行四件事情
// 1.创建一个新对象
// 2.原型链指向新对象
// 3.this绑定新对象
// 4.返回对象 如果函数没有返回对象 就返回这个函数对象
function foo(){
console.log(this);
return {a:1}
}
let p=new foo() //foo {} 会打印出这个 代表在new的时候 首先会执行一次
console.log(p);//{ a: 1 }如果里面有函数,函数就绑定到p里面
7.特殊绑定(包括箭头函数、间接函数引用(obj1.foo=obj2.foo)()的绑定、内置函数(setTimeout、foreach、div的点击))
// 特殊绑定规则
// 1.箭头函数不绑定this 会取上层的this
// 2.间接函数的绑定
var obj={
foo:function(){
console.log(this);
}
}
var obj1={};//注意这里的;不要漏了 不然会报错
// 相当于obj1.foo=obj.foo 然后obj1.foo()
(obj1.foo=obj.foo)()//global
// 3.setTimeout的this的绑定
setTimeout(function(){//这里需要function 箭头函数是拿上层对象
console.log(this);//node:Timeout{} 浏览器:window
console.log(this===global);//node:false 浏览器:true
})
// 3.对于foreach的this的绑定
let arr=[14]
arr.forEach(function(){
console.log(this);//global
})
arr.forEach(function(){//箭头函数是拿上层对象
console.log(this);//{ a: 0 } this指向的是第二个参数
},{a:0})
8.绑定优先级
1.隐式绑定大于默认绑定
2.显式绑定和new绑定大于隐式绑定
3.new绑定大于bind绑定
function foo() {
console.log(this)
}
var bar = foo.bind("aaa")
var obj = new bar()//foo {}
9.面试题
对于这类题目的分析思路 首先看调用者是谁 然后看是不是箭头函数 如果遇到foo.call(obj) 并且不是箭头函数就相当于obj.foo()
注意对象的{}不算块级作用域
注意apply、call会改变上层作用域
(person.sayName)(); //person 相当于person.sayName()这种调用方式
var name = "window";
var person = {
name: "person",
sayName: function () {
console.log(this.name);
}
};
function sayName() {
var sss = person.sayName;
sss(); //window 前面是赋值没有调用 调用的时候没有调用者 默认绑定
person.sayName(); //person person调用 隐式绑定
(person.sayName)(); //person 相当于person.sayName()这种调用方式
(b = person.sayName)(); //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); // window 箭头函数不绑定this, 上层作用域this是window )
// person1.foo3()(); // window(独立函数调用)
// person1.foo3.call(person2)(); // window(独立函数调用)
// person1.foo3().call(person2); // person2(最终调用返回函数式, 使用的是显示绑定)
// person1.foo4()(); // person1(箭头函数不绑定this, 上层作用域this是person1)
// person1.foo4.call(person2)(); // person2(上层作用域被显示的绑定了一个person2) 相当于person2.foo4()()
// person1.foo4().call(person2); // person1(上层找到person1)
var name = 'window'
function Person (name) {
this.name = name
this.foo1 = function () {
console.log(this.name)
},
this.foo2 = () => console.log(this.name),
this.foo3 = function () {
return function () {
console.log(this.name)
}
},
this.foo4 = function () {
return () => {
console.log(this.name)
}
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.foo1() // person1
person1.foo1.call(person2) // person2(显示高于隐式绑定)
person1.foo2() // person1 (上层作用域中的this是person1)
person1.foo2.call(person2) // person1 (上层作用域中的this是person1)
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
var obj = {
name: "obj",
foo: function() {
}
}
var name = 'window'
function Person (name) {
this.name = name
this.obj = {
name: 'obj',
foo1: function () {
return function () {
console.log(this.name)
}
},
foo2: function () {
return () => {
console.log(this.name)
}
}
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.obj.foo1()() // window
person1.obj.foo1.call(person2)() // window
person1.obj.foo1().call(person2) // person2
person1.obj.foo2()() // obj
person1.obj.foo2.call(person2)() // person2
person1.obj.foo2().call(person2) // obj
//
// 上层作用域的理解
// var obj = {
// name: "obj",
// foo: function() {
// // 上层作用域是全局
// }
// }
// function Student() {
// this.foo = function() {
// }
// }