目录
类
继承
ES5 如何继承
ES6继承
Symbol
用途
可以产生唯一的值,独一无二的值
解决命名冲突
getOwnPropertySymbols()
作为全局注册表 缓存 Symbol.for()
消除魔术字符串
模版字符串
在javascript语言中,生成实例对象使用构造函数;ES6提供了类Class这个概念,作为对象的模板。定义一个类通过class关键字,ES6的类可以看成是构造函数的另一种写法。
class Person{
constructor(name,age,gender){
// 类构造器中属性和方法是实例私有属性和私有方法
this.name = name;
this.age = age;
this.gender = gender;
}
// 实例公共方法 类似于存放在Person类原型对象中
sayName(){
console.log(this.name);
}
test = 'hello'; //实例公共属性
friends = []; //实例私有属性
// 类静态属性和静态方法
static personAttr = '类的静态属性';
static personMethod = function(){
console.log('类静态方法this指向类本身');
console.log(this,this.personAttr,this.test,this.friends);
}
}
let p1 = new Person('可乐',12,'male');
let p2 = new Person();
console.log(p1.test,p2.test);
console.log(p1.test === p2.test);
p1.friends.push('tom');
console.log(p1.friends,p2.friends);
console.log(p1.friends === p2.friends);
Person.personMethod();
实例使用属性和方法
1.从实例对象本身查找属性或者方法
2.如果实例没有,从构造函数的原型对象中找
3.如果还没有,从父构造函数的原型对象中找
/**
* es5 继承
* 经典继承 原型链继承
*/
// function Animal(name,age,length,weight){
// this.name = name;
// this.age = age;
// this.length = length;
// this.weight = weight;
// }
// Animal.prototype = {
// constructor:Animal,
// sayType(){
// console.log(this.type)
// }
// }
// function Dog(name,age,length,weight,type){
// // 继承父构造函数属性 借用构造函数继承 经典继承
// Animal.call(this,name,age,length,weight);
// this.type = type;
// }
// // 原型链继承 子类得原型对象指向父类得实例
// Dog.prototype = new Animal();
// Dog.prototype.constructor = Dog;
// let d1 = new Dog('可乐',12,'40cm','10kg','狗');
// d1.sayType();
// console.log(d1);
更详细的ES5继承见面向对象之创建对象模式和继承模式_学前端的狗头苏丹的博客-CSDN博客
class可以通过extends关键字实现继承,子类可以没有构造函数,系统会默认分配。子类提供了构造函数则必须要显式调用super。super函数类似于借用构造函数。类似于Animal.call()
1.子类对象指向父类对象
2.子类原型对象继承父类原型对象
/**
* ES6继承 使用extends关键字实现继承
*/
class Animal{
// 构造器属性 实例私有属性
constructor(name,age,length){
this.name = name;
this.age = age;
this.length = length;
}
// 类体方法 实例公共方法 存放在Animal.prototype中
sayName(){
console.log(this.name);
}
test = 'hello';
friends = [];
// 静态属性和静态方法
static ParentAttr = '父类属性';
static ParentMethod = function(a){
console.log('父类的方法');
return a instanceof Animal;
}
}
// 子类继承父类 不提供constructor的情况
class Dog extends Animal{
}
let d1 = new Dog('可乐',12,'50cm');
console.log(d1);
d1.sayName();
d1.friends.push('tom')
console.log(d1.test,d1.friends,d1);
console.log(Dog.ParentAttr);
console.log(Dog.ParentMethod(d1));
// 子类继承自父类
console.log(Dog.__proto__ === Animal);
// 子类原型对象继承自父类的原型对象
console.log(Dog.prototype.__proto__ === Animal.prototype);
// 子类如果提供了构造器 必须显示调用super
// class Dog2 extends Animal{
// constructor(name,age,weight,type,color){
// super(name,age,weight); //相当于调用父类构造器 Animal.call()
// this.type = type;
// this.color = color;
// }
// sayName(){
// console.log(this.name,'子类实例公共方法');
// }
// }
// let d2 = new Dog2('可乐',12,'50cm','狗','黑色');
// console.log(d2);
// d2.sayName();
ES6引入的一种新的原始数据类型Symbol,表示独一无二的值。Symbol函数可以接受参数,表示对于这个唯一值的描述。属于基本数据类型,Symbol()函数会返回symbol类型的值
参数:字符串 表示对这个symbol值的描述
let sy1 = Symbol();
let sy2 = Symbol();
console.log(sy1,sy2,sy1 === sy2,sy1.toString());
let a = new Number();
let b = new String();
console.log(a,b);
let sy3 = Symbol('name'); //接收的字符串 对symbol的描述
let sy4 = Symbol('age');
let obj = {
name:'zhangsan',
age:12,
[sy3]:'terry',
[sy4]:18,
[Symbol('email')]:"[email protected]"
}
console.log(obj);
for(let key in obj){
console.log(key);
}
从上图输出结果来看:我们可以发现for in循环无法遍历到symbol值作为属性名对应的属性,我们想要获取所有的symbol值对应的属性,,则需要使用getOwnPropertySymbols()方法
/**
* 获取所有的symbol值对应的属性
* getOwnPropertySymbols
*/
console.log(Object.getOwnPropertySymbols(obj));
let s = Object.getOwnPropertySymbols(obj); //[ Symbol(name), Symbol(age), Symbol(email) ]
console.log(obj[s[2]]);
全局注册表
Symbol() 不同的是,用 Symbol.for() 方法创建的的 symbol 会被放入一个全局 symbol 注册表中。Symbol.for() 并不是每次都会创建一个新的 symbol,它会首先检查给定的 key 是否已经在注册表中了。假如是,则会直接返回上次存储的那个。否则,它会再新建一个。
/**
* 3.作为全局注册表 缓存 Symbol.for()
*/
// 将symbol放到全局注册表中
let sy5 = Symbol.for('hello');
let sy6 = Symbol.for('hello');
console.log(sy5 === sy6); //true
// 每次都会创建一个不同symbol值 虽然描述符一样 但是Symbol value值不一样
let sy7 = Symbol('hello');
let sy8 = Symbol('hello');
console.log(sy7 === sy8); //false
// Symbol.keyFor()可以检测symbol值是否在全局注册表中注册过。 返回对于symbol的描述或者undefined
console.log(Symbol.keyFor(sy5));
console.log(Symbol.keyFor(sy6));
console.log(Symbol.keyFor(sy7));
Symbol.keyFor()可以检测symbol值是否在全局注册表中注册过。 返回对于symbol的描述或者undefined
魔术字符串指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。
/** * 4.消除魔术字符串 */ function getArea(shape,options){ let area = 0; switch(shape){ case Shape.SJX: area = .5 * options.height * options.width; break; case Shape.ZFX: area = options.height * options.width; break; case Shape.CIRCLE: area = Math.PI * options.r * options.r; break; default: area = -1; } return area; } const Shape = { SJX:Symbol('三角形'), ZFX:Symbol('正方形'), CIRCLE:Symbol('圆'), } let res = getArea(Shape.SJX,{height:100,width:100,r:50}) console.log(res); Shape.SJX = Symbol('六边形'); console.log(Shape);
模板字面量是用反引号(
`
)分隔的字面量,允许多行字符串、带嵌入表达式的字符串插值和一种叫带标签的模板的特殊结构。模板字面量有时被非正式地叫作模板字符串,因为它们最常被用作字符串插值(通过替换占位符来创建字符串)。然而,带标签的模板字面量可能不会产生字符串——它可以与自定义标签函数一起使用,来对模板字面量的不同部分执行任何操作。
/**
* 模版字符串 可以解析变量
*/
let name = 'zhangsan';
let age = 12;
// let str = 'name' + 'age';
let str = `${name}+${age}`
console.log(str);
let id = 1;
let url = `121.199.0.35:8888/findById?id=${id}`;
console.log(url);