JavaScript 高级
This 指向规则
案例
    function foo() {
        console.log(this)
    }
    // 1 调用方式1
    foo();
    // 2 调用方式2 放入对象中调用
    var obj = {
        name: "why",
        foo: foo
    }
    obj.foo()
    // 调用方式三 通过 call/apply 调用
    foo.call("abc")

指向定义
this 是js 给函数的一个绑定值。
- 函数在调用时 JavaScript会默认给this绑定一个值;
- this的绑定和定义的位置(编写的位置)没有关系;
- this的绑定和调用方式以及调用的位置有关系
- this是在运行时被绑定的
无严格模式下 为 window 如果打开严格模式 则为 udnefined
this 的绑定规则如下:
-  绑定一:默认绑定 PS: 没有绑定到任何对象时 & 函数定义在对象中但是被独立调用 对象也是 window 
-  绑定二:隐式绑定 PS:由JS 绑定到调用对象 指向对象 
-  绑定三:new绑定 - new 执行过程
- 1 创建空对象
- 2 修改this 指向为空对象
- 3 执行函数体代码
- 没有显示返回非空对象时 默认返回这个对象
 
-  绑定四 显示绑定 -  如果我们不希望在 对象内部 包含这个函数的引用,同时又希望在这个对象上进行强制调用 
-  function foo() { console.log(this) } var obj = { name: "why", foo: foo } foo.call(123) console 输出内容 {name: 'why', foo: ƒ}
-  call/apply 可以帮助我们完成这个效果 
 
-  
额外函数补充
Call / Apply 调用方法 两者区别不大 但是又细微差别
apply:
    function foo(name, age, height) {
        console.log("foo 函数this 指向", this);
        console.log("参数:", name, age, height);
    }
 
    // 普通调用  直接入参
    foo("why", 18, 1.22)
    // apply
    // 第一个参数 绑定 this 
    // 第二个参数 传入额外的实参 以数组的形式
    //   foo.apply("apply",["why", 18, 1.22])
    foo.apply("123", ["why", 18, 1.22])
call:
    function foo(name, age, height) {
        console.log("foo 函数this 指向", this);
        console.log("参数:", name, age, height);
    }
    // call
    // 第一个参数 绑定 this
    // 后续参数以 参数列表形式 
    foo.call("call", "远目鸟", 18, 12)
两者 相同处 都是调用方法 第一参数都指向this 唯一区别只在后续传入的参数的形势
- apply 为数组
- call 为列表 以 ,分割
bind :会创建 绑定函数 我们希望调用foo 的时候总是让this 指向 obj
    function foo() {
        console.log("foo 函数this 指向", this);
    }
    var obj = {
        name: "why"
    }
    // 需求 调用foo时 总是绑定 obj 
    var bar = foo.bind(obj)
    bar()
在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。 实际开发中 使用不多 作为参考 了解即可
内置函数
一般 对于浏览器 的内置函数 或者是第三方框架的 this 指向 我们只能用经验去判断 一个一个去源码或者文档查看和并不现实
This 优先级
- 默认绑定 优先级最低
- 显式绑定 高于隐式绑定
- new 高于隐式绑定 PS:new不能和 call/apply 一起使用
- new绑定优先级高于bind
- 同显式 bind 优先级高于 call/apply
拓展: 规则之外
**情况一:**如果在显示绑定中,我们传入一个null或者undefined,那么这个显示绑定会被忽略,使用默认规则:
    function foo() {
        console.log("foo 函数this 指向", this);
    }
    var obj = {
        name: "why"
    }
    foo.call(obj)
    foo.call(null)
    foo.call(undefined)
    var bar = foo.bind(obj)
    bar()
但是打开严格模式 就会可以使用基础属性 直接显示 null 或者 undefined
**情况二:**创建一个函数的 间接引用,这种情况使用默认绑定规则。
- 这种情况 (obj2.foo = obj1.foo) 会使用默认规则 指向 window
    var obj1 = {
        name: "obj1",
        foo: function () {
            console.log("foo 函数this 指向", this);
        }
    }
    var obj2 = {
        name: "obj2"
    };
    obj1.foo();
    (obj2.foo = obj1.foo)();
**情况三:**箭头函数
- 箭头函数不会绑定this、arguments属性
- 箭头函数不能作为构造函数来使用
    // {} 是执行体
    var arrFn = () => { }
    // 指向的是对象 需要加小括号才可以做到
    var arrFn = () => ({ name: "why" })
箭头函数
-  基本写法 -  ():函数的参数 
-  {}:函数的执行体 
-  var foo3 = (name, age) => { console.log("箭头函数的函数体") console.log(name, age) }
 
-  
-  优化写法 -  只有一个参数时, 可以省略() names.forEach(item => { console.log(item) })
-  只有一行代码时, 可以省略{} names.forEach(item => console.log(item))
-  只要一行代码时, 表达式的返回值会作为箭头函数默认返回值, 所以可以省略return var newNums = nums.filter(item => item % 2 === 0) var newNums = nums.filter(item => item % 2 === 0)
-  如果箭头函数默认返回的是对象, 在省略{}的时候, 对象必须使用()包裹 () => ({name: “why”}) var arrFn = () => ["abc", "cba"] var arrFn = () => {} // 注意: 这里是{}执行体 var arrFn = () => ({ name: "why" }) console.log(arrFn())
 
-  
箭头函数不使用this的四种标准规则(也就是不绑定this),而是根据外层作用域来决定this。
我们来看一个模拟网络请求的案例:
- 这里我使用setTimeout来模拟网络请求,请求到数据后如何可以存放到data中呢?
- 我们需要拿到obj对象,设置data;
- 但是直接拿到的this是window,我们需要在外层定义:var _this = this
- _在setTimeout的回调函数中使用_this就代表了obj对象
- 但是如果使用箭头函数根据特性他会向上寻找this 省去了_this = this的操作
    var obj = {
        data: [],
        getData: function () {
            request("/11", (res) => {
                this.data = [].concat(res)
            })
        }
    }
    function request(url, callbackFn) {
        var res = ["abc", "cba", "nba"]
        callbackFn(res)
    }
    obj.getData()
总结
- this的指向问题与优先级 是踏入JS的敲门砖,如果不先系统了解之后使用的时候可能会出现奇怪的错误
- 使用ES6的语法 箭头函数 提前熟悉ES6语法可以提升开发效率



















