文章作为学习笔记方便以后复习。小伙伴们查看,可以复制下demo 看下结果 更加便于理解、
1.this
this是我们前端日常编码中最熟悉的关键字,JavaScript 的 this 总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的。
this的指向大致可以分为以下4种:
1.作为对象的方法调用
2.作为普通函数调用
3.构造器调用
4.Function.prototype.call 或 Function.prototype.apply 调用
1.1 作为对象的方法调用
当函数作为对象的方法被调用时,this 指向该对象:
var obj = {
a:1,
getA:function(){
alert(this.a)
}
}
obj.getA()
1.2 作为普通函数调用
当函数不作为对象的属性被调用时,也就是我们常说的普通函数方式,此时的 this 总是指向全局对象。在浏览器的 JavaScript 里,这个全局对象是 window 对象。
window.name = '小人头';
var getName = function(){
return this.name;
};
getName() //小人头
1.3 构造器调用
javaScript中没有类,可以通过构造器创建对象。就是我们通常的new 运算符。 当使用new运算符会返回一个对象。此时构造器内的this 就指向创建出来的对象;
function Book(){
this.name ="小人头";
}
var book = new Book();
book.name // 小人头
book.constructor == Book
//回忆一下。这里的Book 就属于构造器。 而boos 算是实例,构造器内的this 就指向了book
下面在补充一点,就是当构造器内返回一个object类型的对象。这次运算就返回这个对象。而不是之前的this(相信大家都知道)
function Book(){
this.name ="小人头";
return {name:"哈哈哈"}
}
var book = new Book();
book.name // 哈哈哈
如果构造器内返回的是一个对非对象类型的数据。则不会出现上述问题。new后的构造器内this指向实例
function Book(){
this.name ="小人头";
return "123123"
}
var book = new Book();
Book() //12123
book.name // 小人头
1.4 Function.prototype.call 或 Function.prototype.apply调用
函数中有2个方法 call 和apply ,这2个方法可以动态的改变传入函数内的this指向
var obj1 = {
name: '小人头',
getName: function(){
return this.name;
}
};
var obj2 ={
name:"哈哈哈"
}
obj.getName() //小人头
obj.getName.call(obj2) //哈哈哈
obj.getName.apply(obj2)//哈哈哈
2.call 和apply
ECMAScript 规范给所有函数都定义了 call 与 apply 两个方法,它们的应用非常广泛,它们的作用也是一模一样,只是传参的形式有区别而已。
apply( )
apply 方法传入两个参数:一个是作为函数上下文的对象,另外一个是作为函数参数所组成的数组。
var obj = {
name : '小人头'
}
function func(firstName, lastName){
console.log(firstName + ' ' + this.name + ' ' + lastName);
}
func.apply(obj, ['A', 'B']); // A 小人头 B
call( )
call 方法第一个参数也是作为函数上下文的对象,但是后面传入的是一个参数列表,而不是单个数组。
var obj = {
name: '小人头'
}
function func(firstName, lastName) {
console.log(firstName + ' ' + this.name + ' ' + lastName);
}
func.call(obj, 'C', 'D'); // C小人头 D
对比 apply 我们可以看到区别,C 和 D 是作为单独的参数传给 func 函数,而不是放到数组中。
对于什么时候该用什么方法,其实不用纠结。如果你的参数本来就存在一个数组中,那自然就用 apply,如果参数比较散乱相互之间没什么关联,就用 call。
2.1 改变this指向
var obj = {
name: '小人头'
}
function func() {
console.log(this.name);
}
func.call(obj); //小人头
我们知道,call 方法的第一个参数是作为函数上下文的对象,这里把 obj 作为参数传给了 func,此时函数里的 this 便指向了 obj 对象。此处 func 函数里其实相当于:
function func() {
console.log(obj.name);
}
2.2 借用别的对象的方法(继承)
先看栗子:
var Person1 = function () {
this.name = '小人头';
}
var Person2 = function () {
this.getname = function () {
console.log(this.name);
}
Person1.call(this);
}
var person = new Person2();
person.getname();//小人头
从上面我们看到,Person2 实例化出来的对象 person 通过 getname 方法拿到了 Person1 中的 name。因为在 Person2 中,Person1.call(this) 的作用就是使用 Person1 对象代替 this 对象,那么 Person2 就有了 Person1 中的所有属性和方法了,相当于 Person2 继承了 Person1 的属性和方法。
2.3 调用函数
apply、call 方法都会使函数立即执行,因此它们也可以用来调用函数。
function func() {
console.log('小人头');
}
func.call(); //小人头
3.bind 和call/apply的区别
在 EcmaScript5 中扩展了叫 bind 的方法,在低版本的 IE 中不兼容。它和 call 很相似,接受的参数有两部分,第一个参数是是作为函数上下文的对象,第二部分参数是个列表,可以接受多个参数。它们之间的区别有以下两点:
1.bind方法返回值是函数
var obj = {
name: '小人头'
}
function func() {
console.log(this.name);
}
var func1 = func.bind(obj);
func1();//小人头
2.参数的使用
function func(a, b, c) {
console.log(a, b, c);
}
var func1 = func.bind(null,'小人头');
func('A', 'B', 'C'); // A B C
func1('A', 'B', 'C'); // 小人头 A B
func1('B', 'C'); // 小人头 B C
func.call(null, 'linxin'); // 小人头 undefined undefined
由于低版本的不兼容bind的方法 我们可以实现一个简易版bind:
Function.prototype.bind = function(context){
var self = this;
return function(){
return self.apply(context,arguments);
}
}
var obj = {
name:"小人头"
}
var func = function(){
alert(this.name) //小人头
}.bind(obj)
func();
bind书中有个复杂的例子。我还没完全弄懂。后面再加。溜了溜了~
网友评论