this 指向讨论(call,apply,bind)

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 指向这个新对象;
  • 为这个对象添加属性、方法等;
  • 最终返回新对象。
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享