变量声明
var 特点:
1.可以重复声明
2.不能定义常量
3.不支持块级作用域
复制代码
- let
//1.不存在预解释 变量提升
//2.暂时性死区
//3.具备块级,同一块内不能重复声明;
let a ={name:'xiaoming'}
if(true){
let a = 'xiaohong';//不同块,可以声明相同名;
}
console.log(a) //{name:'xiaoming'}
if(true){
let v= '20130401'
}
console.log(v) //报错:v is not defined
for(var i=0;i<3;i++){//i是全局的
//闭包
(function(i){
setTimeout(function(){
console.log(i)
})
})(i)
}
//用let
for(let i = 0;i<3;i++){//i是块级的
setTimeout(function(){
console.log(i)
},1000)
}
复制代码
- const
//不存在预解释、变量提升
//不能重复定义声明
//不能更改他的值。
//具备块级
const str = 123;
str = 3445;//报错:常量不能重新赋值
const = obj = {name:'xiaoming'}
obj.name= 'xiaohong';//可以修改;const限制的是不能给变量重新赋值,给变量的属性修改,实际并未修改内存地址。
复制代码
解构
解构就是分解一个对象的解构,可以用一种类似数组的方式定义n个变量,可以将一个数组中的值按照规则赋值过去。
解构的时候,等号两边结构类似;左边对象右边就是对象;左边数据右边也得是数组,右边还必须是一个真是存在的值;
复制代码
- 数组、对象的简单解构赋值
var arr = [1,2,3]
var [a,b,c] = arr; // a=>1 b=>2 c=>3
var obj = {a:1,b:2}
var {a,b} = obj; //对象解构,根据key解构,a=>1,b=>2
var {a:a1,b:b1} = obj;// 对象解构,不用key作为变量名,指定变量名; a1=>1 b1=>2
复制代码
- 嵌套解构赋值
var arr = [{a:1,b:2},[3,4],5]
var [{a,b},[c,d],e] = arr; //结构一样,a=1 b=2,c=3,d=4,e=5
var [obj,ary,n] = arr ; //整合起来赋值,obj= {a:1,b:2} ary=[3,4] n=5
复制代码
- 默认赋值解构;如果能取到值就用取到的,取不到(undefined)时就用默认的值;
var obj = {a:1}
var {a,b} = obj;
console.log(b)//undefined
var {a,b=2} = obj;
console.log(b)//2
var ary = [1,,3]//ary[1] = undefined
var [a = "a", b = "b", c =new Error('C必须指定')] = ary;
console.log(a, b, c);// 1,b,3
function ajax(options){
var method = options.method || 'get'
var data = options.data || {}
...
}
函数声明形参利用解构赋值+默认赋值
function ajax({method='get',data={}){
//函数传参解构赋值,相当于let了这个变量;
console.log(method,data)
}
ajax({
method:'get',
data:{id:1}
})
复制代码
- 省略赋值
var arr = [1,2,3]
var [,,j] = arr;
console.log(j)//3 只想取出数组最后一个
复制代码
模版字符串
- 1.可以嵌套变量
- 2.支持换行
- 3.可带一个标签属性进行描述,因为我们希望有时候在拼接字符串的时候有自己的逻辑
var name = 'xiaoming',age = 9;
var str = `${name}今年${age}岁`
var str1= `${name}
今年${age}岁
`console.log(str)
console.log(str1)
//把老数组中的每一个元素应设为新数组中的每一个元素
var users = [{id:1,name:'zfpx1'},{id:2,name:'zfpx2'}]
var newUser = users.map(item=>{
return `<li>${item.id}:${item.name}</li>`
})
let str = (`
<ul>
${newUser}
</ul>
`)
console.log(str)
//描述
//带标签的模版字符串就像一个函数调用
//参数:第一个参数是文本的数组,剩下的依次是模版字符串中出现的变量值;可以用剩余运算符收拢起来
//strings 文本的数组 指的是 模版字符串被变量分割出来的数组。
function desc(strings,...rest){
let result = '';
for(let i =0;i<rest.length;i++){
result +=(strings[i]+rest[i])
}
result += strings[strings.length-1] //strings是被变量分割出来的,所以长度比rest多一个;
return result;
}
var str = desc`${name}今年{age}岁了`
//str就是desc的返回值
面试:模版字符串(ejs等字符串模版通用原理)的原理:正则匹配-分组捕获-替换
var name = 'xiaoming',age = 9;
var tem = "${name}今年${age}岁了";
function replace(tem){
return tem.replace(/\$\{(\w+)\}/g,function(...args){
//args[0] 匹配到的整个串
//args[1] 第一个分组捕获的
return eval(args[1]);//替换匹配到的整个串
})
}
console.log(replace(tem))
复制代码
字符串新增的方法
- includes 是否包含
- startsWith 是否以什么开头
- endsWith 是否以什么结尾
- repeat 重复多少遍,返回新的字符串
let address1 = 'http://www.baidu.com'
let address2 = 'ftp://www.baidu.com'
if(address1.startsWith('http')){
console.log('http网址')
}else if(address1.endsWidth('http')){
console.log('ftp服务')
}
let filename = 'avatar.jpg';
if(filename.endsWith('jpg') || filename.endWith('png')){
console.log('图片')
}
let str = 'zfpx'
str.includes('z')//true 包含
let str2 = str.repeat(3);// zfpxzfpxzfpx 重复三遍,返回新的字符串
复制代码
func方法(函数传参、接收参数、剩余运算符、展开运算符)
- 默认参数:可以指定默认值,没传的话(undefined)就用默认值;指定必传参数,不传报错;解构赋值参数; function ajax(url=new Error('url不能为空'),method='get',dataType='json'){ console.log(url) console.log(method) console.log(dataType) } function ajax1({url=new Error('url不能为空'),method='get',dataType='json'}){ console.log(url) console.log(method) console.log(dataType) }
ajax('/user') ajax1({ url:'/user' })
- 剩余操作符,函数接收参数时使用,只能作为函数的最后一个接收参数使用;
//求和
function sum(prefix,...rest){
let n = rest.reduce((prev,next,nextIndex,origin)=>{
return prev+next;
})
return prefix+n
}
sum('$',1,2,3,4)
//求平均值
function fn(...rest){
return rest.reduce((prev,next,nextIndex,origin)=>{
let sum = prev+next;
if(nextIndex == origin.length-1){
return sum/origin.length;
}else{
return sum;
}
})
}
fn(1,2,3,4)
复制代码
- 展开运算符(浅拷贝、合并对象、函数入参)
//数组
var arr1 = [1,2,3]
var arr2 = [4,5,6]
var arr3 = [...arr1,...arr2]
var arr4 =arr1.concat(arr2)
//对象
var obj1 = {a:1,b:2}
var obj2 = {c:3,d:4}
var obj3 = {
...obj1,
...obj2
}
var obj4 = Object.assign({},obj1,obj2)
//函数入参
function sum(a,b,c){
return a+b+c
}
sum(...arr1)
Math.max(1,2,3)
Math.max.apply(null,arr1)
Math.max(...arr1)
前端面试扩展:
//深拷贝、浅拷贝
浅拷贝: ...展开运算符、Object.assign
深拷贝:
JSON.parse(JSON.stringify({home:{city:'beijing'}))
function deepClone(origin){
let result;
if(origin instanceof Array){
result = [];
for(let i=0;i<origin.length;i++){
result.push(deepClone(origin[i]))
}
}else if(origin instanof Object){
result = {};
for(let key in origin){
result[key] = deepClone(origin[key])
}
}else{
result = origin
}
return result;
}
//reduce 的原理
//reduce 支持两个参数:第一个参数是函数,第二个参数是初始值(不传的话默认是数组第一项)
//主要原理 就是 上一次的执行结果是下一次的初始值。
var arr = [1,2,3,4]
arr.reduce((prev,next,nextIndex,origin)=>{
return prev +next
},10) //初始值是10,第一次调用prev是10,next是1,nextIndex是0, 最后得到的结果是20
Array.prototype.myReduce = function(cb,initVal){
var prev,nextIndex;
if(typeof initVal =='undefined'){
//没传的话,初始值是数组第一项,next的索引是1
prev = this[0];
nextIndex = 1;
}else{
//传了的话,初始值是传入的,next的索引是0
prev = initVal;
nextIndex = 0;
}
for(var j = nextIndex;j<this.length;j++){
prev = cb(prev,this[j],j,this)//执行结果是下一次的初始值。
}
return prev;
}
复制代码
arrow箭头函数
- this指向上一级作用域的this
- 没有arguments
var sum = function(a,b){
return a+b;
}
//如果只有返回值,没有函数题代码,则可以省略{}
var sum1 = (a,b)=>a+b;
sum1(1,2)
如果有且只有一个参数,可以省略小括号;
var double = num =>num*2
console.log(double(2))
//this问题, 箭头函数没有this,他会使用上级作用域的的this;
let obj = {
name:'zfpx',
getName(){
console.log(this.name)//this=>obj
}
}
obj.getName()
-------
let obj2 = {
name:'zfpx',
getName(){
//this=>obj
setTimeout(function () {
console.log(this.name)//this=>window, undefined
},1000)
}
}
obj2.getName()
---
let obj3 = {
name:'zfpx',
getName(){
//this=>obj
setTimeout( ()=> {
//箭头函数没有this,他会使用上级作用域的的this
console.log(this.name)//this=>obj, zfpx
},1000)
}
}
obj3.getName()
---
let obj4 = {
name:'zfpx',
getName:()=>{
console.log(this.name,11111) //this =>window, undefined
}
}
obj4.getName()
//箭头函数的this是定死的,在定义时就定死了,不管在哪里调,不管谁去调,this都是定义时的外层作用域的this
var obj5 = {
name:'zfpx',
getName:()=>{
console.log(this.name) //this =>window, undefined
}
}
var obj6 = {};
obj6.getName = obj5.getName;
obj6.getName();
复制代码