javascript 是一种基于原型(prototype)的面向对象的语言,而不是基于类的面向对象语言
C++,Java 有Class和实例 Instance 的概念,类是一类事物的抽象,而实例则是类的实体
JS是基于原型的语言,它只有原型对象的概念,原型对象就是一个模板,新的对象从这个模板构建从而获取最初的属性,任何对象在运行时可以动态的增加属性,而且,任何一个对象都可以作为另一个对象的原型,这样后者就可以共享前者的属性、
数组的解构
const arr =[100,200,300];
let [x,y,z] = arr;
console.log(1,x,y,z);
//100,200,300
//丢弃
const [,b,] = arr;
console.log(2,b);
// 200
//变量与元组个数不匹配
const [d,e ]= arr;
console.log(3,d,e);
//100 200
const [m,n,o,p] =arr;
console.log(4,m,n,o,p);
//100 200 300 undefined
//可变变量
const [f,...args] = arr;
console.log(5,f,args);
// 100,[200,300]
//支持默认值
const [j=1,k,,,l=10] = arr;
console.log(j,k,l);
//100 200 10
解构时,变量从左到右和元素对齐,可变参数放到最右边
能对应到数据就返回数据,对应不上就返回默认值,没有默认值就是undefined
对象的解构
const obj = {
a:100,
b:200,
c:300
};
let {x,y,z} = obj;
console.log(1,x,y,z);
//undefined undefined undefined
let {a,b,c} = obj ;
console.log(2,a,b,c);
// 100 200 300
let {a:m,b:n,c:p} = obj;
console.log(3,m,n,p);
// 100 200 300
let {a:M,b:N,c:C='Python',d:D='hello'} = obj;
console.log(4,M,N,C,D);
// 100 200 300 'hello'
数组的操作
方法
|
描述
|
push(...items)
|
尾部增加多个元素
|
pop()
|
移除最后一个元素,并返回它
|
map
|
引入处理函数来处理数组中的每一个元素,返回新的数组
|
filter
|
引入处理函数处理数组中每一个元素,此处理函数返回true的元素保留,否则该元素被过滤掉,保留的元素构成新的数组返回
|
foreach
|
迭代所有元素无返回值
|
对象的操作
Object的静态方法
|
描述
|
Object.keys(obj)
|
ES5开始支持,返回所有key
|
Object.values(obj)
|
返回所有值,试验阶段,支持较差
|
Object.entries(obj)
|
返回所有值,测试阶段,支持较差
|
Object.assign(target,...sources)
|
使用多个source对象,来填充target对象,返回target对象
|
const obj = {
a:100,
b:200,
c:300
};
console.log(Object.keys(obj));
console.log(Object.values(obj));
console.log(Object.entries(obj))
定义类
字面式声明方式
var obj = {
property_1 : value_1,
property_2 : value_2,
......
"property n" : value_n
};
这种方法也称作字面值创建对象
ES6之前的实现
定义一个函数(构造数)对象,使用this 定义属性
使用new和构造器创建一个新对象
//定义类
function Point(x,y) {
this.x = x;
this.y = y;
this.show = () => {
console.log("this:",this,this.x,this.y)
}
}
// 继承
function Point3D(x,y,z) {
Point.call(this,x,y);
this.z = z;
console.log(this,z);
}
console.log(Point3D);
p2 = new Point3D(13,14,15);
console.log(p2);
p2.show()
new 构建一个新的通用对象,new操作符会将新对象的this值传递给Point3D构造器函数,函数为这个对象创建Z属性
从上句话知道new后得到一个对象,使用这个对象的this来调用构造器,那么如何执行“基类”的构造器方法呢?使用Point3D对象的this来执行Point构造器,所以使用call方法,传入子类的this
ES6中的class
从ES6开始,新提供了 class关键字,使得创建对象更加简单,清晰
1、类定义
使用class关键字,创建的本质上还是函数,是一个特殊的函数
3、一个类只能拥有一个constructor的构造器方法,如果没有显式定义一个构造一个方法,则会添加一个默认的constructor方法
4、继承使用extends关键字
5、一个构造器可以使用super关键字来调用一个人父类的构造函数
6、类没有私有属性
示例:
class example {
constructor /*consturctor =>构造器函数*/(args1,args2){
this.args1 = args1;
this.args2 = args2;
// this is what mean? like python class self~~~
}
show() /* this show function is from example_class definition */
{
console.log("hello world")
}
how to use this class?
take new definition to this class
like:
Point = new example(args1,args2)
use inherit(继承)
class Point3D extends Point{
constructor(x,y,z){
super(x,y); //只是继承父类的this.x = x ,this.y = y 方法
this.z = z;
}
show(){
console.log(this.z,this.x,this.y)
}
}
let P2 = new Point3D(1,2,6);
P2.show();
重写方法
直接子类中重写一个 父类的方法,即可调用子类的 重写方法
箭头函数也支持子类的覆盖
如果想使用父类的方法,使用super.method()的方式调用即可
总结:
父类,子类使用同一种方式类定义方法,子类覆盖父类
如果父类使用属性,子类使用方法,则使用父类的属性,如果父类使用方法,子类使用属性,则使用子类的方法, 优先使用属性
静态属性
静态属性目前还没有得到很好的支持
静态方法
在方法名前 加上static 就是静态方法了
class add{
constructor(x,y){
this.x = x
this.y = y
}
static show (){
console.log("this is show function")
}
静态方法不需要实例调用,所以也不需要self 与cls, 直接使用类直接调用即可,like==> add.show()
静态方法,实例不能直接访问,
实例 可以通过 构造方法访问,like ==> add.constructor.show()
#静态的概念和python中的静态不同,相当于python中的类变量
关于this的知识点
js是动态语言,在运行期绑定,this在编译期绑定
var school = {
name : 'magedu',
getnamefunc : function () {
console.log(1,this.name);
console.log(2,this);
return function () {
console.log(3,this == global);
return this.name
}
}
};
console.log(school.getnamefunc());
console.log(school.getnamefunc()());
1、函数执行时,会开启新的上下文环境ExecutionContext
2、创建this属性,但是this是什么就要看函数是怎么调用的了
3、使用 school.getnamefunc() () ,调用,普通函数school.getnamefunc()( )调用方式,this指向global对象,nodejs的global或者浏览器的window
school.getnamefunc() 对象的调用方式,this指向包含该方法的对象
4、call和apply方法调用,需要注意第一个参数是谁
如何避免 this指针带来的不便呢?
1、显示传入(主动传入一个对象)
var school = {
name : 'magedu',
getnamefunc : function () {
console.log(1,this.name);
console.log(2,this);
return function (that) {
console.log(3,that == global);
return that.name
}
}
};
// console.log(school.getnamefunc());
console.log('~~~~~');
console.log(school.getnamefunc()(school));
//在调用时,将对象显示的传入进去,这样类似于绑定方法
2、ES,引入了apply,call方法
var school = {
name : 'magedu',
getnamefunc : function () {
console.log(1,this.name);
console.log(2,this);
return function () {
console.log(3,this == global); //判断当前this是否是全局的
return this.name
}
}
};
// console.log(school.getnamefunc());
console.log('~~~~~');
console.log(school.getnamefunc().call(school));
//call方法显示的传入了this对应的对象,确保了程序执行的正确性
apply call 方法都是函数对象的方法。第一参数都是传入对象引入的
function Print(){
this.print = function (x,y) {console.log(x+y)
};
}
p =new Print();
p.print(10,20);
call传其他参数需要使用可变参数收集
p.print.call(p,10,20);
apply传其他参数需要使用数组
p.print.apply(p,[10,20]);
ES5引入了bind方法
bind方法来设置函数的this值
var school = {
name : 'school',
getNamaefunc : function () {
console.log(this.name);
console.log(this);
return function () {
console.log(this == global);
return this.name;
};
}
};
var func = school.getNamaefunc();
console.log(func);
console.log('~~~~~~~~~~');
var boundfunc = func.bind(school); //绑定后返回新的 函数bound()
console.log('~~~~~~~~~~');
console.log(boundfunc);
console.log('~~~~~~~~~~');
console.log(boundfunc());
apply,call方法、参数不同,调用时传入this
bind方法是先绑定this,调用时直接传入
ES6 引入支持this的箭头函数
ES6新技术,不需要兼容this问题
class school{
constructor(){
this.name = 'magedu'
}
getNamefunc(){
console.log(this.name)
console.log(this,typeof this)
return () =>{
console.log(this == global);
return this.name;
};
}
}
console.log(new school().getNamefunc()());
bind方法在应用中使用的较多
高阶对象,高阶类,或称为Mixin模式
Mixin模式,混合模式这是一种不用继承就可以复用的技术,主要还是为了解决多重继承的问题,多继承路径是个问题
js是基于对象的,类和对象都是对象模板
混合mixin,指的是将一个对象的全部或者部分拷贝到另一个对象上去,其实就是属性
可以将多个类或者对象混合成一个类或对象
继承实现实例:
class Serialization{
constructor(){
console.log('Serialization constructor~~~')
if (typeof(this.stringfy)!== "function") {
throw new ReferenceError('should defined stringfy');
}
}
}
class Point extends Serialization{
constructor(x,y){
console.log("point constructor")
super();
this.x = x
this.y = y
}
//子类必须满足继承父类的构造器函数条件才可以完成构造,所以子类中需要一个stringfy方法
stringfy (){
return `<Point ${this.x}.${this.y}>`
}
}
//Point类继承了父类的构造器方法,父类构造器中方法条件不满足则构造失败
// s = new Serialization();
p = new Point(4,5);
//高阶类的实现
class A extends Object{};
console.log(A);
//匿名继承
const B = class extends Object{
constructor(){
super();
console.log('B constructor');
}
};
// console.log(B);
// b = new B();
// console.log(b);
//箭头函数,参数是类,返回值也是类
const x =(sup) => {
return class extends sup{
constructor(){
super();
console.log('b constructor');
}
}
}
//演化
const C = sup => class extends sup{
constructor(){
super();
console.log("c constructor")
}
}
cls = C(A);
console.log(cls,typeof cls);
c = new cls();
console.log(c);
//流程, 定义常量C,它是一个函数,这个函数可以混合别的类,返回一个新的类,new class = C(需要混合的类名),拿到new class后,在对其实例化 cls = new class();, 这样生产出的 cls类就可以获得 混合类的属性与方法
将序列化函数改造为箭头函数 高阶对象实例
const Serialization = Sup => class extends Sup{
constructor(...args){
console.log('Serialization constructor~~~');
super(...args)
if (typeof(this.stringfy)!== "function") {
throw new ReferenceError('should defined stringfy');
}
}
}
class Point {
constructor(x, y) {
console.log("point constructor");
this.x = x
this.y = y
}
}
class Point3D extends Serialization(Point) /*返回一个新类*/{
constructor(x,y,z){
super(x,y);
this.z = z
}
stringfy (){
return `<Point3d ${this.x}.${this.y}.>`
}
}
cls = new Point3D(4,5,6)
console.log(cls)
这个cls 实际上可以使用三个类的方法,因为这个类的定义中实际混合两个类的 混合返回的新类