加载中

js语言this指向

指向特性

// 输出 window
console.log(this)

// 输出 window
function fun() {
    console.log(this)
}
fun()    // <=> [this.]fun()

// 输出 window
function fun() {
    function fun() {
        console.log(this)
    }
    fun()
}
fun()    // <=> [this.]fun()

// 输出 obj
let obj = {
    fun: function() {
        console.log(this);
    }
}
obj.fun()

以上证明this指向它的执行对象

绑定类型

指定了绑定对象称为显式绑定,没有指定称为隐式绑定,除此还有绑定丢失

var obj = {
    fun: function() {
        console.log(this)
    }
}
let fun = obj.fun    // fun 作为实参赋值,执行对象将成为其绑定对象
fun()    // 输出 window
let obj = {
    fun: function() {
        console.log(this)
    }
}
function run(fun) {
    fun()
}
run(obj.fun)    // 输出 window

切换绑定

绑定函数有:call, apply, bind

// 绑定示例
function Person() {
    console.log(this.name)
}
let student = {
    name: "zhangSan"
}
Person.call(student)
// 3个绑定函数区别
let person = {
    name: "zhangSan",
    say: function(age, phone) {
        console.log(this.name)
        console.log(age)
        console.log(phone)
    }
}
let person2 = {
    name: "liSi"
}
person.say.call(person2, "age", "phone")
person.say.apply(person2, ["age", "phone"])    // 参数以数组传递
person.say.bind(person2, "age", "phone")    // 得到一个函数而非直接执行

构造函数指向

// 构造函数中的this指向新建对象
function person(name, age) {
    this.name = name
    this.age = age
}

let person1 = new person("zhangSan", 20)

call 的实现

先用最基础的代码解释原理

// 测试用
let person = {
    name: 'zhangSan'
}
let obj = {
    name: 'kiSi',
    fun: function() {
        console.log(this.name)
    }
}

// 添加 call2 原型
Function.prototype.call2 = function(context) {
    context.p = this
    /**
     * 此 this 指向 obj.fun,即调用者
     * 修改后为
     * context: { name: 'zhangSan', p: function(){ /*...*/ } }
     */

    context.p()
    // 此时调用p, p中的this指向context本身
}
obj.fun.call2(person)

原理如上,懂了原理再完善一下代码:

  1. 如果 context.p 原本就存在,call2 会干扰原对象,此时可用 Symbol 创建唯一 Key
  2. 要能传参数
  3. 健壮性保证,对 context 进行预处理
Function.prototype.call2 = function(context, ...args) {
    if(context === null || context === undefined) {
        context = window 
    }else {
        context = Object(context) // 值为原始值(数字, 字符串, 布尔值)的 this 会指向该原始值的实例对象
    }

    const p = Symbol('随便写')
    context[p] = this
    let result = context[p](...args)
    delete context[p]   // 从对象中删除临时函数
    return result
}
obj.fun.call2(person, 18, "nv")

手写call原文参考:https://www.cnblogs.com/web-chuan/p/11592261.html
如有侵权,立即删除

posted @ 2020-10-23 18:55  jialeYang  阅读(44)  评论(0编辑  收藏  举报