this的作用
在面向对象编程中,this(或类似的关键字如self)用于引用当前对象实例。JavaScript虽然支持面向对象编程,但它的this机制更加灵活
var obj = {
name: "sun",
eating: function () {
console.log(obj.name, "正在吃东西");
},
running: function () {
console.log(obj.name, "正在吃跑步");
},
studying: function () {
console.log(obj.name, "正在吃学习");
},
};
obj.eating();
obj.running();
obj.studying();假如说这里的obj对象名如果改成obj1,那么该对象里面的方法中的obj都需要改成,obj1,如果用this,就可以避免这一个繁杂的操作。 没有this也有解决方案,有this在编写代码时更方面。
this的指向
this在浏览器全局作用域下指向window,在node中执行一个空对象{},因为node在执行代码时会将js打包成一个模块进行加载、编译,放到一个函数中,再执行这个函数的call({})方法。 通常情况下都是出现在函数中。
function foo() {
console.log(this);
}
// 调用方式一
foo(); //window
// 调用方式二
var obj = {
foo: foo,
};
obj.foo(); //obj对象
// 调用方式三
foo.call("abc"); //String{"abc"}对象上述案例中函数的调用方式不同产生了三种不同的打印结果,可见函数在调用时,JavaScript会默认给this绑定一个值,this的绑定和定义的位置没有关系跟this的绑定和调用方式以及调用的位置有关。this是在运行时被绑定的。
this的绑定规则
默认绑定:独立函数调用,可以理解成有没有被绑定到某个对象上进行调用
function foo() {
console.log(this);
}
foo();//windowvar obj = {
foo: function () {
console.log(this);
},
};
var bar = obj.foo;
bar(); //windowfunction foo(func) {
func();
}
var obj = {
bar: function () {
console.log(this);
},
};
foo(obj.bar); //window隐式绑定:通过某个对象发起的调用,在调用的对象内部会有一个对函数的引用(比如一个属性)
var obj = {
eating: function () {
console.log(this);
},
};
obj.eating();//obj显示绑定:在隐式绑定时,必须在调用函数的对象中有一个对函数的引用,比如一个属性,就是这个属性将函数的this绑定到该对象上。如果不希望有这个引用,又想对函数有一个引用,那么可以通过call、apply和bind方法。因为这些方法显示地指定了this地指向,所以被称为显示绑定。
function foo(num1, num2) {
console.log(num1 + num2, this);
}
var obj = {};
foo.call(window, 1, 2); //3 Window
foo.call(obj, 1, 2); //3 {}
foo.call(123, 1, 2); //3 Number {123}
foo.apply(obj, [1, 2]); //3 {}
var obj1 = foo.bind(obj, 1, 2);
obj1();//3 {}// 实现一下call:用来将函数绑定到传入得对象上;
Function.prototype.sjcall = function (thisArg, ...args) {
// 1,首先得执行该方法
var fn = this;
// 2,获取传入得对象,将函数绑定到该对象:即使用该对象隐式调用方法
var obj = thisArg ? Object(thisArg) : window;
obj.fn = fn;
// 3,如果有参数
var result = obj.fn(args);
// 4,删去fn属性
delete obj.fn;
// 5,返回res
return result;
};new绑定:JavaScript中的函数可以当做一个类的构造函数来使用,也就是使用new关键字。 使用new关键字来调用函数是,会执行如下的操作:
1.创建一个全新的对象;
2.这个新对象会被执行prototype连接;
3.这个新对象会绑定到函数调用的this上(this的绑定在这个步骤完成);
4.如果函数没有返回其他对象,表达式会返回这个新对象;
function Person(name) {
console.log(this); // Person {}
this.name = name;
}
var p = new Person("sun");
console.log(p); // Person {name: "sun"}优先级:
new绑定 > 显式绑定 > 隐式绑定 > 默认绑定
bind的优先级低于newnull或undefined作为this绑定会被忽略,转为默认绑定
一些函数的this分析
//setTimeout
setTimeout(function () {
console.log(this); //window
}, 1000);
//onclick
var box = document.querySelector(".box");
box.onclick = function () {
console.log(this); //<div class="box"></div>
};
//forEach
var name = ["abc", "cba", "nba"];
var obj = { name: "sun" };
name.forEach(function () {
console.log(this); // 三遍 {name: "sun"}
}, obj);箭头函数
箭头函数是es6之后增加的一种编写函数的方法,并且它比函数表达式要更加简洁。箭头函数不会绑定this、arguments属性,也不能作为构造函数来使用。
nums.forEach((item,index,arr) => {})箭头函数编写优化
1,如果有一个参数()可以省略。
nums.forEach(item=>{})2,如果函数执行体只有一行代码,那么可以省略大括号,并且这行代码的返回值会作为整个函数的返回值
nums.forEach(item => console.log(item))
nums.filter(item => true)3,如果函数执行体只有返回一个对象,那么需要给这个对象加上()
var foo = () => {
return { name: "abc"}
}
var bar = () => ({name: "abc"})箭头函数中的this箭头函数不适应this的四种标准规则,不绑定this,而是根据外层作用域来决定this。 这里使用settimeout来模拟网络请求,然后拿到obj对象,设置data;
不用箭头函数的情况: 拿到的this是window,需要在外层定义:this = this,在setTimeOut的回调函数中使用this就代表了obj对象。
var obj = {
data: [],
getData: function () {
var _this = this;
setTimeout(function () {
var res = ["abc", "cba", "nba"];
_this.data.push(...res);
}, 1000);
},
};使用箭头函数: 箭头函数不绑定this对象,this引用就会从上层作用域中找到对应的this
var obj = {
data: [],
getData: function () {
setTimeout(() => {
var res = ["abc", "cba", "nba"];
this.data.push(...res)
}, 1000);
},
};如果getData也是一个箭头函数,那么settimeout中的回调函数中this指向谁呢? window
var obj = {
data: [],
getData: () => {
setTimeout(() => {
var res = ["abc", "cba", "nba"];
this.data.push(...res);
}, 1000);
},
};相关面试题
var name = "window";
var person = {
name: "person",
sayName: function () {
console.log(this.name);
},
};
function sayName() {
var sss = person.sayName;
sss(); //window 独立函数调用
person.sayName(); //person 隐式调用
(person.sayName)();//person js引擎解析后没有第一对(),相当于隐式函数调用
(b = person.sayName)();//window 独立函数调用
}
sayName();var name = "window";
var person1 = {
name: "person1",
foo1: function () {
console.log(this.name);
},
foo2: () => console.log(this.name),
foo3: function () {
return function () {
console.log(this.name);
};
},
foo4: function () {
return () => {
console.log(this.name);
};
},
};
var person2 = {
name: "person2",
};
person1.foo1(); //person1
person1.foo1.call(person2); //person2
person1.foo2(); //window
person1.foo2.call(person2); //window
person1.foo3()(); //window,独立函数调用。有this不需要向上层找
person1.foo3.call(person2)(); //window 独立函数调用
person1.foo3().call(person2); //person2
person1.foo4()(); //person1。没有this,向上层找
person1.foo4.call(person2)(); //person2。call(person2)将上层作用域绑定给了person2,
person1.foo4().call(person2); //person1var name = "window ";
function Person(name) {
this.name = name;
this.foo1 = function () {
console.log(this.name);
};
this.foo2 = () => console.log(this.name);
this.foo3 = function () {
return function () {
console.log(this.name);
};
};
this.foo4 = function () {
return () => {
console.log(this.name);
};
};
}
var person1 = new Person("person1");
var person2 = new Person("person2");
person1.foo1(); //person1
person1.foo1.call(person2); // person2 显示和隐式同时存在,显示作用
person1.foo2(); //person1 函数具有作用域
person1.foo2.call(person2); // person1
person1.foo3()(); //- window
person1.foo3.call(person2)(); //window
person1.foo3().call(person2); // person2
person1.foo4()(); // person1
person1.foo4.call(person2)(); // person2
person1.foo4().call(person2); // person1var name = "window";
function Person(name) {
this.name = name;
this.obj = {
name: "obj",
foo1: function () {
return function () {
console.log(this.name);
};
},
foo2: function () {
return () => {
console.log(this.name);
};
},
};
}
var person1 = new Person("person1");
var person2 = new Person("person2 ");
person1.obj.foo1()(); //window
person1.obj.foo1.call(person2)(); //window
person1.obj.foo1().call(person2); // person2
person1.obj.foo2()(); // obj
person1.obj.foo2.call(person2)(); // person2
person1.obj.foo2().call(person2); //obj