This关键字与ES6新特性
一、this关键字
-
每一个函数内部都有一个关键字
this
-
可以让我们直接使用的
-
函数内部的
this
指向谁,取决于函数的调用方式-
全局定义的函数调用,
this =>window
function fn(){ console.log(this) } fn() //此时this指向window
-
对象内部的方法调用
this = >调用者
var obj = { fn:function (){ console.log(this) } } obj.fn() //此时this指向obj
-
定时器的处理函数,
this =>window
setTimeout(function(){ console.log(this) },1000) //此时定时器处理函数里面的this指向window
-
事件处理函数,
this => 事件源
div.onclick = function(){ console.log(this) } //当你点击div时,this指向div
-
自调用函数,
this =>window
(function(){ console.log(this) })() //此时this指向window
-
重点: 函数内部的this只和函数的调用方式有关系,和函数定义的方式没有关系
-
二、call、apply和bind
这个三个方法可以改变this指向
call
-
call
方法是附加在函数调用者后面使用,可以忽略函数本身的this指向语法:
函数名.call(要改变的this指向,要给函数传递的参数1,要给函数传递的参数2)
var obj = {name:'jack'} function fn(a,b){ console.log(this) console.log(a) console.log(b) } fn(1,2) fn.call(obj,1,2)
fn()
的时候,函数内部的this指向windowfn.call(obj,1,2)
的时候,函数内部的this就指向obj这个对象- 使用call方法
- 会立即执行函数
- 第一个参数是你要改变的函数内部的this指向
- 第二个参数开始,依次是向函数传递参数
apply
-
apply
方法是附加在函数调用后面使用,可以忽略函数本身的this指向 -
语法:
函数名.apply(要改变的this指向,[要给函数传递的参数1,要给函数传递的参数2...])
var obj = {name:'jack'} function fn(a,b){ console.log(this) console.log(a) console.log(b) } fn(1,2) fn.apply(obj,[1,2])
fn()
的时候,函数内部的this指向windowfn.apply(obj,[1,2])
的时候,函数内部的this指向就指向了obj这个对象- 使用apply方法的时候
- 会立即执行函数
- 第一个参数是你要改变的的函数内部的this指向
- 第二个参数是一个 数组 ,数组里面的每一项依次是向函数传递的参数
bind
-
bind
方法是附加在函数调用后面使用,可以忽略函数本身的this指向 -
和
call、apply
有一些不一样,就不会立即执行函数,而是返回一个已经改变了this指向的函数var obj = {name:'jack'} function fn(a,b){ console.log(this) console.log(a) console.log(b) } fn(1,2) var newFn = fn.bind(obj) newFn(1,2)
- bind调用的时候,不会执行fn这个函数,而是返回一个新的函数
- 这个新的函数就是一个改变了this指向以后的fn函数
- fn(1,2)的时候this指向window
- newFn(1,2)的时候执行的是一个和fn一模一样的函数,只不过里面的this指向
改变成了obj
三、ES6新特性
1.let和const关键字
-
我们以前都是使用
var
关键字来声明变量的 -
在ES6的时候,多了两个关键字let和const,也是用来声明变量的
-
let和const不允许重复声明变量
//使用var的时候重复声明变量是没有问题的,只不过后面的会把前面的覆盖掉 var num = 100 var num = 200 //使用let重复声明变量的时候就会报错 let num = 100 let num = 200 //这里就会报错 //使用const重复声明变量的时候就会报错 const num = 100 const num = 200 //这里就会报错
-
let
和const
没有变量提升 -
let
和const
声明的变量会被所有代码块限制作用范围//var 声明的变量只有函数能限制其作用域,其他不能限制 if(true) { var num = 100 } console.log(num) //100 //let声明变量,除了函数可以限制,所有其他的代码块都可以限制其作用域(if/while/for/..) if(true){ let num = 100 console.log(num) //100 } console.log(num) //报错 //const声明变量,除了函数可以限制,所有代码块都可以限制其作用域(if/while/for/...) if(true){ const num = 100 console.log(num) //100 } console.log(num) //报错
2.箭头函数
-
箭头函数是ES6里面一个简写函数的语法方式
-
重点: 箭头函数只能简写函数表达式,不能简写声明式函数
function fu () {} //不能简写 const fu = function () {} //可以简写 const obj = { fn:function () {} //可以简写 }
-
语法: (函数的形参) =>{函数体内要执行的代码}
const fn = function (a,b) { console,log(a) console.log(b) } //可以使用箭头函数写成 const fu = (a,b) => { console.log(a) console.log(b) } const obj = { fn:function(a,b) { console.log(a) console.log(b) } } //可以使用箭头函数 const obj = { fn:(a,b) =>{ console.log(a) console.log(b) } }
-
箭头函数的特殊性
-
箭头函数内部没有
this
,箭头函数的this
是向下文的this
//在箭头函数定义的位置往上数,这一行是可以打印出this的 //因为这里的this是window //所以箭头函数内部的this就是window const obj = { fn:function () { console.log(this) }, //这个位置是箭头函数 的上一行,但是不能打印出this fun:() =>{ //箭头函数内部的this是书写箭头函数的上一行一个可以打印出this的位置 console.log(this) } } obj.fn() obj.fun()
-
函数的形参只有一个的时候可以不写(),其余情况必须写
const obj = { fn:() =>{ console.log('没有参数,必须写小括号') }, fn2:a =>{ console.log('一个形参,可以不写小括号') }, fn3:(a,b) =>{ console.log('两个或者两个以上参数,必须写小括号') } }
-
函数体只有一行代码的时候,可以不写{},并且会自动return
const obj ={ fn:a =>{ return a+10 }, fun:a =>a+10 } console.log(fn(10)) //20 console.log(fun(10)) //20
-
3.函数传递参数的时候的默认值
-
我们在定义函数的时候,有时候需要一个默认值出现
-
就是当我们不传递参数的时候,使用默认值,传递参数了,就使用传递的参数
function fn(a){ a = a || 10 console.log(a) } fn() //不传递参数的时候,函数内部的a就是10 fn(20) //传递了参数20的时候,函数内部的a就是20
-
在ES6中,我们可以直接把默认值写在函数的形参位置
function fn(a=10){ console.log(a) } n() //不传递参数的时候,函数内部的a就是10 n(20) //传递了参数20的时候,函数内部就是a 20
-
这个默认值的方式在箭头函数中也可以使用
const fn = (a=10) =>{ console.log(a) } fn() //不传递参数的时候,函数内部的a就是10 fn() //传递了参数20的时候,函数内部a就是20 //注意:箭头函数如果你要使用默认值的话,那么一个参数的时候也要写()
4.解构赋值
就是快速的从对象或者数组中取出成员的一个语法方式
-
解构对象
//快速的从对象中获取成员 //ES5的方法想得到对象中的成员 const obj = { name:'jack', age:18, sex:'男' } let name = obj.name let age = obj.age let sex = obj.sex //解构对象 //解构赋值的方式从对象中获取成员 const obj = { name:'jack', age:18, sex:'男' } //前面的{}表示我要从obj这个对象中获取成员了 //name age sex 都是obj中有的成员 //obj 必须是一个对象 let {name,age,sex} = obj
-
解构数组
//快速的从数组中获取成员了 //ES5的方式从数组中获取成员 const arr = ['jack','rose','tom'] //前面的[]表示要从arr这个数组中获取成员了 //a b c 分别对应这个数组中的索引0 1 2 //arr必须是一个数组 let [a,b,c]
-
注意
- {}是专门解构对象使用的
- []是专门解构数组使用的
- 不能混用
5.展开运算符
-
ES6里面新添加了一个运算符
...
,叫做展开运算符 -
作用是把数组展开
let arr = [1,2,3,4] console.log(...arr) //1 2 3 4
-
合并数组的时候可以使用
let arr = [1,2,3,4] let arr2 = [...arr,5] console.log(arr2) //1,2,3,4,5
-
也可以合并对象使用
let obj = { name:'jack', age:18 } let obj2 = { ...obj, sex:'男' } console.log(obj2)
-
在函数传递参数的时候也可以使用
let arr = [1,2,3] function fn(a,b,c){ console.log(a) console.log(b) console.log(c) } fn(...arr) //等价于fn(1,2,3)
6.对象字面量简化写法
const name = 'jack'
const age = 20
//ES6
const person = {
name,
age
}
//ES5
var person = {
name: name,
age, age
}
四、js错误处理机制
1.错误类型
-
逻辑错误
-
运行时错误
-
JavaScript解析或运行时,一旦发生错误,引擎就会抛出一个错误对象Error
var err = new Error('出错了') err.message //'出错了'
-
2.常用错误对象
- SyntaxError 对象
- SyntaxError对象是解析代码时发生的语法错误。
- ReferenceError 对象
- ReferenceError对象是引用一个不存在的变量时发生的错误
- TypeError 对象
- TypeError对象是变量或参数不是预期类型时发生的错误
- RangeError 对象
- RangeError对象是一个值超出有效范围时发生的错误。
- 主要有几种情况,一是数组长度为负数,二是Number对象的方法参数超出范围,以及函数堆栈超过最大值。
3.throw语句
-
throw
语句的作用就是手动中断程序执行,抛出一个错误if(x<0){ throw new Error('x 必须为正数') }
-
对于JavaScript引擎来说,遇到throw语句,程序就终止了,引擎会接收到throw抛出的信息
4.try…catch语句
一旦发生错误,程序就终止执行了。JavaScript提供了try…catch结构,允许对错误程序进行处理,选择是否往下执行
try {
throw new Error('出错了')
} catch (e) {
console.log(e.name + ":" + e.message)
console.log(e.stack)
}
5.finally代码块
try…catch结构允许在最后添加一个finally代码块,表示不管是否出现错误,都必需在最后运行的语句。
try {
throw new Error('出错了...')
console.log('此行不会执行')
} finally {
console.log('完成清理工作')
}