zoukankan      html  css  js  c++  java
  • 【《你不知道的JS(上卷②)》】二、this详解

    二、this全面解析:

    ​ 这一章将详细分析this的各种绑定方式。

    一)、调用位置:

    ​ 要理解绑定方式,首先需要理解 调用位置

    (调用位置 o 调用栈(为了到达当前执行位置所调用的所有函数))

    function baz() {
    	// 调用栈: baz
    	// 调用位置: 全局作用域
    	console.log("baz");
    	bar();
    }
    
    function bar() {
    	// 调用栈: baz -> bar
    	// 调用位置: baz函数中
    	console.log("bar");
    	foo();
    }
    
    function foo() {
    	//  调用栈: baz -> bar -> foo
    	// 调用位置: bar函数中
    	console.log("foo");
    }
    
    baz();
    

    二)、绑定规则:

    1、默认绑定:

    ​ 可以看作是当其他绑定规则无法应用时的默认规则:this指向全局作用域(use strict时为undefined)

    2、隐式绑定:

    ​ 应用于调用位置具有上下文对象时。

    function foo() {
    	console.log(this.a);
    }
    
    var obj = {
      a: 2,
      foo: foo
    };
    
    obj.foo(); // 2
    

    尽管在JS中不能说obj对象拥有foo函数。但是在上列中调用位置会使用obj上下文调用函数,在函数调用时可以说obj“拥有”这个函数。

    • 对象属性引用链中只有栈顶会影响调用位置。

    引用丢失:

    var obj = {
      a: 2,
      foo: foo
    };
    
    // bar是一个obj.foo的引用,但实际上是foo的引用,因此此时适用于默认绑定
    var bar = obj.foo;
    
    var a = "oops, global";
    
    bar(); // oops, global
    
    • 引用丢失常发生在回调函数中,如果给回调函数传obj.foo,实际上函数引用的就是foo。

    3、显式绑定:

    call(), apply()方法,将对象绑定到this,接着在调用函数时指定这个this。

    function foo() {
    	console.log(this.a);
    }
    
    var obj = {
    	a:2
    };
    
    foo.call(obj); // 2
    
    • 因为可以直接指定this的绑定对象,因此被称为显式绑定。

    但是显式绑定仍然无法解决 丢失绑定问题。

    1)、硬绑定:

    // ...
    var bar = function() {
    	foo.call(obj);
    }
    
    setTimeout(bar, 100000);
    

    创建一个包裹函数,传入所有的参数并返回接收到的所有值。

    • 由于硬绑定非常常用,因此ES5中内置了bind方法:

      var bar = foo.bind(obj);
      

    2)、API调用的“上下文”:

    ​ 第三方库的许多函数,以及JS语言和宿主环境中许多新的内置函数,都提供了一个可选的参数,通常被称为“上下文”(context),其作用和bind一样,确保你的回调函数使用指定的this。

    function foo(el) {
    	console.log(el, this.id);
    }
    
    var obj = {
    	id: "awesome";
    };
    
    // 调用foo(...)时把this绑定到obj
    [1, 2, 3].forEach(foo, obj);
    // 1 awesome 2 awesome 3 awesome
    

    4、new绑定:

    ​ 在传统的面向对象语言中,new是构造函数的特殊方法。而在JS中,构造函数只是一些使用new操作符时被调用的函数。它们并不会属于某个类,也不会实例化一个类。更不是特殊的函数类型,只是被new操作符调用的普通函数。

    ​ 使用new调用函数时自动执行以下操作:

    1. 创建(构造)一个全新的对象。
    2. 新对象执行[[原型]]连接。
    3. 新对象绑定到函数调用的this。
    4. 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
    function foo(a) {
    	this.a = a;
    }
    
    var bar = new foo(2);
    console.log(bar.a); // 2
    

    三)、优先级:

    (new>显式>隐式>默认)

    四)、绑定例外:

    1、被忽略的this:

    ​ 将null或者undefined作为this的绑定对象传入call、apply或者bind,这些值在调用时会被忽略,实际应用的是默认绑定规则。

    2、间接引用:

    function foo() {
    	console.log(this.a);
    }
    
    var a = 2;
    var o = {a: 3, foo: foo};
    var p = {a: 4};
    o.foo() // 3
    // 赋值表达式的返回值是foo的引用,因此调用位置为foo(),因此应用默认绑定
    (p.foo = o.foo); // 2
    

    3、软绑定:

    五)、this词法:

    箭头函数:

    ​ 箭头函数不适用于this的规则,而是由外层(函数或者全局来决定this)。

    function foo() {
    	return (a) => {
    		console.log(this.a);
    	};
    }
    
    var obj1 = {
    	a: 2
    };
    
    var obj2 = {
    	a: 3
    };
    
    var bar = foo.call(obj1);
    bar.call(obj2); // 2
    

    箭头函数可以像bind(..)一样确保函数的this被绑定到指定对象,此外,它用更常见的词法作用域取代了传统的this机制。

    • this风格与词法作用域不应该混用!
  • 相关阅读:
    maven项目中各文件都没有报错,但是项目名称有红叉
    executeFind()方法和execute()方法区别
    数据库查询
    getHibernateTemplate出现的所有find方法的总结
    HQL和SQL的区别
    Java创建对象的方式
    xml中的<![CDATA[]]>和转义字符
    DWRUtil.addOptions
    dwr
    response.setHeader("Cache-Control","no-cache");的作用
  • 原文地址:https://www.cnblogs.com/enmac/p/13138271.html
Copyright © 2011-2022 走看看