1. this的绑定和调用方式以及调用的位置有关系
1.1 常规调用
function Demo() {
console.log(this);
}
Demo() // window(非严格模式)
function bar(){
"use strict";
console.log(this);
}
bar() // undefined(严格模式)
复制代码
函数调用时并未与其他对象进行关联,所以 this 指向全局对象 window(非严)
1.2 通过对象调用函数
function Demo() {
console.log(this);
}
const obj = {
age: 18,
func: Demo
};
obj.func(); // {age: 18, func: ƒ Demo()}
复制代码
通过此方式进行调用,Demo 函数内的 this 会被隐式的绑定到 obj 对象上
1.3 this 丢失
function Demo() {
console.log(this);
}
const obj = {
age: 18,
func: Demo
};
const test = obj.func
test() // window
复制代码
最终调用的位置是 test,而 test 进行调用时没有绑定任何对象,所以默认为 window
1.4 间接函数引用
function Demo() {
console.log(this);
}
const obj = {
age: 18,
func: Demo
};
const obj2 = {
name: "obj2"
};
(obj2.func = obj.func)(); //window
复制代码
(obj2.func = obj.func) 的结果时 Demo 函数,Demo函数被直接调用。
2. call
function.call(thisArg, arg1, arg2, …),改变 this 指向,接收一个参数列表并立即执行。当第一个参数 thisArg 为 null or undefined,则 this 指向 window。(此方法只是临时改变this指向一次。)
- 使用 call 方法调用父构造函数
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
function Toy(name, price) {
Product(name, price);
this.category = 'toy';
}
var cheese = new Food('feta', 5);
var fun = new Toy('robot', 40);
复制代码
// console
=> fun
[object Object] {
category: "toy"
}
=> window.name
"robot"
window.price
=> 40
=> cheese
[object Object] {
category: "food",
name: "feta",
price: 5
}
复制代码
- 使用 call 方法调用函数并且指定上下文的 ‘this’
当调用 greet 方法的时候,该方法的this值会绑定到 obj 对象。
function greet() {
var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
console.log(reply);
}
var obj = {
animal: 'cats', sleepDuration: '12 and 16 hours'
};
greet.call(obj); // cats typically sleep between 12 and 16 hours
复制代码
js.jirengu.com/qamuhuwaxa/…
js.jirengu.com/xivizuzeno/…
3.apply
func.apply(thisArg, argsArray)。argsArray,一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数,改变 this 指向。当第一个参数 thisArg 为 null or undefined,则 this 指向 window。(此方法只是临时改变this指向一次。)
- 使用 apply 将数组添加到另外一个数组中
var arr = [1,2,3,4];
var newArr = [5,6];
arr.push.apply(arr,newArr)
复制代码
// console
=> arr
[1, 2, 3, 4, 5, 6]
复制代码
var arr=[1,10,5,8,3];
console.log(Math.max.apply(null, arr)); //10
复制代码
其中Math.max函数的参数是以参数列表,如:Math.max(1,10,5,8,3)的形式传入的,因此我们没法直接把数组当做参数,但是apply方法可以将数组参数转换成列表参数传入,从而直接求数组的最大值。
function.bind(thisArg[, arg1[, arg2[, …]]])
bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入,call则必须一次性传入所有参数),但是它改变this指向后不会立即执行,而是返回一个永久改变this指向的函数。
this.x = 9; // 在浏览器中,this 指向全局的 "window" 对象
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 81
var retrieveX = module.getX;
retrieveX();
// 返回 9 - 因为函数是在全局作用域中调用的
// 创建一个新函数,把 'this' 绑定到 module 对象
// 新手可能会将全局变量 x 与 module 的属性 x 混淆
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81
var arr=[1,10,5,8,12];
var max=Math.max.bind(null,arr[0],arr[1],arr[2],arr[3])
console.log(max(arr[4])); //12,分两次传参
复制代码
apply,call,bind三者的区别
- 三者都可以改变函数的this对象指向。
- 三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefined或null,则默认指向全局window。
- 三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入。
bind 是返回绑定this之后的函数,便于稍后调用;apply 、call 则是立即执行 。
绑定优先级
- 1.箭头函数
- 2.关键字new调
- 3.显式绑定
- 4.隐式绑定
- 5.默认绑定
箭头函数优先级最高,会无视2-5绑定规则。而默认绑定优先级最低,只有其他绑定都不使用的时候,才会使用默认绑定。
new 操作符调用构造函数,具体做了什么?
- 创建一个新的对象;
- 将构造函数的 this 指向这个新对象;
- 为这个对象添加属性、方法等;
- 最终返回新对象。