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

文章目录

    • 2.1 this
      • this 作为对象的方法
      • this 作为普通函数
      • 构造器调用
      • call 和 apply
    • 2.2 call 和 apply
      • 修正函数中的 this
      • 模拟 bind 函数
      • 借用其他对象的方法

2.1 this

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

this 作为对象的方法

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

var obj = {
	numb: 1,
	getNum: function(){
		alert(this === obj) // -> true
		alert(this.num) // -> 1
	}
}

this 作为普通函数

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

window.name = 'global'
var getName = function() {
	return this.name
}

getName() // 返回 global

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

window.name = 'global'
var obj = {
	name: 'sven',
	getName: function(){
		return this.name;
	}
}

var getNameGlobal = obj.getName 
alert(getNameGlobal()) // 输出 global

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

window.name = 'global'
var obj = {
	name: 'sven',
	that: this,
	getName: function() {
		return that.name;
	}
}

构造器调用

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

var myClass = function(){
	this.name = 'sven'
}

var obj = new myClass();
alert(obj.name) // sven

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

var myClass = function() {
	this.name = 'sven'
	return {
		name: 'anne'
	}
}

var obj = new myClass()
alert(obj.name) // anne

call 和 apply

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

var obj = {
	name: 'sven'
	getName: function(){
		return this.name;
	}
}

var obj2 = { name: 'anne' }

alert(obj1.getName.call(obj2)) // anne

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) // 参数一个一个传入

那么在 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
}

模拟 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

借用其他对象的方法

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

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());

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

(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); // 转换成真的数组

你可能感兴趣的:(设计模式,javascript,设计模式,开发语言)