原型 以及 类(class)

原型 以及 类(class)

函数的 prototype

**    实例对象.prototype  查看原型   及原型的属性方法**

普通对象的 proto , ie 安全级别高,不支持

区别:

函数的 prototype,父亲改自己的基因。有生育能力,但是可以不生。

对象的proto,孩子找父亲,一层一层往上找,越到上面越抽象

原型链:本质proto

hasOwnProperty(类似  in –**‘属性名’ in  对象**) 判断自己身上是否有那个属性,原型链中继承来的不算

console.log(p1.hasOwnProperty(‘name’));

console.log(Object.hasOwnProperty(‘name’));

检测对象有没有某个属性

下面两种包含从原型链上继承下来的

obj.属性  undefined

属性  in obj

只有自己构造函数中有的

obj.hasOwnProperty(属性名)

======

**伪数组和数组的区别  **

伪数组无法调用真数组的方法。

伪数组的原型(_proto_)的 construction(父-构造函数)是  HTMLCollection();<HTML  元素的集合>

而真数组的原型的  construction  是 Array();


**类****(class,本质就是 function 的语法糖)**

OCP 开闭原则, 对扩展开放,对修改关闭。

尽量不要修改类,而是通过继承去扩展类

  • 类中的构造器不是必须写的,要对实例进行一些初始化操作,如添加指定属性时才写。
  • 如果 A 类继承了 B 类,且 A 类中写了构造器,那么 A 类构造器中的 super()是必须要调用的
  • 类中所定义的方法,都是放在类的原型对象上,供实例使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
//创建一个Person类
class Person{
//构造器方法
// 对象创建时,就会调用该构造函数
constructor(name,age){
// 一般实例化一个class 需要传入参数, 才使用constructor。或一些实例后就需要执行的方法。就是初始化一个实例
//构造器中的this指向 类的实例对象
//就是把类构造器的参数赋给实例的参数
this.name = name,
this.age = age,
/* 写死不需要传参数。该类的boss属性就是 bzj */
this.boos='bzj'
// super() 是执行 父类的 constructor,可以传递参数,也可以不传、
但是不传参数就代表执行 父类整个 constructor。
//ts中: 子类的构造函数中,必须在调用 super(父类的属性) 把父类的构造方法也执行了,不然继承无效。类似java的写法了。
// super.父类得方法/属性 => 使用super可以调用父类得方法和属性 ==> Parent.prototype.constructor.call(this)
// 可以传递 子类的参数 给父类的 constructor 执行
super()
}
//创建一般方法
speak(){
// speak方法放在了 类的原型对象上。供实例使用。
// 如果通过Person实例调用speak时,
// speak中的this就是Person实例
console.log(`我是${this.name},年龄是${this.age}`);
}
}
// 创建一个Person的实例对象
const p1 = new Person('tom',19);
console.log(p1);

/* 创建一个Student子类,继承Person类
子类就可以使用父类的属性和方法*/
class Student extends Person{
constructor(name,age,grade){
/* 子类写了构造器方法,必须用super()继承,不然就报错 */
/* 且super必须写在最前面 */
super(name,age),
this.grade=grade
}

// 重写从父类继承过来的方法
speak(){
console.log(`年级是${this.grade}`);
}

// 子类自己的方法
study(){
console.log('我非常努力的学习');
}
}

/* 创建Student类的实例对象 */
const s1 = new Student('zhangsna',19,'高二')
console.log(s1);
/* 重写了父类方法的话就使用自己的重写后的方法 */
/* 没有重写就直接使用 继承于父类的方法 */
s1.speak()
s1.study()

>> Class 的静态方法/属性

  • 就是类本身的属性和方法 使用 static关键字定义
  • 调用是使用类本身来调用
  • 而未用 static关键字定义的属性 方法 都是实例上的属性方法
  • static 修饰的方法中的 this 指向类本身 并非实例。所有 static 方法中可以调用其他静态属性或方法

>> get / set

  • get 或 set 定义的看起来是 方法,**实际上是属性**,可以理解为 vue 中的计算属性,计算属性本质就是 get
  • 调用不加小括号, 因为是属性
  • get 定义的属性必须要有返回值。
  • 一个属性 同时具有 set get, 然后就不懂了, 待补充

单例模式

{ 无非是用一个变量来标志当前是否已经为某个类创建过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象:}

优点

  • 在内存中只有一个对象,节省内存空间;(创建 websocket 实例对象
  • 避免频繁的创建销毁对象,可以提高性能
  • 避免对共享资源的多重占用,简化访问;
  • 为整个系统提供一个全局访问点。

缺点

  • 不适用于变化频繁的对象
  • 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;
  • 如果实例化的对象长时间不被利用,系统会认为该对象是垃圾而被回收,这可能会导致对象状态的丢失;

封装进阶

为什么需要封装隐藏?

安全性:不想被看到具体实现,防止被篡改

封装隐藏

隐藏   放在函数内部执行,改变作用域

使用 (暴露)  通过 return

封装对象

**   ** 构造函数,原型方法

new  对象

利用自执行函数,window 暴露

1
2
3
4
5
6
7
8
(function () {
window.fun = function (参数) {
// 构造函数+原型方法
return new 对象(参数);
};
})();

// 调用:fun(参数)

深拷贝浅拷贝

-准备知识点-

–>基本的数据类型之间赋值,得到都是独立的值、

–>而引用数据类型之间的赋值,则是获取到的地址,数据任何变化,赋值方和被赋值方都会改变

所以我们需要拷贝、且拷贝也是引用数据类型上才存在的操作。

>>浅拷贝

  • 只是拷贝目标对象的一层数据,也就是   如果该对象或者数组中除了基础数据类型外,还有其他的引用数据类型。则无法拷贝更深的数据了。
  • –常用方法
    • 扩展运算符 […arr]  就是浅拷贝了 arr
    • =

Object.assign 方法   第一个参必须写。数组就写 []、对象就写{},在括号里面还可以添加新的属性。一个参数中的值,若在拷贝对象中存在,则还是使用拷贝对象的,如果不存在,则使用 assign 方法提供的。其实第一个参数就是设置默认值

二到 n 个参数参数就是要拷贝的对象或数组了。

Object.assgin

合并对象

  • const o1 = { a: 1 };const o2 = { b: 2 };const o3 = { c: 3 };
    const obj = Object.assign(o1, o2, o3);
    console.log(obj); // { a: 1, b: 2, c: 3 }
    console.log(o1); // { a: 1, b: 2, c: 3 }, // 第一个参数 target, 执行后自身也会改变。

合并具有相同属性的对象

  • const o1 = { a: 1, b: 1, c: 1 };const o2 = { b: 2, c: 2 };const o3 = { c: 3 };

const obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
属性被参数中具有相同属性的其他对象覆盖。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!