this指向
默认绑定
独立函数调用就是所谓的默认绑定,独立的函数调用我们可以理解成函数没有被绑定到某个对象上进行调用
<script>
// --------------- 独立的函数调用
function fn() {
console.log(this);
}
function gn() {
console.log(this);
fn() // 独立的函数调用
}
function kn() {
console.log(this);
gn(); // 独立的函数调用
}
kn(); // 独立的函数调用 Windows
</script>
<script>
// --------------- 独立的函数调用
function fn() {
function gn() {
console.log(this);
}
return gn;
}
var kn = fn();
kn(); // 独立的函数调用
</script>
隐式绑定
另外一种比较常见的调用方式是通过某个对象进行调用的,也就是它的调用位置中,是通过某个对象发起的函数调用
<script>
// --------------- 隐式绑定
function fn() {
console.log(this);
}
var obj = {
name: "wc",
fn: fn
}
// fn中的this表示obj
// fn中this是谁,看.前面是谁
obj.fn(); // 隐式绑定 会把obj对象绑定到this上
</script>
<script>
// --------------- 隐式绑定
var obj = {
name: "wc",
fn: function() {
console.log(this);
}
}
var obj2 = {
name: "xq",
gn: obj.fn
}
// fn中this是谁,看.前面是谁
obj2.gn(); // obj2
</script>
显示绑定
<script>
// fn是一个函数
function fn() {
console.log("fn...");
}
// 在JS中一切都是对象,函数也是对象
// 可以给这个对象上添加属性
fn.uname = "wc";
fn.age = 18;
fn.score = 100;
console.log(fn.uname);
console.log(fn.age);
console.log(fn.score);
</script>
call、apply、bind
方法 | 示例 | 是否执行 | 传参 |
---|---|---|---|
call | fn.call(obj,1,2) | fn执行 | 直接传参 |
apply | fn.apply(obj,[1,2]) | fn执行 | 数组内传参 |
bind | fn.bind(obj,1,2) | 返回绑定this后的新函数 | 直接传参 |
<script>
function fn() {
console.log("fn...");
console.log(this);
}
let obj = {
name: "wc"
}
// fn本身也是对象
// call的作用:1)显示绑定this 2)让函数执行
// 通过call可以显示绑定this为obj
fn.call(obj);
</script>
<script>
function fn() {
console.log("fn...");
console.log(this);
}
let obj = {
name: "wc"
}
// apply的作用:1)显示绑定this 2)让函数执行
// 通过call可以显示绑定this为obj
fn.apply(obj);
</script>
<script>
function fn() {
console.log("fn...");
console.log(this);
}
let obj = {
name: "wc"
}
//bind的作用:1)显示绑定this 2)不会让函数执行 3)返回一个绑定this之后新函数
// 通过call可以显示绑定this为obj
let newFn = fn.bind(obj);
newFn();
</script>
Tips:如果call,apply,bind后面跟的是基本数据类型,如下:
<script>
function fn() {
console.log("fn...");
console.log(this);
}
fn.call("hello"); // 会把"hello"包装成一个新的对象
fn.call(undefined); // 参数是und this指定window
fn.call(null); // 参数是null this指定window
</script>
new绑定
** JavaScript中的函数可以当做一个类的构造函数来使用,也就是使用new关键字。使用new关键字来调用函数是,会执行如下的操作:
- 创建一个全新的对象;
- 这个新对象会被执行prototype连接;
- 这个新对象会绑定到函数调用的this上(this的绑定在这个步骤完成);
- 如果函数没有返回其他对象,表达式会返回这个新对象;
<script>
// --------------- new运算符
// 函数的几种角色:
// 1)普通函数
// 2)对象的方法
// 3)普通的对象
// 4)类 new一个类,就得到一个对象
// 如果你要把函数当成一个类,建议把函数名首字母大写
function Fn() {
// new做了什么
// 1)在类中创建一个空的对象
// 2)把这个对象绑定到类中的this上面
// 3)返回这个空对象
this.name = "wc";
this.age = 18;
}
let obj = new Fn(); // new一个类,得到一个对象
console.log(obj); // {name: 'wc', age: 18}
</script>
<script>
// 类 构造器
// JS内置了一些构造器 String Number Boolean
function Person(name, age) {
this.name = name;
this.age = age;
}
let p1 = new Person("wc", 18);
console.log(p1);
let p2 = new Person("xq", 20);
console.log(p2);
</script>
内置函数的绑定
有些时候,我们会调用一些JavaScript的内置函数,或者一些第三方库中的内置函数
- 这些内置函数会要求我们传入另外一个函数;
- 我们自己并不会显示的调用这些函数,而且JavaScript内部或者第三方库内部会帮助我们执行;
- 这些函数中的this又是如何绑定的呢?
定时器中的this表示什么?如下:
<script>
// 一次性定时器
// 3000表示3000ms 3s
// 3s之后,会自动调用里面的函数
// setTimeout(function(){
// console.log("hello 定时器~");
// },3000)
// 循环定时器
// 每隔2s会执行里面的函数
setInterval(function() {
console.log("hello 定时器~");//Windows
}, 2000)
</script>
监听器中的this,表示什么,如下:
<div id="box">click me</div>
<script>
// 得到id为box的元素 dom元素是一个对象
// 对象是引用数据类型
let box = document.getElementById("box");
// box表示事件源 事件发生的场所
// click表示事件类型 JS中有非常多不同类型的事件
// function(){} 表示当点击事件发生了做什么 监听器
box.onclick = function() {
console.log("hello DOM~");
console.log(this); // 监听器中的this表示事件源
//<button></button>这个事件源
}
</script>
规则优先级
- 毫无疑问,默认规则的优先级是最低的,因为存在其他规则时,就会通过其他规则的方式来绑定this
- 显示绑定优先级高于隐式绑定
<script>
function fn() {
console.log(this);
}
let obj = {
name: "wc",
// bind 作用:1)绑定this 2)返回一个绑定this指向后的新函数
fn: fn.bind({
name: "xq"
}) // fn.bind({name:"xq"})是显示绑定
}
obj.fn(); // obj.fn() 隐式绑定
</script>
- new绑定优先级高于隐式绑定
<script>
var obj = {
name: "wc",
fn: function() {
console.log(this);
}
}
// obj.fn(); // 隐式绑定
// 在JS中,只要是函数,都可以new
let res = new obj.fn();
</script>
new绑定优先级高于bind
- new绑定和call、apply是不允许同时使用的,所以不存在谁的优先级更高
- new绑定可以和bind一起使用,new绑定优先级更高
<script>
function fn() {
console.log(this);
}
// bind返回改变this指向后的新函数
var gn = fn.bind({
name: "wc"
});
// gn();
// this 是 {} 说明:new绑定高于显示绑定
var kn = new gn();
</script>
<script>
function fn() {
console.log(this);
}
// new 不能和call和apply一起使用
// call 可以让fn执行 gn不是函数
var gn = fn.call({
name: "wc"
});
console.log(gn);
var kn = new gn();
</script>
忽略显示绑定
我们讲到的规则已经足以应付平时的开发,但是总有一些语法,超出了我们的规则之外。
- 如果在显示绑定中,我们传入一个null或者undefined,那么这个显示绑定会被忽略,使用默认规则
<script>
function fn() {
console.log(this);
}
fn.apply({
name: "wc"
})
// 忽略显示绑定
fn.apply(null) // window
fn.apply(undefined) // window
var gn = fn.bind(null);
gn();
</script>
ES6箭头函数this
为什么在setTimeout的回调函数中可以直接使用this呢?
- 因为箭头函数并不绑定this对象,那么this引用就会从上层作用于中找到对应的this。
记:箭头函数中的this,需要向上找一级。
<script>
console.log(this); // 最外层的this是window
var fn = () => {
// 箭头函数中的this都需要向外找一级
console.log(this);
}
fn(); // window
var obj = {
name: "wc"
}
fn.call(obj); // window
</script>