this

js中的this是一个指针,指向一片作用域,指向哪里,跟编译过程无关,在运行的时候绑定的上下文执行环境

关于构造函数

new 一个实例的过程

  • 创建一个空对象
  • 将基类的原型赋值给实例的原型proto

    1. obj.__proto__ = fn.prototype
    2. Object.setPrototypeOf(obj, fn.prototype)
  • 调用基类的构造函数,this的在执行过程中指向新创建的对象,执行构造函数的代码

    1. fn.apply(obj, args)

    手写全过程

    1. function defineNew(fn, ...args) {
    2. const obj = {}
    3. obj.__proto__ = fn.prototype
    4. fn.apply(obj, args)
    5. return obj
    6. }

    测试

    1. function Person(name,age){
    2. this.name = name;
    3. this.age = age;
    4. this.speak = function(){
    5. console.log('im '+this.name+',im '+this.age+' years old')
    6. }
    7. }
    1. let my = creatObj(Person,'gromy',18)
    2. my.__proto__ == Person.prototype
    3. true

    image.png

    执行上下文

  • 全局执行上下文 这是默认的、最基础的执行上下文。不在任何函数中的代码都位于全局执行上下文中。它做了两件事:1. 创建一个全局对象,在浏览器中这个全局对象就是 window 对象。2. 将 this 指针指向这个全局对象。一个程序中只能存在一个全局执行上下文。

  • 函数执行上下文: 每次调用函数时,都会为该函数创建一个新的执行上下文。每个函数都拥有自己的执行上下文,但是只有在函数被调用的时候才会被创建。一个程序中可以存在任意数量的函数执行上下文。每当一个新的执行上下文被创建,它都会按照特定的顺序执行一系列步骤。

    下文准备

    1. let cat = {
    2. name:'tom',
    3. eat:'fish',
    4. speak:function(speak,like){
    5. console.log('im '+this.name+',im eat '+this.eat);
    6. console.log('im speak '+speak+' ,i like '+like);
    7. }
    8. }
    9. let dog = {
    10. name:'gromit',
    11. eat:'meat'
    12. }

    Call

    使用

    1. cat.speak.call(dog,'wangwang','play ball')

    执行结果

    1. im gromit,im eat meat
    2. im speak wangwang ,i like play ball

    原理

    将this的指向到从调用者 转移到 目标对象上,执行并返回结果

    代码实现

    1. Function.prototype.gromyCall = function(target,...args){
    2. //此时this是调用者,Function
    3. let context = Symbol('this') //避免key冲突
    4. target[context] = this //把调用者的作用域地址送给目标的一个属性
    5. return target[context](...args) //执行并返回
    6. }

    Apply

    使用

    1. cat.speak.call(dog,['wangwang','play ball'])

    原理

    跟call 一样,把调用者的this 地址送给 目标对象的一个属性,区别在参数的形式

    代码实现

    1. Function.prototype.gromyApply = function(target,args){
    2. let context = Symbol('this');
    3. target[context] = this
    4. return target[context](...args)
    5. }

    bind

    使用

    1. cat.speak.bind(dog,'wangwang','play ball')()

    原理

    this的改变和call,apply相同,不同的是bind没有执行过程,返回具有调用函数相同构造器的函数

    代码实现

    1. Function.prototype.gromyBind = function(target,...args){
    2. let context = Symbol('this')
    3. target[context] = this
    4. let result = function(){
    5. return target[context](...args)
    6. }
    7. if(this.prototype){ //保证
    8. result.prototype = this.prototype
    9. }
    10. return result
    11. }