为什么要用this
function identify() { return this.name } let people={ name:'名字' } identify.call(people)//返回 '名字'
function identify(context) { return context.name } let people={ name:'名字' } identify(people)//返回 '名字'
上面的两段代码执行结果是一样的,但是一个用的this,一个是显式的传入context, 当我们设计API时,或者代码复杂后,显示传入context会让代码混乱起来,
this是什么
this是一个运行时的概念,当一个函数被调用,就会创建一个执行上下文,执行上下文里的 lexical environment:词法环境 里就绑定了this指向(之前的执行上下文博客里也说过),指向什么完全取决于函数在哪里被调用(当前的调用栈)
this绑定规则
- 默认绑定
- 隐式绑定
- 显示绑定
- new绑定
默认绑定
//默认绑定 function foo() { console.log(this.a) } let a=1 foo()//1 //如此foo()直接使用不带修饰的函数引用进行调用的就会进行默认绑定
但是要注意在严格模式下上面的this会指向undefined
隐式绑定
//隐式调用 function foo() { console.log(this.a) } let obj2={ a:1, foo:foo } let obj1={ a:2, obj2:obj2 } obj.obj2.foo()//1 //当函数拥有调用者,this就会被指向调用者这个对象
这里要着重说下调用者 下面代码就不会隐式绑定this,因为没有实际调用者,就会进行默认绑定
function foo() { console.log(this.a) } function active(fn) { //fn其实foo的引用,参数传递其实是隐式赋值 fn(); // 真实调用者,为独立调用 } var a = 20; var obj = { a: 10, getA: foo } active(obj.getA); //
显式绑定 (使用call apply bind 绑定this)
function fn(num1, num2) { console.log(this.a + num1 + num2); } var obj = { a: 20 } fn.call(obj, 100, 10); // 130 fn.apply(obj, [20, 10]); // 50 fn.bind(obj)
call 和apply 都将函数的this指向第一个参数
call和apply实现结果都是一样的,区别在于后面的参数,都是向将要执行的函数传递参数。其中call以一个一个的形式传递,apply以数组的形式传递。这是他们唯一的不同。
我们可以这样使用:
function turnToArray() { var arrArgs = [].slice.call(arguments) // 将参数转换成数组 //arrArgs=Array.from(arguments) console.log(arrArgs) // ['a','b'] } turnToArray('a', 'b')
new绑定
function Person(name, age) { // 这里的this指向了谁? this.name = name; this.age = age; } Person.prototype.getName = function() { // 这里的this又指向了谁? return this.name; } // 上面的2个this,是同一个吗,他们是否指向了原型对象? var p1 = new Person('Nick', 20); p1.getName(); //其实都是指向p1这个实例
通过new操作符调用构造函数,会经历以下4个阶段。
- 创建一个新的对象;
- 将构造函数的this指向这个新对象;
- 指向构造函数的代码,为这个对象添加属性,方法等;
- 返回新对象。
以上绑定方式的优先级 new>显式绑定>隐式绑定>默认绑定
参考 https://yangbo5207.github.io/wutongluo/ji-chu-jin-jie-xi-lie/wu-3001-this.html ;你不知道的js上卷