复杂数据类型
引用类型的值是保存在内存中的对象。
当一个变量是一个对象时,实际上变量中保存的并不是对象本身,而是对象的引用
当从一个变量向另一个变量复制引用类型的值时,会将对象的引用复制到变量中,并不是创建一个新的对象
这时,两个变量指向的是同一个对象。因此,改变其中一个变量会影响另一个。
对象(Object)
数组和函数都属于对象
定义
- 多个数据(属性)的集合
- 用来保存多个数据(属性)的容器
组成
- 属性名 : 字符串(标识)
- 属性值 : 任意类型
创建对象方式
//第一种
var person = new Object();
person.name = "孙悟空";
person.age = 18;
//第二种
var person = {
name:"孙悟空",
age:18
}
简写方式
当键名和键值(是一个变量),是相同的名字时就可以采用对象的简写形式
var name='zs'
var age=18
var obj={
name,
age
}
取值方式
var obj={
name:'熏悟空',
age:500
}
//对象名.属性名
obj.name //'熏悟空'
//对象名[属性名] 属性名有特殊字符/属性名是一个变量
obj[name]//'熏悟空'
方法
遍历
forin
:会遍历对象中所有的可枚举属性(包括自有属性和继承属性)
var obj={
name:'熏悟空'
age:18
}
for (var key in obj){
console.log(key)//name ,age
}
Object.keys(obj)
: 会返回一个包括所有的可枚举的自有属性的名称组成的数组
var obj={
name:'熏悟空'
age:18
}
Object.keys(obj)//['name','age']
Object.getOwnPropertyNames(obj)
会返回自有属性的名称 (不管是不是可枚举的)
var arr = ["a", "b", "c"];
Object.getOwnPropertyNames(arr)// ["0", "1", "2", "length"]
Object.getOwnPropertySymbols(obj)
返回一个数组,包含对象自身的所有 Symbol 属性的键名
var a = Symbol('a');
var b = Symbol('b');
var obj = {};
obj[a] = 1;
obj[b] = 2;
Object.getOwnPropertySymbols(obj); // [Symbol(a), Symbol(b)]
Reflect.ownKeys(obj)
返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举
Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 })// ['2', '10', 'b', 'a', Symbol()]
以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则
首先遍历所有数值键,按照数值升序排列
其次遍历所有字符串键,按照加入时间升序排列
最后遍历所有 Symbol 键,按照加入时间升序排列
判断
Object.is(value1,value2)
用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致
Object.is('foo', 'foo')// true
Object.is({}, {})// false
不同之处只有两个:一是+0不等于-0,二是NaN等于自身
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
合并
Object.assign()
方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)属于浅拷贝
var target = { a: 1 };
var source1 = { b: 2 };
var source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
获取键值
Object.values()
方法返回一个数组,数组的子项是键值
var obj = { foo: 'bar', baz: 42 };
Object.values(obj)// ["bar", 42]
会过滤属性名为 Symbol 值的属性
Object.values({ [Symbol()]: 123, foo: 'abc' });// ['abc']
参数是一个字符串,会返回各个字符组成的一个数组
Object.values('foo')// ['f', 'o', 'o']
数值和布尔值的包装对象,都不会为实例添加非继承的属性。所以,Object.values会返回空数组
Object.values(42) // []
Object.values(true) // []
Object.entries()
方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组
const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)// [ ["foo", "bar"], ["baz", 42] ]
判断对象是否含有该属性
Object.hasOwn()
可以接受两个参数,第一个是所要判断的对象,第二个是属性名,返回布尔值
var foo = { a: 123 };
foo.b = 456;
Object.hasOwn(foo, 'a') // false
Object.hasOwn(foo, 'b') // true
Object. hasOwnProperty()
接受一个参数,参数是属性名,返回布尔值
var obj={
name:'熏悟空'
}
obj. hasOwnProperty('name')//true
obj. hasOwnProperty('age')//false
数组(Array)
什么是数组
数组是一种用于表达有顺序关系的值的集合的语言结构
创建
//第一种 字面量
var arr=[1,2,3]
//第二种
var arr2=new Array(n)//只有一个参数或者没有参数得到的是一个长度为n的数组
数组的方法
forEach()
数组专有的遍历方法 arr.forEach(function(val,index,arr){}) 没有返回值 会改变原始的数组的值,允许callback更改原始数组的元素
fill(val,start,end)
数组的填充 将数组内的项替换成val start 起始下标end 结束下标
reverse()
数组的翻转
sort(a,b)
数组的排序 a - b 从小到大b - a 从大到小
push(val)
数组的尾部添加
unshift(val)
数组的头部添加
pop()
数组的尾部删除
shift()
数组的头部删除
splice(start,length,val)
start切割数组的起始下标;length切割的长度; val添加的子项;返回新数组
concat(arr1,arr2,....,arrn)
数组的拼接,组成新的数组
var a=[1,2]
var b=[3,4]
concat(a,b)//[1,2,3,4]
filter(function(val,index,arr){})
数组的过滤,寻找满足条件的子项,组成新的数组
var arr=[1,2,3,4,5]
//第一个参数表示子项,第二个参数表示下标 第三个参数表示原数组
arr.filter(function(item,index){
return item%2==0
}) // [2, 4]
find(function(val,index,arr){})
数组的查找,查找符合条件的第一个子项
var arr=[1,2,3,4]
arr.find(function(item,index){
return item%2==0
})//2
findIndex(function(val,index,arr){})
查找第一个符合条件的子项的下标
var arr=[1,2,3,4]
arr.findIndex(function(item,index){
return item%2==0
})//1
includes()
数组是否包含子项 返回布尔
var arr=[1,2,3,4]
arr.includes(4)//true
indexOf()
通过指定的子项,返回下标;找不到返回 -1,从0开始
var arr=[1,3,4,5]
arr.indexOf(1)//0
arr.indexOf(6)..-1
isArray()
判断是否为数组,返回bol值
var arr=[1,3,4]
Array.isArray(arr)//true
var arr1='12312'
Array.isArray(arr1)//false
join(str)
将数组通过连接符转成字符串,str为连接符
var arr=[1,2,3]
arr.join('')//'123'
map(function(val,index,arr){})
映射当前数组里的每一个子项,返回一个新的数组 有返回值 原本的数组不受到影响,更快,会分配内存空间存储新数组并返回
var arr=[1,2,3]
arr.map(function(item,index){
console.log(item,index)
//1 0
//2 1
//3 2
})
slice(start,end)
start为起始下标,end为终点下标
Array.from()
方法用于将两类对象转为真正的数组
var arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5 的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6 的写法
var arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
Array.of()
方法用于将一组值,转换为数组
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
函数(Function)
函数是由一连串的子程序(语句的集合)所组成的,可以被外部程序调用。向函数传递参数之后,数可以返回一定的值。
通常情况下,JavaScript 代码是自上而下执行的,不过函数体内部的代码则不是这样。如果只是对函数进行了声明,其中的代码并不会执行。只有在调用函数时才会执行函数体内部的代码。
这里要注意的是JavaScript中的函数也是一个对象。
声明
//第一种 变量
var sum = function(a,b){return a+b};
//第二种 关键字 通过function关键字
function sum(a,b){return a+b}
调用
var result = sum(123,456)
传递参数
JS中的所有的参数传递都是按值传递的。也就是说把函数外部的值赋值给函数内部的参数,就和把值从一个变量赋值给另一个变量是一样的
内部属性
在函数内部,有两个特殊的对象:
arguments
• 该对象实际上是一个数组,用于保存函数的参数。
• 同时该对象还有一个属性callee来表示当前函数。
this
• this 引用的是一个对象。对于最外层代码与函数内部的情况,其引用目标是不同的。
• 此外,即使在函数内部,根据函数调用方式的不同,引用对象也会有所不同。需要注意的是,this 引用会根据代码的上下文语境自动改变其引用对象
构造函数
构造函数是用于生成对象的函数,像之前调用的
Object()
就是一个构造函数
创建一个构造函数
为了区分构造函数与普通函数的区别,通常采用大驼峰命名法
function MyClass(x,y) {
this.x = x;
this.y = y;
}
调用构造函数
构造函数本身和普通的函数声明形式相同。
构造函数通过 new 关键字来调用,new 关键字会新创建一个对象并返回。
通过 new关键字调用的构造函数内的 this 引用引用了(被新生成的)对象。
var myClass=new MyClass(1,2)
myClass.x//1
es5之前的参数不能设置默认值,es6增加了函数的参数可以设置一个默认值
箭头函数
ES6 允许使用“箭头”(=>)
定义函数
var f = v => v;
// 等同于
var f = function (v) {
return v;
};
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
注意点
(1)箭头函数没有自己的this对象。this指向也不能改变
(2)不可以当作构造函数,也就是说,不可以对箭头函数使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest参数代替。
rest 参数 形式为...变量名
,用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数(后面会讲到)
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 42
Generator 函数
Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
Generator 函数是一个普通函数,但是有两个特征。
一是,function关键字与函数名之间有一个星号
二是,函数体内部使用yield表达式,定义不同的内状态
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
Generator
函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用 Generator
函数后,该函数并不执行,返回的也不是函数运行结果,而是一个对象
yield
相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next
方法,执行一段代码
helloWorldGenerator.next()//{value:'hello',done:false}
helloWorldGenerator.next()//{value:'world',done:false}
helloWorldGenerator.next()//{value:'ending',done:true}