• 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
  • 相关阅读:
    spring5.3 十一:spring启动过程源码分析
    #循循渐进学51单片机#函数进阶与按键#not.7
    mysql中动态行转列
    MKD调试下载的时候提示:Contents mismatch at: xxxxxxxxH (Flash=xxH Required=xxH)
    Ansys Zemax | 如何建立LCD背光源模型
    为什么我认识的机械工程师都抱怨工资低?
    软件加密系统Themida应用程序保护指南(九):通过命令行进行保护
    广州蓝景分享—14个非常实用的CSS属性技巧
    Java基于API接口爬取淘宝商品数据
    Pulsar-Pulsar 之 Functions
  • 原文地址:https://blog.csdn.net/Littlelumos/article/details/132882513