学习内容:
- this指向定义时所在的对象,而不是调用时所在的对象
- 不可以当作构造函数
- 不可以使用arguments对象
1、this指向定义时所在的对象,而不是调用时所在的对象
先来回顾一下ES5当中如何定义函数:
function sum(x, y) {
return x + y
}
console.log(sum(1, 2))
----
3
还有一种形式,把函数赋值给一个变量:
let sum = function(x, y) {
return x + y
}
console.log(sum(1, 2))
----
3
以上两种方式的区别是,第一种定义函数的方法中,sum函数会被预定义,也就是说,无论是先定义再调用,还是先调用再定义都不会报错;第二种方法let定义的函数,只能先定义再调用,因为let不存在变量提升。
注意:src下面的代码会被webpack打包编译报错信息不明显,但如果放到static目录下就直接报错了,提示sum没有被定义
下面是箭头函数的写法(箭头函数左边是参数,右边是函数体)
- 首先箭头函数不需要写function关键字
- 然后在参数和函数体之间加一个等号大括号=>
let sum = (x, y) => {
return x + y
}
console.log(sum(1, 2))
----
3
当函数体只有一行代码,{}可以省略不写,return关键字也可以省略,上面的代码等价于:
let sum = (x, y) => x + y
console.log(sum(1, 2))
----
3
写到这里,复习了ES5的函数写法,也了解了ES6的箭头函数的写法
现在可以来看看“this指向定义时所在的对象,而不是调用时所在的对象”是什么意思了。
// Mac Pro的键盘敲起来真的是舒服 ^_^
通过例子演示,先来看看ES5中的this:
在html中写一个button,
<button id="btn">完成</button>
然后通过DOM操作获取这个button,给button绑定一个点击事件,此时的this指向button对象,
let btn = document.querySelector('#btn')
btn.addEventListener('click',function() {
console.log(this)
})
// 在HTML页面中点击按钮
-------------------------------
<button id="btn">完成</button>
给上面的代码加一个定时器 ,把console.log(this)放到setTimeout里面来输出,
let btn = document.querySelector('#btn')
btn.addEventListener('click',function() {
setTimeout(function () {
console.log(this)
}, 1000)
})
// 在HTML页面中点击按钮
------------------------------------------------------------------------------------------------
Window {window: Window, self: Window, document: document, name: '', location: Location, …}
我们看到输出了Window {....,这是因为此时的this指向的是调用时的对象,setTimeout是window的对象,this的作用域在{}里面,所以当前对象也就是指的window,上面的代码也可以改成:
window.setTimeout(function () {
console.log(this)
}, 1000)
但是,我还是希望等一秒输出,但希望this指向button而不是window,也就是要改变this指向,有三个方法可以实现,call、apply、bind,这里需要用bind代码:
let btn = document.querySelector('#btn')
btn.addEventListener('click',function() {
window.setTimeout(function () {
console.log(this) // 希望这个this指向谁,外面的bind就传入谁
}.bind(this), 1000)
})
// 在HTML页面中点击按钮
-------------------------------
<button id="btn">完成</button>
现在来看如何通过箭头函数来实现改变this的指向
箭头函数里面,this指向定义时所在的对象,而不是调用时所在的对象
let btn = document.querySelector('#btn')
btn.addEventListener('click',function () {
setTimeout(() => {
console.log(this)
}, 1000);
})
----------------------------------
<button id="btn">完成</button>
其实箭头函数里并没有this,上面的this是继承了外面一层上下文中的this,所以外面的this就是指向的btn
2、不可以当作构造函数
还是先来看ES5当中如何模拟一个类
用function模拟一个类
function Peple(name, age) {
console.log(this) //this指向的是peple对象
this.name = name
this.age = age
}
let peple = new Peple('Sure','36')
console.log(peple)
---------------------------------------
Peple {}
age: "36"
name: "Sure"
[[Prototype]]: Object
Peple {name: 'Sure', age: '36'}
age: "36"
name: "Sure"
[[Prototype]]: Object
现在把上面的Peple改为箭头函数来试一下
let Peple = (name, age) => {
this.name = name
this.age = age
}
let peple = new Peple('Sure','36')
console.log(peple)
------------------------------------------------------------------------------
Peple {}
[[Prototype]]: Objectconstructor: ƒ Peple(name, age)[[Prototype]]: Object
发现Peple里面什么也没有。首先在VS Code脚手架里执行的代码跟浏览器里执行的代码是不一样的,因为当前环境使用webpack完成代码构建,这里面使用了一个叫eval的函数,这个eval可以把字符串作为代码去执行,所以用eval去执行代码会和实际有不同。
现在把代码放到浏览器中执行,
现在看到了箭头函数不可以当作构造函数
3、不可以使用arguments对象
先写ES5代码
let test = function () {
console.log(arguments)
}
test(1, 2, 3)
--------------------------------------------------------------
Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
现在把它改成箭头函数:
let test = () => {
console.log(arguments)
}
test(1, 2, 3)
------------------------------------------------------------------
Arguments(3) [{…}, {…}, ƒ, callee: ƒ, Symbol(Symbol.iterator): ƒ]
0: {i: './src/2-7.js', l: true, exports: {…}}
1: {}
2: ƒ __webpack_require__(moduleId)
callee: ƒ (module, exports)
length: 3
Symbol(Symbol.iterator): ƒ values()
[[Prototype]]: Object
虽然也能输出一些参数,但参数已经不是1,2,3了,但也是受eval函数影,现在再放到浏览器中执行看一下:
如果还是想输出1,2,3,可以使用rest运算符实现:
let test = (...args) => {
console.log(args)
}
test(1, 2, 3)
----------------------
(3) [1, 2, 3]