面向对象补充:
JavaScript 通过构造函数生成新对象,因此构造函数可以视为对象的模板。实例对象的属性和方法,可以定义在构造函数内部。
通过构造函数为实例对象定义属性,虽然很方便,但是有一个缺点。同一个构造函数的多个实例之间,无法共享属性,从而造成对系统资源的浪费。
JavaScript 继承机制的设计思想就是,原型对象的所有属性和方法,都能被实例对象共享。也就是说,如果属性和方法定义在原型上,那么所有实例对象就能共享,不仅节省了内存,还体现了实例对象之间的联系。
JavaScript 规定,每个函数都有一个prototype属性,指向一个对象。这个对象就是函数的原型。
-
eg:1继承
效果如下:
25.1继承.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
let p = new F('小明','很胖');
function F(name ,skill){
this.name = name;
this.skill = skill;
}
F.prototype.shou = 2;
F.prototype.showName = function(){
//字符串模板 '' "" `${}`
return `我的名字叫做:${this.name}`;
}
F.prototype.showSkill = function (){
return `我的技能是:${this.skill}`;
}
console.log(p.showName());
console.log(p.showSkill());
function Stu(name,skill,use){
F.apply(this,[name,skill]);
this.use = use ;
}
console.log(Stu.prototype.constructor);
Stu.prototype = new F('','');
console.log(Stu.prototype.constructor);
Stu.prototype.constructor = Stu;
console.log(Stu.prototype.constructor);
let liming = new Stu('李明','包揽了整个高中英语','use less');
console.log(liming.showName());
console.log(liming.showSkill());
</script>
</body>
</html>
原型链:
JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……
如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。也就是说,所有对象都继承了(多继承)
-
eg:2多继承
效果如下:
25.2多继承.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
function F(name,skill){
this.name = name;
this.skill = skill;
}
F.prototype.shou = 2;
F.prototype.showName = function(){
//字符串模板''\""\`${}`
return `我的名字叫做:${this.name}`;
}
F.prototype.showSkill = function(){
return `我的技能是:${this.skill}`;
}
function M(sex){
this.sex = sex;
}
M.prototype.showSex = function(){
return `我的性别是:${this.sex}`;
}
function W(use){
this.use = use;
}
W.prototype.showUse = function(){
return`我的功能是:${this.use}`;
}
function Stu(name,skill,sex,use){
F.apply(this,[name,skill]);
M.call(this,sex);
this.use = use;
}
Stu.prototype = Object.create(F.prototype);
Object.assign(Stu.prototype,M.prototype);
Object.assign(Stu.prototype,W.prototype);
Stu.prototype.constructor = Stu;
let z = new Stu('李华','高中英语','男','包揽了整个高中英语');
console.log(z.showName());
console.log(z.showSkill());
console.log(z.showSex());
console.log(z.showUse());
</script>
</body>
</html>
-
eg:3函数实现多继承
效果如下:
25.3函数实现多继承.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
function F(name,skill){
this.name = name;
this.skill= skill;
}
F.prototype.shou=2;
F.prototype.showName = function(){
//字符串模板''\""\`${}`
return `我的名字叫做:${this.name}`;
}
F.prototype.showSkill = function (){
return `我的技能是:${this.skill}`;
}
function M(sex){
this.sex = sex;
}
M.prototype.showSex = function(){
return `我的性别是:${this.sex}`;
}
function Stu(name,skill,sex,use){
this.use= use;
}
Stu.prototype.extends = function(obj,...man){
obj.apply(this,[...man]); //结构数组
Object.assign(Stu.prototype,obj.prototype);
Stu.prototype.constructor=Stu;
}
let z =new Stu('包揽了整个高中英语');
z.extends(F,'李明','高中英语');
z.extends(M,'男');
console.log(z.showName());
console.log(z.showSex());
console.log(z.showSkill());
</script>
</body>
</html>
-
eg:4.对象扩展
效果如下:
25.4扩展.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
function f(...m){
console.log([...m]); //扩展运算符(...)
}
f(1,222,333);
</script>
</body>
</html>
Object.prototype的属性。这就是所有对象都有valueOf和toString方法的原因,因为这是从Object.prototype继承的。
那么,Object.prototype对象有没有它的原型呢?回答是Object.prototype的原型是null。null没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是null。
-
eg:5单方面的继承
效果如下:
25.5单方面的继承.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
function F(){
}
F.prototype.h= function(){
console.log('h');
}
F.prototype.m=function(){
console.log('m');
}
function L(){
}
L.prototype.m =function(){
F.prototype.m.call(this);
}
let l = new L();
l.m();
</script>
</body>
</html>
constructor:
prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。
ES6
1、ES6面向对象:
class ----- 构造函数
对象 ----- 实例对象
-
eg:6ES6对象简写
效果如下:
25.6ES6对象简写.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
let name = '小明';
let skill = '高中英语';
let s = Symbol('s'); //对一无二的值
let ss = Symbol('ss');
console.log(s);
console.log(ss);
const obj ={
name,
skill,
say(){
console.log('say');
},
[s]:s,
};
console.log(obj.name)
obj.say();
console.log(obj[s])
</script>
</body>
</html>
-
eg:7面向对象
效果如下:
25.7ES6面向对象.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
const a = Symbol(); //常量
class Person{
constructor(name,skill){ //构造函数,new的时候自动的调用的,用于初始化的。自动传递参数
this.name = name;
this.skill=skill;
} //在此处有constructor所以不能有逗号
showName(){
console.log(`我的名字:${this.name}`);
}
showSkill(){
console.log(`我的技能:就是${this.skill}`);
}
[a](){
console.log(`我是Symbol数据类型的函数名`);
}
}
console.log(typeof Person);
let p1 =new Person('李明','高中英语');
p1.showName();
p1.showSkill();
p1[a]();
</script>
</body>
</html>
- ES5面向对象是模拟面向对象。
实例:
人类 张三
动物类 熊猫
鸟类 黄鹂
植物类 仙人球
哺乳动物 人
(1)、constructor: 类的构造函数,类在实例化的时候自动调用。参数自动传递。
(2)、class 的属性名可以是变量,但是这个变量需要使用[]包装起来,表示变量的解析。
class的内在本质还是一个function。
-
eg:9class结构
效果如下:
25.9class结构.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
class P{
constructor(name){
this.name=name;
}
say(){
console.log(this)
console.log(this.name);
};
}
let p1 =new P('李明');
p1.say();
let {say}=p1;
say.bind(p1);
</script>
</body>
</html>
对于ES5的构造函数来说,本质上定义的是一个函数,函数和变量一样,具有提升的特性,所以可以在构造函数的申明之前进行实例化。 class没有提升,所以在创建类对象的时候一定要保证类是先加载的。
-
eg:8class没有提升
效果如下:
25.8class没有提升.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
let pp= new P();
class P{
constructor(){//constructor构造函数是class必须的,即使没有声明 ,那么class也会自动的添加一个空的constrcutor函数。
}
}
</script>
</body>
</html>
2、setter与getter:
封装class内部成员属性的作用。
语法。
自动能调用。
(1)、set 语法定义的函数,外部在调用
函数名为属性的属性设置值的时候调用。
(2)、get 语法定义的函数。外部在获取
这个函数名为属性的属性的时候调用。
- eg:10get 与 set
效果如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
class P{
}
const Person = class{
constructor(name){
this.name= name;
}
/*
set age(value){
设置这个值的时候会自动调用console.log('这里调用参数的设置');
let c = value ;
console.log(c);
} */
get age(){
console.log('这里调用了参数的获取')
return 111111111;
}
}
let p1 =new Person('李明');
console.log(p1.name)
p1.name = '高中英语'; //公共属性
console.log(p1.age)
p1.age =22222222222222222;
console.log(p1.age)
</script>
</body>
</html>
有的时候我们需要不创建你对象,直接使用类去执行某些事情,这个时候就可以设计静态方法。
(3)、static 静态的。不需要实例化对象去调用的方法。
静态方法里面的this指类本身。而不是对象。
静态方法直接使用类名调用,不能使用对象调用。
静态的类: Math
实例:
var proxy = new Proxy(target, handler);
target : 要进行代理的对象。
handler:代理的规则。
代理:帮助做一些事情。
-
eg:11 static
效果如下:
25.11static.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
class P {
constructor(){}
say(){
console.log(this); //实例对象
console.log('1111111111111');
}
static ss(){
console.log(this); //class
console.log('2222222222222222222');
}
}
let p = new P();
p.say();
P.ss();
</script>
</body>
</html>
(4)extends继承
-
eg:12extends
效果如下:
25.12extends.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
class F{
constructer(name){
this.name = name;
}
say(){
console.log(this.name);
}
static s(){
console.log('ssssssssssssssssssss');
}
}
class W extends F{
constructor(name,age,skill){
//如果没有设置constructor,那么这个构造函数就是继承自父类。
//但是一旦自己设置了constructor函数,规定在内部必须调用父亲的构造函数
super(name); //表示调用父类的构造函数
this.age = age ;
this.skill = skill;
this.name = name;
}
eat(){
console.log('eat');
}
say(){ //重写 overriding
super.say(); //super表示父级
console.log('33333333333333');
}
}
let t = new W('lalalalalalala');
t.say();
t.eat();
W.s(); //继承静态的方法
</script>
</body>
</html>
(5)、proxy
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
-
eg:13proxy
效果如下:
25.13proxy.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
const obj = {//const
a:12,
b:'abc',
c:1111111,
d:'liming'
};
const c = new Proxy(obj,{
get: function(a,b,c){
//console.log(a);//第一个参数是代理对象
//console.log(b); //代理的属性
//console.log(typeof a[b])
//console.log(a[b].prototype)
if(typeof a[b] =='number'){
return a[b];
}
return 2;
}
});
console.log(c.d);
</script>
</body>
</html>
(6)、reflect
*Reflect*
对象与Proxy
对象一样,也是 ES6 为了操作对象而提供的新 API。*Reflect*
对象的设计目的有这样几个。
将Object
对象的一些明显属于语言内部的方法(比如Object.defineProperty
),放到Reflect
对象上。现阶段,某些方法同时在Object
和Reflect
对象上部署,未来的新方法将只部署在Reflect
对象上。也就是说,从Reflect
对象上可以拿到语言内部的方法。
效果如下:
25.reflect.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
const obj = {
a:122222,
b:'liming'
};
let c = new Proxy (obj,{
set:function(target,name,value,receiver){
var success = Reflect.set(target,name,2,receiver);
console.log(success);
if(success){
}
return success;
}
});
c.a = 1111111;
console.log(c.a);
</script>
</body>
</html>
网友评论