proxy
proxy作用
对应es5的Object.defineProperty
let obj = {}
let newVal = ''
Object.defineProperty(obj,'name',{
get(){
return newVal;
},
set(val){
console.log('set');
newVal = val;
}
})
obj.name = 'es';
console.log(obj.name)
基本使用
let obj = {};
let p = new Proxy(obj,{})
p.name = 'imooc'
console.log(obj.name)
console.log(p.name)
for(let key in obj){
console.log(key)
}
for(let key in p){
console.log(key)
}
get
let arr = [7,8,9]
arr = new Proxy(arr,{
get(target,prop){
console.log('target',target)
console.log('prop',prop)
return prop in target ? target[prop] : 'error'
}
})
console.log(arr[1])
console.log(arr[10])
let dict = {
'hello':'你好',
'world':'世界'
}
dict = new Proxy(dict,{
get(target,prop){
return prop in target ? target[prop] : 'error'
}
})
console.log(dict['hello'])
console.log(dict['world11'])
set
let arr = []
arr = new Proxy(arr,{
set(target,prop,val){
if(typeof val === 'number'){
target[prop] = val;
return true;
}else{
console.log('false')
return false
}
}
})
arr.push(5)
arr.push('6')
console.log(arr[0],arr[1],arr.length)
has
let range = {
start:1,
end:5
}
range = new Proxy(range,{
has(target,prop){
return prop >= target.start && prop <= range.end
}
})
console.log(2 in range)
console.log(9 in range)
ownKeys
let obj = {
name:'imooc',
[Symbol('es')]:'es6'
}
console.log(Object.getOwnPropertyNames(obj))
console.log(Object.getOwnPropertySymbols(obj))
console.log(Object.keys(obj))
for(let key in obj){
console.log(key)
}
let userinfo = {
username:'xiecheng',
age:34,
_password:'***'
}
userinfo = new Proxy(userinfo,{
ownKeys(target){
return Object.keys(target).filter(key => !key.startsWith('_'))
}
})
for(let key in userinfo){
console.log(key)
}
console.log(Object.keys(userinfo))
proxy对象
let user = {
username:'xiecheng',
age:34,
_password:'***'
}
user = new Proxy(user,{
get(target,prop){
if(prop.startsWith('_')){
throw new Error('不可访问')
}else{
return target[prop]
}
},
set(target,prop,val){
if(prop.startsWith('_')){
throw new Error('不可访问')
}else{
target[prop] = val
return
}
},
deleteProperty(target,prop){
if(prop.startsWith('_')){
throw new Error('不可删除')
}else{
delete target[prop]
return true
}
}
})
// console.log(user.age)
// console.log(user._password)
user.age = 18
console.log(user.age)
try{
user._password = 'aa'
}catch(err){
console.log(err)
}
proxy方法
let sum = (...args) => {
let sum =0;
args.forEach(item => {
sum += item;
})
return sum;
}
sum = new Proxy(sum,{
apply(target,ctx,args){
return target(...args)*2;
}
})
console.log(sum(1,2))
console.log(sum.call(null,1,2))
console.log(sum.apply(null,[1,2]))
proxy类
let User = class{
constructor(name){
this.name = name;
}
}
User = new Proxy(User,{
construct(target,args,newTarget){
console.log('con')
return new target(...args)
}
})
console.log(new User('imooc'))
扩展运算符和rest参数
扩展运算符
把数组或者类数组展开成用逗号隔开的值
rest参数
把逗号隔开的值组合成一个数组
扩展运算符
基本操作
function foo(a,b,c){
console.log(a,b,c)
}
let arr = [1,2,3]
console.log(...arr) //1 2 3
合并数组
let arr1 = [1,2,3]
let arr2 = [4,5,6]
// Array.prototype.push.apply(arr1,arr2)
arr1.push(...arr2)
console.log(arr1) //[ 1, 2, 3, 4, 5, 6 ]
字符串合并成一个数组
let str = 'abca'
let arr = [...str]
console.log(arr) //[ 'a', 'b', 'c', 'a' ]
深拷贝
var arr1 = [1, 2, 3]
var arr2 = arr1
arr1[0] = 4;
console.log('arr1', arr1); //[4, 2, 3]
console.log('arr2', arr2); //[4, 2, 3]
var arr3 = [...arr1]
// 等同于 var arr3 = arr1.slice()
arr3[0] = 4
console.log('arr1', arr1); //[1, 2, 3]
console.log('arr3', arr3); //[4, 2, 3]
rest参数
通过arguments获取所有参数
function foo(x,y,z){
let sum = 0;
// Array.prototype.forEach.call(arguments,function(item){
// sum += item;
// })
Array.from(arguments).forEach(function(item){
sum += item;
})
return sum;
}
console.log(foo(1,2)) //3
console.log(foo(1,2,3)) //6
通过rest参数
function foo(...args){
console.log(args) //[ 1, 2 ] //[ 1, 2, 3 ]
let sum =0;
args.forEach(function(item){
sum += item;
})
return sum
}
console.log(foo(1,2)) //3
console.log(foo(1,2,3)) //6
拆分方法参数
function foo(x,...args){
console.log(x)
console.log(args)
}
foo(1,2,3,4) //[ 2, 3, 4 ]
解构赋值
let [x,...y] = [1,2,3]
console.log(x) //1
console.log(y) //[ 2, 3 ]
对象的拓展
属性简洁表示法
简写前
let name = 'aa'
let age = 14;
let obj = {
name:name,
age:age
}
console.log('obj',obj)
简写后
let name = 'aa'
let age = 14;
let obj = {
name,
age
}
属性名表达式
let s = 'school'
let obj = {
[s]:'imooc'
}
console.log('obj',obj) //{ school: 'imooc' }
对象中的方法的正确写法
错误
let obj = {
name:'aa',
study:() =>{
console.log(this.name+'在学习') //undefined在学习
}
}
obj.study()
正确
let obj = {
name:'aa',
study(){
console.log(this.name+'在学习') //aa在学习
}
}
obj.study()
Object.is
它用来比较两个值是否严格相等,与严格相等运算符(===)的行为基本一致
对比2个对象是否相等(对比的是存储的内存地址(指针))
let obj1 = { //new Object()
name :'aa',
age : 14
}
let obj2 = {//new Object()
name :'aa',
age : 14
}
// 对比的是存储的内存地址(指针)
console.log(obj1==obj2) //false
console.log(Object.is(obj1,obj2)) //false
let obj1 = { //new Object()
name :'aa',
age : 14
}
let obj2 = obj1;
console.log(obj1===obj2) //true
console.log(Object.is(obj1,obj2)) //true
扩展运算符与Object.assign()
扩展运算符
let x = {
a:3,
b:4
}
let y = {...x}
console.log(y) //{ a: 3, b: 4 }
Object.assign后面的对象会把前面的覆盖
let x = {
a:3,
b:4
}
let y = {
a:1,
c:5,
d:6
}
Object.assign(y,x)
console.log(y) //{ a: 3, c: 5, d: 6, b: 4 }
对象遍历
for...in
let obj = {
name : 'aa',
age : 14
}
for(let key in obj){
console.log(key,obj[key])
}
Object.keys
let obj = {
name : 'aa',
age : 14
}
console.log(Object.keys(obj)) //[ 'name', 'age' ]
Object.keys(obj).forEach(key => {
console.log(key,obj[key])
})
Object.values
let obj = {
name : 'aa',
age : 14
}
console.log(Object.values(obj)) //[ 'aa', 14 ]
let
let声明的全局变量不是全局对象window的属性
var a = 5;
console.log(window.a); //5
let b=5;
console.log(window.b); //undefined
用let定义变量不允许重复声明
var a = 5;
var a = 6;
console.log(a); //6
let b = 5;
let b = 6;
console.log(b); //Identifier 'b' has already been declared
let声明的变量不存在变量提升
function foo(){
console.log(a); //undefined
var a = 5;
}
foo()
function foo(){
var a;
console.log(a); //undefined
a = 5;
}
foo()
function foo(){
console.log(a); //Cannot access 'a' before initialization
let a = 5;
}
foo()
let声明的变量具有暂时性死区
var a = 5;
if(true){
a = 6;
let a;
}
// Cannot access 'a' before initialization
var a = 5;
if(true){
let a= 6;
console.log(a); //6
}
console.log(a); //5
var a = 5;
if(true){
a= 6;
console.log(a); //6
}
console.log(a);//6
let 声明的变量拥有块级作用域
es5只有全局作用域和函数作用域
{
let a = 5
}
console.log(a) // undefined
for(var i =0;i<3;i++){
console.log('内'+i);
}
console.log('外'+i);
//内0
//内1
//内2
//外3
for(let i =0;i<3;i++){
console.log('内'+i);
}
console.log('外'+i);
//内0
//内1
//内2
//Uncaught ReferenceError: i is not defined
console.log('1'+a);
if(false){
console.log('2'+a);
var a = 5;
}
console.log('3'+a);
// 1undefined
// 3undefined
一道面试题
想要打印0,1,2
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i)
})
}
//3
//3
//3
改成闭包
for (var i = 0; i < 3; i++) {
(function(j){
setTimeout(function() {
console.log(j)
})
})(i)
}
//0
//1
//2
改成let
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i)
})
}
//0
//1
//2
转成es5等同于
function _loop(i) {
setTimeout(function() {
console.log(i)
})
}
for (var i = 0; i < 3; i++) {
_loop(i)
}
//0
//1
//2
const
ES5 中定义一个常量
Object.defineProperty(window,'pi',{
value:3.14,
writable:false
})
console.log(pi); //3.14
pi = 5;
console.log(pi); //3.14
const 声明的变量必须进行初始化,并且不可被修改
const a =5;
a = 6; //Assignment to constant variable.
const a;
a = 5; // Missing initializer in const declaration
if(true){
console.log(a); // Cannot access 'a' before initialization
const a = 5;
}
const定义引用类型的数据,可以修改
const obj = {
name:'aa',
age:12
}
console.log(obj); //{name: "aa", age: 12}
obj.school = 'bb'
console.log(obj); //{name: "aa", age: 12, school: "bb"}
const arr = [1,2,3]
arr.push(4)
console.log(arr); // [1, 2, 3, 4]
Object.freeze冻结数据
Object.freeze可以冻结数据,使其不可以被修改,但是只能递归冻结
const obj = {
name:'aa',
age:12
}
Object.freeze(obj)
console.log(obj); //{name: "aa", age: 12}
obj.school = 'bb'
console.log(obj); //{name: "aa", age: 12}
只能冻结当前层
const obj = {
name:'aa',
age:12,
skill:{
name:'code',
year:11
}
}
Object.freeze(obj)
console.log(obj); //{name: "aa", age: 12}
obj.school = 'bb'
obj.skill.year = 12
console.log(obj); //year: 12
指定冻结第几层
const obj = {
name:'aa',
age:12,
skill:{
name:'code',
year:11
}
}
Object.freeze(obj)
Object.freeze(obj.skill)
console.log(obj); //{name: "aa", age: 12}
obj.school = 'bb'
obj.skill.year = 12
console.log(obj); //year: 11
解构赋值
数组解构赋值
基本
let arr = [1,2,3,4]
const [a,b,c,d] = arr;
console.log(a,b,c,d); //1 2 3 4
跳过赋值元素
let [name, , title] = ['John', 'Jim', 'Sun', 'Moon']
console.log( title ) // Sun
rest 参数
let [name1, name2, ...rest] = ["a", "b", "c", "d"]
console.log(name1) // a
console.log(name2) // b
console.log(rest[0]) // c
console.log(rest[1]) // d
console.log(rest.length) // 2
默认值
let [name = "a", surname = "b"] = ["aa"]
console.log(name) // aa (from array)
console.log(surname) // b (default used)
Set
let [a, b, c] = new Set([1, 2, 3])
console.log(a); //1
console.log(b); //2
console.log(c); //3
对象
基本操作
let obj = {
age:10,
name:'aa',
school:'imooc'
}
const {age,name,school} = obj
console.log(age,name,school); //10 "aa" "imooc"
默认值
let options = {
title: "Menu"
}
let {width = 100, height = 200, title} = options
console.log(width) // 100
console.log(height) // 200
console.log(title) // Menu
rest 参数
let options = {
title: "Menu",
height: 200,
width: 100
}
let {title, ...rest} = options
console.log(title) // Menu
console.log(rest.height) // 200
console.log(rest.width) // 100
字符串
let str = '1234'
const [a,b,c,d] = str;
console.log(a,b,c,d) //1 2 3 4
数组的各种遍历
for
支持break
let arr = [1, 2, 3]
for (let i = 0; i < arr.length; i++) {
if(arr[i] === 2){
break;
}
console.log(arr[i]) //1
}
支持continue
for (let i = 0; i < arr.length; i++) {
if(arr[i] === 2){
continue
}
console.log(arr[i]) //1 3
}
forEach不支持break,不支持continue
arr.forEach(item => {
if(arr[i] === 2){
// break; //报错
continue //报错
}
console.log('item',item);
})
map
let result = arr.map(item => {
return item +=1;
})
console.log(arr); //result
console.log(result); //[2, 3, 4]
filter
let result = arr.filter(item => {
console.log(item);
return item ==2;
})
console.log(arr); // [1, 2, 3]
console.log(result); //[2]
some
let result = arr.some(item => {
return item ==2;
})
console.log(arr); // [1, 2, 3]
console.log(result); //true
every
let result = arr.every(item => {
return item ==2;
})
console.log(arr); // [1, 2, 3]
console.log(result); //false
reduce
数组求和
let sum = arr.reduce((prev,cur,index,arr) => {
console.log('prev',prev);
console.log('cur',cur);
console.log('index',index);
console.log('arr',arr);
return prev+cur
},0)
console.log(sum);
数组求最大值
let max = arr.reduce((prev,cur) => {
console.log('prev',prev);
console.log('cur',cur);
return Math.max(prev,cur)
})
console.log(max);
// prev 1
// cur 2
// prev 2
// cur 3
数组去重
let arr = [1,2,3,2,4]
let res = arr.reduce((prev,cur) => {
console.log('prev',prev);
console.log('cur',cur);
if(prev.indexOf(cur) == -1 ){
prev.push(cur)
}
return prev
},[])
console.log(res);
// prev []
// cur 1
// prev [1]
// cur 2
// prev (2) [1, 2]
// cur 3
// prev (3) [1, 2, 3]
// cur 2
// prev (3) [1, 2, 3]
// cur 4
for in
for in 是为对象设计的,如果用于数组会调用数组原型上的方法
Array.prototype.foo = function(){
console.log('foo');
}
for (var index in arr) {
console.log(arr[index]);
}
// ƒ () {
console.log('foo');
}
for of 是为数组设计的
for(let val of [1,2,3]){
console.log(val);
}
find
找到数组中符合条件的第一个item
arr = [1,2,3,2]
let result = arr.find(item => {
return item ==2
})
console.log(arr);
console.log(result); //2 item
findIndex
找到数组中符合条件的第一个item的index
arr = [1,2,3,2]
let result = arr.findIndex(item => {
return item ==2
})
console.log(arr);
console.log(result); //1 index
数组拓展
伪数组
let divs = document.getElementsByTagName('div')
console.log(divs); //HTMLCollection []
let divs2 = document.getElementsByClassName('div')
console.log(divs2); //HTMLCollection []
let divs3 = document.querySelectorAll('.xx')
console.log(divs3); //NodeList []
console.log(divs3 instanceof Array); //false 是否是数组实例
divs3.push(123) //报错
Array.from把类数组转化为数组
let arrayLike = {
0:'a',
1:'b',
2:'c',
length:3
}
let arr = Array.from(arrayLike)
console.log(arr instanceof Array); //true
arr.push('d')
console.log(arr); //["a", "b", "c", "d"]
Array.of
创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型
new Array存在的问题,根据参数传递数量不同,而创建不一样的数组
let arr1 = new Array(1,2)
console.log(arr1); //[1, 2]
let arr2 = new Array(3)
console.log(arr2); //[empty × 3]
Array.of
let arr1s = Array.of(1,2)
console.log(arr1s); //[1, 2]
let arr2s = Array.of(3)
console.log(arr2s); //[3]
let arr3 = Array.of(1,true,'immoc',{'1':'a'})
console.log(arr3); //[1, true, "immoc", {…}]
Array.prototype.fill()
fill() 方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。
let arr1 = new Array(3).fill(7)
console.log(arr1); //[7, 7, 7]
let arr2 = [1,2,3,4,5]
arr2.fill('aa',1,3)
console.log(arr2); //[1, "aa", "aa", 4, 5]
let arr2 = [1,2,3,4,5]
arr2.fill(0)
console.log(arr2); //[0, 0, 0, 0, 0]
indexOf与includes
indexOf存在的问题
不能判断NaN
let arr = [1,2,3,NaN,undefined]
console.log(arr.indexOf(1)); //0
console.log(arr.indexOf(NaN)); //-1
console.log(arr.indexOf(undefined)); //4
includes完美解决
let arr = [1,2,3,NaN,undefined]
console.log(arr.includes(1)); //true
console.log(arr.includes(NaN)); //true
console.log(arr.includes(undefined)); //true
函数的参数
参数的默认值
es5中默认值存在的问题
function foo(x, y) {
y = y || 'world'
console.log(x, y)
}
foo('hello', 'imooc') //hello imooc
foo('hello', 0) //hello world
es6默认值解决问题
function foo(x, y = 'world') {
console.log(x, y)
}
foo('hello', 0) //hello 0
默认值要放在最后一个参数
function foo(x, y = 5,z) {
// console.log(x, y,z)
console.log('x',x); //1
console.log('y',y); //2
console.log('z',z); //undefined
}
foo(1,2)
function foo(x,z,y = 5) {
// console.log(x, y,z)
console.log('x',x); //1
console.log('y',y); //5
console.log('z',z); //2
}
foo(1,2)
解构
function foo({x,y =5}){
console.log(x,y);
}
foo({}) //undefined 5
foo({
x:1,
y:2
}) //1 2
function ajax(url,{
body='',
method='GET'
} = {}){
console.log('method',method);
}
ajax('www') //method GET
ajax('www',{
method:"POST"
}) //method POST
length
函数指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数
function foo(x,y=2,z=3){
console.log(x,y,z);
}
console.log(foo.length); //1
作用域
foo函数里能找到值,直接用
let x = 1;
function foo(x,y =x){
console.log(y);
}
foo(2)
foo函数里不能找到值,向上一层找,上一层没有函数,就到window上找
let x = 1;
function foo(y =x){
let x = 2;
console.log(y);
}
foo()
// Uncaught ReferenceError: x is not defined
function foo(y =x){
let x = 2;
console.log(y);
}
foo()
函数的name
function foo(){}
console.log(foo.name); //foo
console.log((new Function).name); //anonymous
前头函数
声明方式
函数声明
console.log(sum(4,5)); //9
function sum(x,y){
return x+y
}
console.log(sum(4,5)); //9
函数表达式
console.log(sum(4,5)); //Uncaught TypeError: sum is not a function
let sum = function(x,y){
return x+y
}
console.log(sum(4,5)); //9
前头函数简写
只有一行,并且是return
console.log(sum(4,5)); //9
let sum = (x,y) => {
return x+y
}
let sum = (x,y) => x+y
console.log(sum(4,5)); //9
this(他)
默认情况
<button id='btn'>btn</button>
let oBtn = document.querySelector('#btn')
oBtn.addEventListener('click',function(){
console.log(this); //btn
})
异步方法里调用
oBtn.addEventListener('click',function(){
console.log(this); //btn
setTimeout(function(){
console.log(this); //window
},1000)
}
bind
利用bind,把this传进来
oBtn.addEventListener('click',function(){
console.log(this);
setTimeout(function(){
console.log(this); //btn
}.bind(this),1000)
})
箭头函数
箭头函数并没有this,是从上一层函数拿的,也就是继承
oBtn.addEventListener('click',function(){
console.log(this); //btn
setTimeout(() => {
console.log(this); //btn
},1000)
})
构造函数
非箭头函数
function People(name,age){
console.log(this); //People {}
this.name = name;
this.age = age;
}
let p1 = new People('aa',10)
console.log(p1); //People {name: "aa", age: 10}
箭头函数
let People = (name,age) => {
console.log(this); //{}
this.name = name;
this.age = age;
}
let p1 = new People('aa',10)
console.log(p1); //People {}
arguments
let foo = () => {
console.log(arguments);
}
foo(1,2,3)
let foo = (...args) => {
console.log(args); //1 2 3
}
foo(1,2,3)
深拷贝
把一个对象赋值给另一个对象,修改原对象,不影响新对象
let checkType = data => {
return Object.prototype.toString.call(data).slice(8,-1)
}
let deepClone = target => {
let targetType = checkType(target)
let result;
if(targetType === 'Object'){
result = {}
}else if(targetType === 'Array'){
result = []
}else{
return target;
}
for(let i in target){
let value = target[i]
let valueType = checkType(value)
if(valueType === 'Object' || valueType === 'Array'){
result[i] = deepClone(value)
}else{
result[i] = value
}
}
return result;
}
let obj1 = {
name:'aa',
age:22
}
let obj2 = deepClone(obj1)
obj2.name = 'bb'
console.log(obj1);
console.log(obj2);