• JavaScript 设计模式中的 this、call 和 apply(设计模式与开发实践 P3)


    2.1 this

    javascript 的 this 总是指向一个对象,且指向的对象 基于函数的执行环境 动态绑定,而不是函数声明时的环境

    this 作为对象的方法

    函数 getNum 作为对象 obj 的方法被调用,this 指向对象 obj

    var obj = {
    	numb: 1,
    	getNum: function(){
    		alert(this === obj) // -> true
    		alert(this.num) // -> 1
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    this 作为普通函数

    此时 this 总是指向全局对象,在浏览器中,这个全局对象就是 window

    window.name = 'global'
    var getName = function() {
    	return this.name
    }
    
    getName() // 返回 global
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这时就会遇到一个我们不想要的情况:

    window.name = 'global'
    var obj = {
    	name: 'sven',
    	getName: function(){
    		return this.name;
    	}
    }
    
    var getNameGlobal = obj.getName 
    alert(getNameGlobal()) // 输出 global
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    我们可以通过设置一个变量来解决 (这部分内容存疑,但在代码行中是可实现的):

    window.name = 'global'
    var obj = {
    	name: 'sven',
    	that: this,
    	getName: function() {
    		return that.name;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    构造器调用

    javascript 中没有类,但可以通过 new 运算符来从函数中构造对象:

    var myClass = function(){
    	this.name = 'sven'
    }
    
    var obj = new myClass();
    alert(obj.name) // sven
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    不过需要注意的是,如果 function 显式返回一个对象,运算结果还是那个返回值

    var myClass = function() {
    	this.name = 'sven'
    	return {
    		name: 'anne'
    	}
    }
    
    var obj = new myClass()
    alert(obj.name) // anne
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    call 和 apply

    用 call 和 apply 可以动态地改变传入函数的 this:

    var obj = {
    	name: 'sven'
    	getName: function(){
    		return this.name;
    	}
    }
    
    var obj2 = { name: 'anne' }
    
    alert(obj1.getName.call(obj2)) // anne
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.2 call 和 apply

    call 和 apply 作用一模一样,只是传入参数的形式不同

    var func = function(a, b, c){
    	alert([a, b, c])
    }
     
    func.apply(null, [1, 2, 3]) // 参数以数组的形式发送,用的更多~
    func.call(null, 1, 2, 3) // 参数一个一个传入
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    那么在 javascript 中 call 和 apply 有什么实际用途?

    修正函数中的 this

    document.getElementById('div1').onclick = function(){
    	alert(this.id)
    	var func = function(){
    		alert(this.id)
    	}
    	func() // window.id => undefined
    	func.call(this) // div1
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    模拟 bind 函数

    Function.prototype.bind = function(ctx) {
    	var self = this;
    	return function(){
    		return self.apply(ctx, arguments);
    	}
    }
    
    var obj = { name: 'sven' }
    
    var func = function(){
    	alert(this.name)
    }.bind(obj)
    
    func(); // 输出 sven
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    借用其他对象的方法

    如下这样,就可以通过借用其他构造函数来实现类似继承的效果了:

    var A = function (name) {
      this.name = name;
    };
    
    var B = function () {
      A.apply(this, arguments);
    };
    
    B.prototype.getName = function () {
      return this.name;
    };
    
    var b = new B("sven");
    console.log(b.getName());
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    另一个例子是借用一些实用类,这就使得一些本来不是数组的东西也可以使用数组的方法了:

    (function () {
      var x = Array.prototype.push.apply(arguments, [4, 5, 6]);
      console.log(arguments);
    })(1, 2, 3); // 添加新元素
    
    (function () {
      var x = Array.prototype.slice.apply(arguments, [0, 1]);
      console.log(x);
    })(1, 2, 3, 4, 5); // 转换成真的数组
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    ESP8266--Arduino开发(环境搭建)
    Amlogic T972 AOSP 编译服务器搭建
    堪称全网最详细的Java八股面试文,面试必备(附答案)
    企业发展必不可缺——BPM系统
    西山科技将于12月6日上会:年收入2亿元,耗材收入成为新增长点
    python永久配置pip下载镜像源方法(window版本)
    postgres数据库报错无法写入文件 “base/pgsql_tmp/pgsql_tmp215574.97“: 设备上没有空间
    黑马JVM总结(十二)
    html visibilitychange 事件
    NCCoE发布“向后量子密码学迁移”项目进展情况说明书
  • 原文地址:https://blog.csdn.net/Littlelumos/article/details/132882513