this是什麼
this就是函數內部的關鍵字
看下面例子理解js中的this
// 例子1
function fnOne () {
console.log(this)
}
'use strict'
function fnOne () {
console.log(this)
}
// 例子2
let a = {
txt: 'hello world',
fn: function() {
console.log(this.txt)
}
}
a.fn()
window.a.fn()
// 例子3
let b = {
txt: 'hello',
obj: {
txt: 'world',
fn: function(){
console.log(this.txt)
console.log(this)
}
}
}
let c = {
txt: 'hello',
obj: {
// txt: 'world',
fn: function(){
console.log(this.txt)
}
}
}
b.obj.fn()
c.obj.fn()
let d = b.obj.fn
d()
// 例子4
function Fn () {
this.txt = 'hello world'
}
let e = new Fn()
e.txt
// 例子5
function Fn () {
this.txt = 'hello world'
return {txt:'hello'}
}
function Fn () {
this.txt = 'hello world'
return [1]
}
function Fn () {
this.txt = 'hello world'
return 1
}
function Fn () {
this.txt = 'hello world'
return null
}
function Fn () {
this.txt = 'hello world'
return undefined
}
let e = new Fn()
e.txt
// 帶有{}或者[]返回值的方法實例化時this指向被改變
// 例子6
// 箭頭函數與包裹它的代碼共享相同的this對象
// 若是箭頭函數在其餘函數的內部
// 它也將共享該函數的arguments變量
let bob = {
_name: "Bob",
_friends: [],
printFriends: () => {
console.log(this._name)
console.log(this)
}
}
let bob = {
_name: "Bob",
_friends: [],
printFriends() {
console.log(this._name)
console.log(this)
}
}
let bob = {
_name: "Bob",
_friends: [1],
printFriends() {
this._friends.forEach((item) => {
console.log(this._name)
})
}
}
// arguments 對象
function square() {
let example = () => {
let numbers = [];
for (let number of arguments) {
numbers.push(number * number);
}
return numbers;
};
return example();
}
square(2, 4, 7.5, 8, 11.5, 21); // returns: [4, 16, 56.25, 64, 132.25, 441]
this的指向
this永遠指向的是最後調用它的對象(箭頭函數除外)
this的應用
如何改變函數的this指向 apply call bind
三者的區別apply和call改變函數this並且是當即執行。bind(es5新加方法注意兼容性)是複製函數,不會當即執行。根據各自執行時機的不一樣來選擇採用哪一種方案。
function Product(name, price) {
this.name = name
this.price = price
}
function Food(name, price) {
Product.call(this, name, price)
// Product.apply(this, arguments)
this.category = 'food'
}
console.log(new Food('cheese', 5).name)
bind用法和能夠解決的問題
// 解決,從對象中拿出方法定義給新變量,可是但願方法的this值保持不變這時能夠用bind來綁定this
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 返回 81
var retrieveX = module.getX;
retrieveX(); // 返回 9, 在這種狀況下,"this"指向全局做用域
// 建立一個新函數,將"this"綁定到module對象
// 新手可能會被全局的x變量和module裏的屬性x所迷惑
var boundGetX = retrieveX.bind(module);
boundGetX(); // 返回 81
// bind配合setTimeout()
function LateBloomer() {
this.petalCount = Math.ceil(Math.random() * 12) + 1;
}
LateBloomer.prototype.bloom = function() {
window.setTimeout(this.declare.bind(this), 1000);
}
LateBloomer.prototype.declare = function() {
console.log('I am a beautiful flower with ' +
this.petalCount + ' petals!');
}
var flower = new LateBloomer();
flower.bloom(); // 一秒鐘後, 調用'declare'方法
箭頭函數的this使用注意事項
一、函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。
二、不能夠看成構造函數,也就是說,不可使用new命令,不然會拋出一個錯誤。
三、不可使用arguments對象,該對象在函數體內不存在。若是要用,能夠用 rest 參數代替。
四、不可使用yield命令,所以箭頭函數不能用做 Generator 函數。
五、不能使用apply/call/bind
// 箭頭函數可讓setTimeout裏面的this,綁定定義時所在的做用域,而不是指向運行時所在的做用域。下面是另外一個例子。
function Timer() {
this.s1 = 0;
this.s2 = 0;
// 箭頭函數
setInterval(() => this.s1++, 1000);
// 普通函數
setInterval(function () {
this.s2++;
}, 1000);
}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3
// s2: 0
// 箭頭函數可讓this指向固定化,這種特性頗有利於封裝回調函數。下面是一個例子,DOM 事件的回調函數封裝在一個對象裏面。
var handler = {
id: '123456',
init: function() {
document.addEventListener('click',
event => this.doSomething(event.type), false);
},
doSomething: function(type) {
console.log('Handling ' + type + ' for ' + this.id);
}
};