判断this指向的关键点:
1. 函数调用,this等于window
2. 对象方法调用时,this等于那个对象。
3. 匿名函数的执行环境具有全局性,因此其this对象通常指向window
4. call、apply、bind,new等会改变this指向
5. 多次调用,this指向直接调用方法的对象
例:
哪个对象调用了方法,该方法的this就指向那个对象
多次调用,this指向直接调用方法的对象
var a = 3;
function foo(){
console.log(this.a)
}
var obj = {
a: 2,
foo: foo
};
var obj1 = {
a: 3,
obj2: obj
}
obj.foo(); // 2 ; 对象方法调用:因为是obj调用的foo,所以foo的this指向了obj
obj1.obj2.foo(); // 2 ;对象方法调用:多次调用时,this指向直接调用方法的对象
例:
- 找准关系,理解obj.foo(获取属性值)和obj.foo()(执行对象方法)
var a = "obj";
function foo() {
console.log( this.a )
}
var obj = {
a: 2,
foo: foo
}
var obj2 = obj.foo;
obj2(); // "obj" ; 函数调用:因为obj2引用的是foo函数本身,obj2()是一个函数调用,因此this指向window
// ===========================
var obj = { a: "blue" };
function foo() {
return this.a;
}
obj.foo = foo;
console.log(obj.foo()); // blue; 对象方法调用:obj.foo指向了foo,但是obj.foo()是对象调用了方法
例:
- 找准是函数调用还是方法调用
function foo () {
console.log(this.a)
}
function doFoo (fn) {
fn();
}
var obj = {
a: 2,
foo: foo
}
var a = "obj";
doFoo(obj.foo); // obj ; 函数调用:尽管来回引用多次,但是最后是foo的函数调用
四、闭包
var color = "red";
var obj = {
color: "blue",
sayColor: function () {
// var that = this; 将this保存,传递到匿名内。
console.log(this.color);
return function () {
// return that.color
return this.color;
};
}
}
console.log(obj.sayColor()()); // blue red
// obj.sayColor()对象方法调用:返回了一个匿名函数,后面跟上一个(),进行了函数调用(匿名函数一般指向window)
五、call()与apply()方法作用相同,区别仅仅在于接收参数方式不同
call(this, arg1, arg2) & apply(this,arguments) & apply(this,[arg1,arg2,…argn])
function add(num1, num2) {
return num1 + num2;
}
function callAdd(num1, num2) {
return add.apply(this, arguments);
}
function callAdd1(num1, num2) {
return add.apply(this, [num1, num2]);
}
// function callAdd1(num1, num2) {
// return add.call(this, num1, num2);
// }
console.log(callAdd(10, 10)); // 20
console.log(callAdd1(10, 10)); // 20
类似于:
obj.m = foo; // 将foo存储为obj的临时方法
o.m(); // 调用它,不传入参数
delete o.m; // 将临时方法删除
call()和apply()能扩充函数赖以运行的作用域,使对象不需要与方法有任何耦合关系。传入obj对象后,this指向obj
var obj = { color: "blue" };
function sayColor() {
console.log(this.color);
}
sayColor.call(obj);
apply的巧用:
// 返回数组中最大值。
function getMax2(arr){
return Math.max.apply(null,arr);
}
// 将数组转化为参数
function f(x, y, z) {
// ...
}
var args = [0, 1, 2];
f.apply(null, args);
// 将一个数组添加到另一个数组
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
Array.prototype.push.apply(arr1, arr2)
六、bind() 传入对下obj,this指向obj
var obj = { color: "blue" };
function sayColor() {
console.log(this.color);
}
var objSayColor = sayColor.bind(obj);
objSayColor();//blue
七、new
function A(name){
this.name = name;
this.getName = function(){
console.log(this.name);
}
}
var a = new A('testa');
console.dir(a)
console.dir(A)
__proto__
是原型, prototype是函数默认的一个属性,它指向一个对象,这个对象的constructor属性指向函数本身。
var a = new A(‘testa’)做了什么:
var o = new Object();
o. __proto__ = A.prototype
; function里面的默认的属性prototypeA.call(o) 这里this是指向o,可以把什么this.name/getName绑定到o上.
- 把这个o返回给a; var a = new A()的过程.
如果返回(return)一个原始类型(无return时其实为return原始类型undefined)或返回值是5种基本型(Undefined类型、Null类型、Boolean类型、Number类型、String类型)之一,那么就返回new创建的匿名对象。
function A(name){
this.name = name;
return 3
}
var a = new A('testa');
console.log(a) // A{name: "testa"}
只要new表达式之后的constructor返回(return)一个引用对象(数组,对象,函数等),都将覆盖new创建的匿名对象
function A(name){
this.name = name;
return {
b: 3
}
}
var a = new A('testa');
console.log(a) // Object{b: 3}