箭头函数
ES6 允许使用“箭头”(=>
)定义函数。箭头函数看似是一个函数,其实他不是一个函数他是一个函数表达式
es5
的方式定义了一个函数表达式
var x = function(){
console.log('我是函数表达式')
}
x();//让函数执行
es6
定义了一个箭头函数的形式
let fn = ()=>{//箭头函数是简化函数这种写法的
//把原本的function关键词去掉换成=>,在和()换一下位置这就是箭头函数的写法了
console.log('我是箭头函数')//箭头函数必须是匿名函数的写法
}
fn();//箭头函数执行
在es6
中如何给箭头函数传递参数
let fn = (a,b)=>{//箭头函数和普通函数传递参数的方式是一样的都在()内部传递参数
console.log(a+b);
}
fn('我是箭头函数',1)
那么在箭头函数内部只有一个参数该怎么传递参数??
let fn = a=>{//当你在箭头函数中只有一个参数传进来的时候,那么()可以省略掉不写
console.log(a)
}
fn('我是箭头函数我只有一个参数')
那么在箭头函数中只有一句return
呢??
let fn = a=>a;
//当箭头函数的花括号内部,只有一句代码并且是return这一句代码,那么这个箭头函数的{}可以去掉
let result = fn('我是箭头函数,我的代码里面只有一句return');
console.log(result)
验证箭头函数内部是没有this
的
es5
中函数调用this
指向问题:下面的这种情况
let obj = {
name:'huasheng',
sayName:function(){
console.log(this.name);
}//这个函数的this指向,是谁调用了我这个函数那么this就会指向调用这个函数的数据
}
obj.sayName();//这个函数是通过obj调用的所以,this指向obj
es6
中箭头函数内部的this
指向问题
var name = 'lal';
var obj = {
name:'huasheng',
sayName:()=>{
//箭头函数内部是没有this的,他是借用箭头函数的所在环境的this
//(箭头函数的this是没有办法改变的)
console.log(this.name);
}//现在箭头函数的this所在环境是全局环境下的this-->window,就去全局环境找到name属性
}
obj.sayName();
总结箭头函数的用法
- 当箭头函数只有一个形参 则
()
可以去掉 - 当箭头函数的代码块 只有一句
return
时 则{}
可以省略 - 箭头函数的
this
指向了 箭头函数所在的环境 - 箭头函数内部也没有
arguments
箭头函数this
指向练习
第一题
var x = 11;
var obj = {
x:22,
say:()=>{
console.log(this.x);//箭头函数this-->window 打印11
}
}
obj.say();
/*
当前在对象中添加了一个箭头函数的方法,箭头函数的this指向是箭头函数所在的环境,
当前箭头函数所在的环境是全局环境下自己内部没有变量x就就会去全局环境中找结果是 x = 11
*/
第二题
/*
GO{
}
*/
let a = 11;
function Test(){
/*
this-->{
a:22,
} return this
*/
this.a = 22;
let b = function(){
/*AO{
this:window
}*/
console.log(this.a)//undefined
}
b();
}
let x = new Test();
/*
通过let声明一个变量是不会挂在window对象上面
通过new启动了Test()函数把这个构造函数赋值给了变量x,然后this.a = 22
把这个变量a添加到构造函数内部a:2
声明一个函数表达式里面的this指向是全局
(在每次函数预编译的时候都是会添加this的 this-->window)查询全局的a结果是undefined
*/
第三题
/*
GO{
a:undefined -->a:11
}
*/
var a = 11;
function test1(){
/*
this-->{
a:22,
}return this
*/
this.a = 22;
let b = ()=>{
/*
AO{
this-->test1:function(){}
}
*/
console.log(this.a);//22
}
b();
}
let x = new test1();
/*
在全局环境下声明了一个变量a值是22自动挂载在全局中,
用new声明的一个test1的一个构造函数赋值给了变量x,
往这个构造函数中内部添加一个a=22的变量,用let方式声明了一个箭头函数表达式(箭头函数本质是函数表达式)
箭头函数里面的this指向是当前所在的环境是用new启动的构造函数的环境this-->test1查询里面的a值是22
*/
第四题
/*
GO{
a:undefined --> a:11,
}
*/
var a = 11;
function test2(){
/*
this-->{
a:22
} return this
*/
this.a = 22;
return ()=>{
/*
AO{
this:test2
}
*/
console.log(this.a);//22
}
}
var x = new test2()();
/*
在全局环境在声明了一个变量a值是11变量a自动挂在在全局当中,然后通过new关键词启动款test2这个构造函数
构造函数的内部this指向是test2然后在构造函数内部中添加了一个a值是22
然后用return把这个箭头函数抛出去用test2接收在次用()启动箭头函数(这时箭头函数是在test2的外部)
return也会把箭头函数的函数作用域链给抛出来然后查询this里面的a就是查询test2里面的a值是22
*/
第五题
/*
GO{
obj:undefined --> obj:{}
}
*/
var obj = {
say:function(){
/*
AO{
this:obj
}
*/
var fn = ()=>{
console.log(this,1);
setTimeout(()=>{
/*
AO{
this:obj
}
*/
console.log(this,2)
},20);
};
fn();
},
};
obj.say();//当前这个say函数是通过obj这个对象调用的
//在这种情况下普通函数的内部this指向是obj(普通函数通过谁调用那么this就指向谁);
/*
在全局中声明了一个obj对象会自动挂在全局当中,
然后通过obj调用say这个函数那么这个say的函数内部的this指向是obj
(通过谁调用那么this指向就指向谁),然后里面一个箭头函数这个箭头函数内部的this是指向obj
(因为箭头函数是没有this的他会往自身环境下去找this),
然后开了一个setTimeout延迟定时器20秒执行内部的箭头函数这时的箭头函数内部的this
也是没有的他会去当前环境下去寻找this this-->obj
*/
第六题
/*
GO{
obj:undefined --> obj:{}
}
*/
var obj = {
say:function(){
/*
AO{
this:obj,
f1:undefined --> f1:function(){}
}
*/
var f1 = function(){
/*
AO{
this:window
}
*/
console.log(this);
setTimeout(()=>{
console.log(this)
})
}
f1();
}
}
obj.say();
/*
用var声明的obj这个变量会自动挂在全局作用域当中,在通过obj调用say函数里面的this执行发生改变
this-->obj,在say函数里面声明一个变量并且存储了一个function函数里面的this发生改变this-->window,
在f1里面里面开了一个计时器是以箭头函数的形式的回调函数自己没有this会在自身环境中去找
this-->window
*/
第七题
/*
GO{
obj:undefined --> obj:{},
o:undefined --> o:{}
}
*/
var obj = {
fn:function(){
console.log(this);//f:function(){}
},
f:()=>{
console.log(this);//window
}
}
var o = {
f:function(){
/*
AO{
this:f:function(){}
}
*/
obj.f();
obj.fn();
}
}
o.f();
/*
在全局中声明了变量obj和o都挂在全局作用域中,然后通过o调用了f这个函数里面的this指向f这个函数
里面在他会obj调用了f这个函数这个函数是箭头函数是没有this的而自身环境下的this-->window
在通过obj调用fn这个函数,fn函数里面的this指向是到底被谁调用了我this-->f:function(){}
*/
使用注意点
箭头函数有几个使用注意点。
- 函数体内的
this
对象,就是定义时所在的环境,而不是使用时所在的对象。 - 函数体内的
this
对象,就是定义时所在的环境,而不是使用时所在的对象。 - 不可以使用
arguments
对象,该对象在函数体内不存在。如果要用,可以用rest
参数代替。 - 不可以使用
yield
命令,因此箭头函数不能用作Generator
函数。
对象的扩展
es5
中定义对象的方法和写法
var name = 'hausheng';
var age = 28;
var obj = {//定义了一个对象,在对象里面添加name属性和age属性
name:name,
age,age,
}
console.log(obj)
es6
中定义对象的方法和写法
对象中属性名的简洁写法
var name = 'huahseng';
var age = 28;
var obj = {
name,
age,
//当你的属性名字和你要使用的变量名字完全一致时,只写一个就可以了
//(属性名和要使用的变量名必须完全一致)对象的简洁写法
}
console.log(obj);
对象中方法的简洁写法
es5
对象中方法的正常写法
var name = 'huasheng';
var age = 28;
var obj = {
name,
age,
sayName:function(){
console.log('sayName')
}
}
//在写es5的代码中对象中是能写很多方法的就是(function函数)
//这样就照成了打很多的重复的代码是不会的,那么es6就解决了这个问题
obj.sayName();
es6
对象中方法的简洁写法
var name = 'huasheng';
var age = 28;
var obj = {
name,
age,
sayName(){//这种形式的简写写法是普通函数的简写形式
console.log(this)
},
sayName1:function(){//普通函数
console.log(this)
},
sayName2:()=>{//箭头函数
console.log(this)
}
}//在es6中Dev对象中方法简洁写法:
//是把function关键词和:去掉即可和es5中对象里面的方法写法完全一致不会报错
obj.sayName();
obj.sayName1();
obj.sayName2();
对象中的属性定义方法
在es5
中定义对象的方法(字面量形式)
var person = {//es5中定义对象的方法
name:'huasheng',
age:28,
//我们在for in 循环的时候用typeof检测属性名的时候他是一个字符串,
//其实完整写法是以下这种形式的
"name1":'huasheng',
"age1":28,//用字面量形式定义的对象属性名是一个字符串(这种方法一般不用)
}
//通过对象.属性名的方式取值
console.log(person.name);//取到person对象中的name属性
//通过对象["属性名"]的方式取值
console.log(person['age']);//取到person对象中的age属性
//在es5中只能通过以上两种方式取到对象中的属性值
在es6
中定义对象的方法(字面量形式)
var a = 'sex';
var person = {
name:'huasheng',
age:28,
['sex']:'male',//在es6新增的用["属性名"]的方式定义一个对象
//这中定义对象的属性名的方式是字符串形式的如果不是字符串形式的那么我会隐式类型转换成字符串
[a]:'mingz',//通过这种方式添加的对象[]里面是个变量和在获取到这个属性的时候也要添加这个
//[变量]和上面的方法完全一致(不常用)
['hello'](){
console.log('我是函数');
},//通过中括号定义了一个函数属性名是hello属性值是普通函数的简洁写法
}
//这样JS就可以通过:和[""]定义对象和通过.和[""]获取对象了
console.log(person.name,person.age,person["sex"],person[a],person.hello());
新增方法
Object.is()
方法
ES5 比较两个值是否相等,只有两个运算符:相等运算符(==
)和严格相等运算符(===
)。它们都有缺点,前者会自动转换数据类型,后者的NaN
不等于自身,以及+0
等于-0
。JavaScript 缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等。
ES6 提出同值相等算法,用来解决这个问题。Object.is
就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===
)的行为基本一致。
Object.is('foo', 'foo')
// true
Object.is({}, {})
// false 两个对象的引用地址不一样结果就是false
不同之处只有两个:一是+0
不等于-0
,二是NaN
等于自身。
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
Object.assign()
方法
Object.assign
方法用于对象的合并,将源对象(source
)的所有可枚举属性,复制到目标对象(target
)。
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
如果只有一个参数,Object.assign
会直接返回该参数。
const obj = {a: 1};
Object.assign(obj) === obj // true
注意:Object.assign
可以用来处理数组,但是会把数组视为对象。
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
//把数组视为属性名为 0、1、2 的对象,因此源数组的 0 号属性4覆盖了目标数组的 0 号属性1。
Object.keys()
方法
ES5 引入了Object.keys
方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable
)属性的键名。
var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]
ES2017 引入了跟Object.keys
配套的Object.values
和Object.entries
,作为遍历一个对象的补充手段,供for...of
循环使用。
let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };
for (let key of keys(obj)) {
console.log(key); // 'a', 'b', 'c'
}
for (let value of values(obj)) {
console.log(value); // 1, 2, 3
}
for (let [key, value] of entries(obj)) {
console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}
Object.values()
方法
Object.values
方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable
)属性的键值。
const obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]
返回数组的成员顺序,
const obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj)
// ["b", "c", "a"]
上面代码中,属性名为数值的属性,是按照数值大小,从小到大遍历的,因此返回的顺序是b、c、a。
Object.entries
方法
Object.entries
方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable
)属性的键值对数组。
const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
除了返回值不一样,该方法的行为与Object.values
基本一致。
对象的扩展运算符
解构赋值
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }
解构赋值必须是最后一个参数,否则会报错。
let { ...x, y, z } = obj; // 句法错误
let { x, ...y, ...z } = obj; // 句法错误
注意,解构赋值的拷贝是浅拷贝,即如果一个键的值是复合类型的值(数组、对象、函数)、那么解构赋值拷贝的是这个值的引用,而不是这个值的副本。
let obj = { a: { b: 1 } };
let { ...x } = obj;
obj.a.b = 2;
x.a.b // 2
扩展运算符
扩展运算符(...
)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
这等同于使用Object.assign
方法。
let aClone = { ...a };
// 等同于
let aClone = Object.assign({}, a);