JS基础(⼆):原型与原型链、this的应⽤场景JS 基础进阶
⽂章⽬录
⼀、js基础语法
1.1 数据类型
typeof能检测哪些类型?
何时使⽤全等于,何时使⽤等于?
值类型和引⽤类型的区别?
1.1.1 es6值类型和引⽤类型
常见值类型:number、string、boolean、undefined、Symbol(‘s’)
常见引⽤类型:对象、数组、null(特殊引⽤类型,指向空指针)、函数(特殊引⽤类型 ,但不⽤于存储数据)
可通过typeof函数检测出具体的值类型和引⽤类型,
其中对象、数组和null通过typeof函数检测时只能检测出object对象,但⽆法指出具体属于哪⼀类;
值类型变量在赋值时两个变量指向不同的内存地址,进⾏的是深拷贝
引⽤类型变量在赋值时指向同⼀个内存地址,进⾏的是浅拷贝
a=1;b=a;b=2;console.log(a)//1 深拷贝
a={'name':'zhangsan','age':18}; b=a; b.age=19;console.log(a.age);//19 浅拷贝
4. 深拷贝代码:
/**
* 深拷贝
*/
const obj1 ={
age:20,
name:'xxx',
address:{
city:'beijing'
},
arr:['a','b','c']
}
const obj2 =deepClone(obj1)
obj2.address.city ='shanghai'
obj2.arr[0]='a1'
console.log(obj1.address.city)
console.log(obj1.arr[0])
/
**
* 深拷贝
* @param {Object} obj 要拷贝的对象
*/
function deepClone(obj ={}){
if(typeof obj !=='object'|| obj ==null){
// obj 是 null ,或者不是对象和数组,直接返回
return obj
}
// 初始化返回结果
let result
if(obj instanceof Array){
result =[]
}else{
result ={}
}
for(let key in obj){
// 保证 key 不是原型的属性
if(obj.hasOwnProperty(key)){
// 递归调⽤
result[key]=deepClone(obj[key])
}
}
// 返回结果
return result
}
1.1.2 let定义变量与var定义变量的区别:
let定义的变量可在各个块作⽤域中使⽤,⽽var定义的变量只能在全局作⽤域中使⽤==注意下⾯代码中变量i的作⽤域
let a
for(let i =0; i <10; i++){
a = ateElement('a')
a.innerHTML = i +'<br>'
a.addEventListener('click',function(e){
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
}
1.1.3 堆栈模型
堆栈模型:值类型⼀般在栈中存储,引⽤类型⼀般在堆中存储
1.2 Symbol ,表⽰独⼀⽆⼆的值。
Symbol 值通过Symbol函数⽣成。这就是说,对象的属性名现在可以有两种类型,⼀种是原来就有的字符串,另⼀种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独⼀⽆⼆的,可以保证不会与其他属性名产⽣冲突。
let s =Symbol()
typeof s
// "symbol"
变量s就是⼀个独⼀⽆⼆的值。typeof的结果说明s是 Symbol 数据类型。
既然是独⼀⽆⼆的,那么两个Symbol()就⼀定是不相等的:
let s1 =Symbol()
let s2 =Symbol()
console.log(s1)
console.log(s2)
console.log(s1 === s2)// false
注意
==Symbol函数前不能使⽤new命令,否则会报错。==这是因为⽣成的 Symbol 是⼀个原始类型的值,不是对象。也就是说,由于Symbol 值不是对象,所以不能添加属性。基本上,它是⼀种类似于字符串的数据类型。
Symbol函数可以接受⼀个字符串作为参数,表⽰对 Symbol 实例的描述,主要是为了在控制台显⽰,或者转为字符串时,⽐较容易区分。
1.2.1 Symbol.for()
Symbol.for() 接受⼀个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建⼀个以该字符串为名称的 Symbol 值,并将其注册到全局。
let s1 = Symbol.for('foo')
let s2 = Symbol.for('foo')
console.log(s1 === s2)// true
注意
Symbol.for()与Symbol()这两种写法,都会⽣成新的 Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。Symbol.for()不会每次调⽤就返回⼀个新的 Symbol 类型的值,⽽是会先检查给定的key是否已经存在,如果不存在才会新建⼀个值。
Symbol.keyFor()⽅法返回⼀个已登记的 Symbol 类型值的key。
const s1 =Symbol('foo')
console.log(Symbol.keyFor(s1))// undefined
const s2 = Symbol.for('foo')
console.log(Symbol.keyFor(s2))// foo
1.2.2 作为属性名
由于每⼀个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,⽤于对象的属性名,就
能保证不会出现同名的属性。这对于⼀个对象由多个模块构成的情况⾮常有⽤,能防⽌某⼀个键被不⼩⼼改写或覆盖。
⽐如在⼀个班级中,可能会有同学名字相同的情况,这时候使⽤对象来描述学⽣信息的时候,如果直接使⽤学⽣姓名作为key会有有问题。
const grade ={
张三:{
address:'xxx',
tel:'111'
},
李四:{
address:'yyy',
tel:'222'
},
李四:{
address:'zzz',
tel:'333'
},
}
console.log(grade)
// 只会保留最后⼀个李四
如果使⽤Symbol,同名的学⽣信息就不会被覆盖:
const stu1 =Symbol('李四')
const stu2 =Symbol('李四')
const grade ={
[stu1]:{
address:'yyy',
tel:'222'
},
[stu2]:{
address:'zzz',
tel:'333'
},
}
console.log(grade)
console.log(grade[stu1])
console.log(grade[stu2])
1.2.3 属性遍历
const sym =Symbol('imooc')
class User {
constructor(name){
this.name = name
this[sym]='imooc'
}
getName(){
return this.name +this[sym]
}
}
const user =new User('xiecheng')
console.Name())
for(let key in user){
console.log(key)
}
for(let key of Object.keys(user)){
console.log(key)
}
for(let key OwnPropertySymbols(user)){
console.log(key)
}
for(let key of Reflect.ownKeys(user)){
console.log(key)
}
1.2.4 消除魔术字符串
js合并两个数组魔术字符串指的是,在代码之中多次出现、与代码形成强耦合的某⼀个具体的字符串或者数值。风格良好的代码,应该尽量消除魔术字符串,改由含义清晰的变量代替。
function getArea(shape){
let area =0
switch(shape){
case'Triangle':
area =1
break
case'Circle':
area =2
break
}
return area
}
console.log(getArea('Triangle'))
上⾯代码中,字符串Triangle和Circle就是魔术字符串。它多次出现,与代码形成“强耦合”,不利于将来的修改和维护。
使⽤Symbol就可以很好的解决这个问题:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论