创建对象
对象的创建方法有很多:
// 1. 对象字面量
var boj = {
name: 'www',
age: 19
}
// 2. new Object+动态添加属性
var obj2 = newObject()
obj2.name = 'www'
// 3. new 其它类
function Person() {}
var obj3 = new Person()
对象的常见操作:
var info = {
name: 'ww',
age: 19,
frend: {
age: 16
},
running: function () {
console.log('running');
}
}
// 访问对象中的属性
console.log(info.name);
console.log(info.frend.age);
// 修改对象中的属性
info.age = 20
info.running = function () {
alert('我修改了')
}
// 添加对象中的属性
info.height = 1.66
// 删除对象中的属性
delete info.age
方括号的使用
var obj = {
name: 'ww',
'my friend':'qq',
'eating':function () {
console.log('eating');
}
}
console.log(obj["my friend"]);
var eatKey = 'eating'
obj[eatKey]()
对象的遍历
Object.keys()方法会返回一个由一个给定对象的自身可枚举属性组成的数组
var info = {
name: 'www',
age: 19,
height: 1.66
}
// for遍历
var infoKey = Object.keys(info) // ['name','age','height']
for (var i = 0; i < infoKey.length; i++) {
var key = infoKey[i] // name age height
var value = info[key] // www 19 1.66
}
// for...in可以遍历对象
for (var key in info){
var value = info[key] // www 19 1.66
console.log(value)
}
// for...of默认是不支持遍历对象
栈内存和堆内存
程序是需要加载到内存中来执行的,我们可以将内存划分为两个区域:栈内存和堆内存。
- 原始类型占据的空间是在栈内存中分配的,在变量中保存的是值本身
- 对象类型占据的空间是在堆内存中分配的,在变量中保存的是对象的“引用”
var name = 'www' //栈内存
var obj = {} // 堆内存
var foo = function() {} // 堆内存
function bar() {} // 堆内存
函数中的this
// 函数中有一个this的变量,this大多数情况下会指向一个对象
function foo(name, age) {
console.log(arguments) // 保存的是传入的所有参数
console.log(this) // 默认指向window
}
foo()
// 如果一个函数被某个对象引用并调用,那么this指向这个对象
var obj = {
name: 'www',
running: function() {
console.log(this)
}
}
obj.running() // this指向obj
// 题目:
function bar() {
console.log(this) // 指向obj对象
}
var obj = {
name:'www',
bar:bar
}
obj.bar()
类和对象
工厂函数: 创建对象可以封装一个函数,这个函数用于帮助创建一个对象,只需要重复调用这个函数
// 工厂函数其实是一种常见的设计模式
function createStudent(name, age) {
var stu = {}
stu.name = name
stu.age = age
return stu
}
createStudent('www',18)
createStudent('qq',19)
构造函数: 也称之为构造器(constructor),通常是我们在创建对象时会调用的函数
如果一个函数被使用new操作符调用了,那么它会执行如下操作:
- 在内存中创建一个新的空对象
- 这个对象内部的[[prototype]]属性会被赋值为该构造函数的prototype属性
- 让this指向这个空对象
- 执行函数的内部代码
- 如果构造函数没有返回非空对象,那么this指向的对象会自动返回
// 构造函数扮演了其他语言中类的角色
function Student(name, age) {
this.name = name
this.age = age
}
var stu1 = new Student('www',18)
var stu2 = new Student('qq',19)
function baz() {}
// 构造函数上添加的函数,称之为类方法
baz.running = function() {}
baz.running()
类和对象的关系:
全局对象:window
// 浏览器中存在一个全局对象:window
console.log(window)
// 作用一:查找变量时,最终会找到 window 上
// 作用二:将一些浏览器全局提供给我们的变量|函数|对象,放在 window 对象上面
// 作用三(了解):使用 var 定义的变量会被默认添加到 window 上
console.log(window.console === console) // ture
函数也是一个对象类型
常见内置类
调用一个原始类型的属性或者方法时,会进行如下操作:
- 根据原始值,创建一个原始类型对应的包装类型对象
- 调用对应的属性或者方法,返回一个新的值
- 创建的包装类对象被销毁
- 通常JS引擎会进行很多的优化,可以跳过创建包装类的过程在内部直接完成属性的获取或方法调用
注意:null、undefined没有任何的方法,也没有对应的“对象包装类”
在调用原始类型的属性或者方法时,内部的操作 num = new Number(num)
var num = 12.2222
console.log(num.toFixed(2))
Number类型
Number.MAX_SAFE_INTEGER:最大的安全整数 Number.MAX_VALUE:最大的正数
Number.MIN_SAFE_INTEGER:最小的安全整数 Number.MIN_VALUE:最小的正数
- 实例方法(通过具体的对象来调用):
var num = 1.234112
// 方法一:toString(base),将数字转成字符串,并且按照base进制进行转化
console.log(typeof num.toString()) // string
// 可以传入值的范围2-36,默认是10
console.log(num.toString(2)) // 转二进制
console.log(num.toString(8)) // 转八进制
console.log(123..toString()) // 对数字进行转换使用..
// 方法二:toFixed(digits),格式化一个数字,保留digits位的小数
var pi = 3.1415926
console.log(pi.toFixed(2)) // 返回的是String类型
- 类方法(通过类名来调用):
var num1 = '123.99'
console.log(Number(num1)) // 将字符串转为数字
console.log(Number.parseInt(num1)) // 将字符串解析成整数
console.log(Number.parseFloat(num1)) // 将字符串解析成浮点数
// 这两种方法在window对象上面
console.log(parseInt(num1)) // 转整数
console.log(parseFloat(num1)) // 转浮点数
更多Number方法,可以查看MDN文档:
developer.mozilla.org/zh-CN/docs/…
Math对象
Math是一个内置对象(不是一个构造函数),它拥有一些数学常数属性和数学函数方法
var num = 12.44
console.log(Math.floor(num)) // 12 向下舍入取整
console.log(Math.ceil(num)) // 13 向上舍入取整
console.log(Math.round(num)) // 12 四舍五入取整
console.log(Math.random()) // 生成0~1的随机数(包含0,不包含1)
console.log(Math.pow(2, 3)) // 2的3次方
console.log(Math.floor(Math.random() * 45 + 5)) // 随即生成5-45的整数
String类
查看MDN的文档:
developer.mozilla.org/zh-CN/docs/…
var str = 'hello www'
console.log(str.length) // 获取字符串的长度
// 访问某一个位置对应的字符
console.log(str[4]) // 下标为4的字符 o 没有找到会返回undefined
console.log(str.charAt((4))) // 下标为4的字符 o 没有找到会返回空字符串
// 修改字符串(字符串在定义后是不可以修改的)
console.log(str[2] = 'Q') // hello www
console.log(str) // hello www
// 将所有的字符转成大写
var str1 = str.toUpperCase() // hello www 生成一个新的字符串,原来的字符串没有被修改
// 将所有的字符转成小写
var str2 = str.toLowerCase() // HELLO WWW
支持 for...of 的遍历(默认对象不支持) 内部将str字符串变成了一个可迭代对象
for (var char of str) {
console.log(char)
}
// 判断一个字符串中是否有另一个字符串
// indexOf(要搜索的字符串,从哪儿开始搜索) 返回字符串所在位置的索引,没有则返回-1
var message = 'hello wqq'
var name = 'wqq'
console.log(message.indexOf(name)) // 6
if (message.indexOf(name) !== -1) {
console.log('message中包含name')
} else {
console.log('message中不包含name')
}
// 是否包含字符串(es6语法),返回true或false
if (message.includes(name)) {
console.log('message中包含name')
}
// 是否以xxx开头
if (message.startsWith('h')) {}
// 是否以xxx结尾
if (message.endsWith('qq')) {}
// 替换字符串
var str3 = 'hello www'
var newName = 'wqq'
var newStr = str.replace('www','qqq') // hello qqq
var fnNewStr = str.replace('www',function() {
return newName.toUpperCase()
}) // hello WQQ
slice()方法不会修改原数组,会返回一个新数组
// 获取子字符串
var str4 = 'hello word'
console.log(str4.slice(3,7)) // lo w
console.log(str4.slice(3,-1)) // lo wor
console.log(str4.slice(3)) // lo word
console.log(str4.substr(3,6)) // lo wor
// 字符串的拼接
var s1 = 'hello'
var s2 = 'www'
var s3 = 'qqq'
var newS1 = s1 + s2 + s3
var newS2 = s1.concat(s2).concat(s3)
var newS3 = s1.concat(s2,s3,'aaa')
// 删除首位空格
console.log(' www'.trim())
// 字符串的切割
var str5 = 'a-b-c'
var newStr5 = str5.split('-') // ['a', 'b', 'c']
newStr5.join('*') // a*b*c
Array数组
- push/pop 方法运行的比较快,而 shift/unshift 比较慢
// 创建数组
var arr = ['a', 'b', 'c']
// 访问数组中的元素
var a = arr[0] // a
var b = arr.at(-1) // c
// 修改数组中的元素
arr[0] = 'www' // arr = ['www','b','c']
// 从最后新增元素
arr.push('在数组最后新增数据','多个数据')
// 删除最后一个元素(只能删一个)
arr.pop()
// 从开头新增元素
arr.unshift('在开头新增')
// 从开头删除元素
arr.shift()
- 在中间某个位置添加或者删除元素,
这个方法会修改原数组
var arr = ['a', 'b', 'c','d']
// 参数一:从什么位置开始操作元素
// 参数二:删除元素的个数
arr .splice(1,2)
// 新增元素
arr.splice(1,0,'新增元素','多个新增')
// 替换元素
arr.splice(1,2,'替换元素')
- length属性
var arr = ['a', 'b', 'c','d']
var len = arr.length // 4
// length属性是可写的,清空数组赋值为 0
arr.length = 7 // 会自动对数字进行扩容,没有数据则会赋值 empty ['a', 'b', 'c', 'd', empty × 3]
arr.length = 2 // 会截取后面的值 ['a','b']
数组的遍历
var arr = ['a', 'b', 'c','d']
// for遍历
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]) // a b c d
}
// for...in遍历
for (var index in arr) {
console.log(index) // 0 1 2 3
console.log(arr[index]) // a b c d
}
// for... of遍历
for (var item of arr) {
console.log(item) // a b c d
}
数组方法
var arr = ['a', 'b', 'c', 'd']
// indexOf():果找到返回对应的索引,没有找到返回-1
console.log(arr.indexOf('c'))
// includes():判断数组是否包含某个元素,返回一个布尔值
console.log(arr.includes('b'))
// find 和 findIndex 直接查找元素或者元素的索引(es6新增语法)
var products = [
{ name: '西瓜', price: 12 },
{ name: '苹果', price: 12 }
]
console.log(products.find(item => item.name === '西瓜')) // {name: '西瓜', price: 12}
console.log(products.findIndex(item => item.name === '苹果')) // 1
数组排序
sort()也是一个高阶函数,会生成一个排序后的新数组
reverse()将数组中元素的位置颠倒,并返回该数组
var nums = [911,32,34,12,56]
// 传入俩参数:谁小谁排在前面
var newNums = nums.sort(function(item1,item2) {
return item1 - item2 // [12, 32, 34, 56, 911]
return item2 - item1 // [911, 56, 34, 32, 12]
})
var newNums2 = nums.reverse() // [911, 56, 34, 32, 12]
var products = [
{id:1, name: '西瓜', price: 12 },
{id:2, name: '苹果', price: 32 },
{id:3, name: '芒果', price: 64 }
]
var newProducts = products.sort((a,b) => a.price -b.price)
其他高阶方法
forEach() 遍历数组,并且让数组中每一个元素都执行一次对应的方法
map() 创建一个新数组, 这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成
filter() 创建一个新数组, 新数组中只包含每个元素调用函数返回为true的元素
reduce() 用于计算数组中所有元素的总和
手动实现wqforEach函数
var arr = ['a', 'b', 'c','d']
// 版本一:
function wqForEach(fn) {
for (var i = 0; i < arr.length; i++) {
fn(arr[i],i,arr)
}
}
wqForEach(function(item,index,arr) {
console.log('------',item,index,arr)
})
// 版本二:
function wqForEach(fn,arr) {
for (var i = 0; i < arr.length; i++) {
fn(arr[i],i,arr)
}
}
wqForEach(function(item,index,arr) {
console.log('------',item,index,arr)
},arr)
wqForEach(function(item,index,arr) {
console.log('------',item,index,arr)
},[11,22,33])
// 版本三
arr.wqForEach = function (fn) {
for (var i = 0; i < this.length; i++) {
fn(this[i],i,this)
}
}
arr.wqForEach(function(item,index,arr) {
console.log('------',item,index,arr)
})
// 最终版本
Array.prototype.wqForEach = function (fn) {
for (var i = 0; i < this.length; i++) {
fn(this[i],i,this)
}
}
var products = [
{ name: '西瓜', price: 12 },
{ name: '苹果', price: 12 }
]
products.wqForEach(function(item,index,arr) {
console.log('------',item,index,arr)
})
手动实现wqFind函数
var products = [
{ name: '西瓜', price: 12 },
{ name: '苹果', price: 12 }
]
Array.prototype.wqFind = function(fn) {
for (var i = 0; i < this.length; i++) {
var isFlag = fn(this[i], i, this)
if (isFlag) return this[i]
}
}
var wqFind = products.wqFind(function(item, index, arr) {
return item.name === '西瓜'
}) // {name: '西瓜', price: 12}
创建Date对象
// 创建Date对象
var date1 = new Date() // Wed Mar 01 2023 11:31:06 GMT+0800 (中国标准时间
var date2 = new Date('2023-03-01') // Wed Mar 01 2023 08:00:00 GMT+0800 (中国标准时间)
// 将date对象转成时间戳
date1.getTime()
date1.valueOf()
Date.now()
// 计算这个操作所花的时间
var startTime = Date.now()
for (var i = 0; i < 1000; i++){
console.log(i)
}
var endTime = Date.now()
console.log('所花的时间:' , endTime - startTime)
Date.parse(str) 方法可以从一个字符串中读取日期