类的使用
严格模式
'use strict'
console.log(this); // win 这里的区域本来就是win 所以这个是win
function aa(){
console.log(this); // undefind这里的作用域不再默认是win,而是undefind,这就是严格模式,,在另一个作用域中,不默认未win
}
aa()
类的基本语法
class User{ // 声明类
constructor(name){ // 构造函数,new的时候会自动执行
this.name = name // 此处的this,一般是new出来的对象
}
getName(){
return this.name // 此处的this,一般是new出来的对象
}
}
let my = new User("大傻逼")
console.log(my.name);
console.log(my.getName());
类与原型
class User {
constructor(name){
this.nme = name // 在这里定义属性的作用就是可以让new出来的对象单独拥有他,和其他new出来互相不影响的,而下面定义的方法则是放原型中中的
}
show() { }
}
function aa() { }
console.dir(User);
console.dir(aa)
// 其实类的本质就是函数,可以看到输出的user和aa都是一样的原型结构
// 并且等于自己原型中的constructor
console.log( User === User.prototype.constructor);
// 并且在类中定义函数是自动放到类的原型当中的,也就是User.prototype
let user = new User('大傻逼')
console.dir(user);
// 结构如下图
// 通过获取对象属性,结果如下图
console.log( Object.getOwnPropertyNames(user)); // 获取new出来的对象的属性只有一个name,自己独有的
console.log( Object.getOwnPropertyNames(User.prototype)); // 获取原型中属性
class User {
name2 = '小煞笔' // 当我在这里定义属性 name2的时候,定义到的是这个类中,或者说就是这个函数当中,他是不会放到原型当中的,new出来的队形都会带有这个值
constructor(name){
this.name = name // 在这里定义属性的作用就是可以让new出来的对象单独拥有他,和其他new出来互相不影响的,而下面定义的方法则是放原型中中的
}
show() { }
changeName2(val){
this.name2 = val // 可以以this.name2 来修改name2
}
}
user.changeName2('你好呀')
console.log(user);
class定义的方法不会被遍历出来
function A(){ }
A.prototype.show(){}
let aa = new A()
for (const key in aa) {
console.log(key); // show 正常的new出来的函数对象是能够被遍历的,这就是函数属性的特征,可以使用Object.getOwnPropertyDescriptor来控制
}
// 或者在遍历的时候,使用 Object.hasOwnProperty() 查询一下有没有这个属性
// 但是在class里面定义的方法是不会别遍历的,也就是不会遍历到原型里面的方法
class类里面的是默认使用严格模式的
// 比如没有指向的this正常是指向windows,但是严格模式下就是underfind
类中的严格模式,就是除了类直接定义的construct里面的作用域,或者直接定义到类的方法,里面的this都是这个类,如果在方法内还有新开的作用域,比如函数,那么这个函数的this指的就是undefind(严格模式)
类中使用静态属性
// 使用静态属性的作用就是为了声明一些公用或者用的多的属性
class Requ{
static host = 'http://baidu.com'
api(url){
return Requ.host + `/${url}`
}
}
let obj = new Requ()
console.log(obj.api('nihao')); // 这时候就会拼接上去
直接把函数当对象去定义方法,或者使用_proto_,定义的方法就是静态方法,直接用函数去调用就好了,通过原型定义的方法就是普通方法
<script>
class User {
show(){ // 这里定义的方法是定义到prototype的,是给new出来的子代用的
console.log('prototype方法');
}
static show = function(){ // 这个静态方法是定义到__proto_的,也就是自己的原型中
console.log('static方法');
}
}
console.dir(User);
User.show() // static方法
let aa = new User()
aa.show() // prototype方法
</script>
// 需求:不适用new类的形式来调用来的构造函数
class No{
constructor(name,age){
this.name = name
this.age = age
}
static create(...args){ // 定义到_proto_
return new this(...args)
}
}
let no = No.create('小明',18)
console.log(no); // 成功输出这个对象
静态方法的小案例
let user = [
{name:'小明',age:18},
{name:'小红',age:20},
{name:'小蓝',age:50}
]
class User{
constructor(data){
this.model = data
console.log( this.model );
}
get name(){ // new出来得对象才可以使用这个方法
console.log(this.model);
return this.model.name
}
static createUser(data){ // 通过这种方法来面对对条数据要传一个类里得麻烦情况
return data.map(item=>new User(item))
}
static maxAge(data){
console.dir(this);
return data.sort((a,b)=>{
return b.age - a.age // 高到低排序
})[0]
}
static totle(data){
return data.reduce((t,c)=>{ // 总年龄
return t+c.age
},0)
}
}
// let my = User.createUser(user)
// let aaa = new User({name:'小明',age:18})
// console.log(aaa.name);
// let myage = User.maxAge(user)
// console.log();
// console.log(User.maxAge(user).name);
console.log(User.totle(user));
类中访问器的作用
class User {
constructor(url) {
this.url = url // 这里也会出发set url 访问器
}
set url(url) {
if (!/^https?:\/\//i.test(url)) {
throw new Error('傻逼')
}
this._url = url
}
}
let aa = new User('https://大傻逼')
// aa.url = 'https://傻逼是你' // 起到保护的作用
console.log(aa);
使用symbol定义protected(私有)属性
// 定义symbol属性
let pro = Symbol()
class Fa{
constructor(){
}
set host(url){
if (!/^a?:/i.test(url)) {
throw new Error('傻逼')
}
this[pro] = {}
this[pro].host = url
}
}
class AA extends Fa{
constructor(){
super()
}
}
let aa = new AA()
aa.host = 'a:大傻逼' // 通过host可以设置symbol的值,但是通过 aa[pro] 是拿不到的,因为 每次定义的 symbol都是不一样的
console.log(aa);
类的继承
其实也就是运用了原型链的继承,如果定义了静态方法,子类也是可以直接调用的
<script>
class AA {
constructor(name) {
this.name = name
}
show(){
console.log('到这');
}
}
class aa extends AA {
constructor(name) {
super(name)
}
show(){
super.show() // 调用父级的show
console.log('我是儿子');
}
}
console.dir(aa);
console.dir(AA);
let a = new aa('大撒谎比0')
a.show()
console.log(a);
</script>
看下图可以看到类的继承其实就是子类的父类_proto_变成了变成了父类的原型
看代码可以看到可以使用super调用 父类的方法
原理:
let aa = {
name:'aa',
show(){
console.log(this.name);
}
}
let bb = {
name:'bb',
__proto__:aa,
show(){
this.__proto__.show.call(this) // 调用父级的show方法,并且指向现在的this 这里输出的就是bb
console.log(this.name);
}
}
bb.show()
使用super的作用
<script>
// 由于像上面代码那里,加入再多一层父级,就会发现会循坏在后面两个子级间循环,因为把this传递过去了,里面的this都是最下级的this
// 这时候关键字super就出现了,这个关键字的作用就是在保持能够调用父级方法的同时,并且不会影响到拿到的是本身的属性,而不是父级的属性
let common = {
show() {
console.log('common.show'+this.name); // common.showbb
}
}
let aa = {
__proto__: common,
name: 'aa',
show() {
super.show() // 调用父级的show方法,并且指向现在的this 这里输出的就是bb
console.log(this.name);
}
}
let bb = {
name: 'bb',
__proto__: aa,
show() {
super.show() // 调用父级的show方法,并且指向现在的this 这里输出的就是bb
console.log(this.name);
}
}
console.log(bb);
bb.show()
</script>
为什么一定要继承的类中使用super
// 正常使用函数继承
function aa(name){
this.name = name
}
function bb(...args){
aa.call(this,...args)
}
bb.prototype = Object.create(aa.prototype)
let b = new bb('大傻逼')
// 使用类
class User{
constructor(name){
this.name = name
}
}
class Admin extends User{
// 使用继承,这时候就会默认设置
// constructor(...args){
// super(...args)
// }
// 使用super就相当于上面的 aa.call(this,...args)
// 所以如果想要自定义constructor 就必须使用super
// 并且在构造函数中必须在super后面使用this,否者会报错
}
super。父类方法 可以直接调用父类的方法
静态方法和原型对比
// 再构造函数中,其实函数也是对象,再原型链中
function User(){}
User.myname = '大撒谎比'
User.show = function(){
console.log('你说撒谎比');
}
function Admin(){}
Admin.__proto__ = User
console.dir(Admin);
// 再类中,其实再类中也是一样的道理,原理都是再原型链中
class User1{
static mynaem1 = '大傻逼'
static show(){
console.log('你呀你大傻逼');
}
}
class Admin1 extends User1{}
console.dir(Admin1); // 得到的东西一样
函数中中实现installceof原理
<script>
// a instanceof b 是检查a当前对象是否在b的原型链上
function User(){}
function Admin(){}
Admin.prototype = Object.create(User.prototype)
let ad = new Admin()
function checkinstanceof(obj,construtor){
if (!obj.__proto__) return false
if (obj.__proto__ === construtor.prototype ) return true
return checkinstanceof(obj.__proto__,construtor)
}
console.log(checkinstanceof(ad,User));
还可以使用isPrototypeOf 来检查继承
简易模块管理
let module = (function () { // 这里就是模块管理区域
let modulesList = {} // 用来保存模块
let moduleActions = [] // 用来保存模块被引用了的时候的动作
function define(name, modules, action) { // 定义模块的方法
modules.map((item,i)=>{ // 遍历引用的模块的名字
if (modulesList[item]) { // 如果这个模块存在就存起来
moduleActions[i] = modulesList[item]
}
})
modulesList[name] = action.apply(null, moduleActions) // 执行这个动作并且存到modulesList对应模块name里面
}
return { define }
})()
module.define('aa', [], function () { // 这里是一个用来被引用的模块 参数:名字,引用模块的名字数组,动作
return {
max(arr) {
return arr.sort((a, b) => b - a)[0]
}
}
})
module.define('bb',['aa','qq'],function(res){ // 去引用模块
console.log( res.max([1,3,9,8]));
})