面向对象JS ES5/ES6 类的书写 继承的实现 new关键字执行 this指向 原型链
2021-05-02 08:28
标签:nod 编程技术 cal 之间 数据 步骤 var 直接 exe 一般可以分为两种: 声明式,告诉计算机应该做什么,但不指定具体要怎么做。如:html,css等 其中命令式编程又可以为两类 将我们要解决问题所需要的步骤分析出来,然后用函数把这些步骤一步一步实现(有序步骤),关注细节。 将问题中的对象抽象出来,既把构成问题的事物分解成各个对象,而解决问题的不是一个个过程化的步骤, 而是利用对象描述、处理“问题”的行为集合(离不开面向过程)。 对象的含义是指具体的某一个事物,即在现实生活中能够看得见摸得着的事物,有句话叫做:万物皆对象。 对象是类的具体实例,对象的抽象是类。 类是具有相同特性(数据元素)和行为(功能)的对象的抽象,代表一类事物的抽象描述。 在代码中:类好比是一个模板,可以批量生产。 类是对象的抽象,类的具体化就是对象。 原本JS不支持面向对象(oo),所以在ES5用函数模拟出类,在ES6时加入语法糖,书写起来更加清晰、更像面向对象编程的语法。 类的本质是函数:构造函数+全局公共区域 prototype。 ES5 注:两种方式都能成功的声明一个Person类,现在一般就用ES6方式,但是其实内部是用ES5的方式运行的,ES6方式相当于一个语法糖。 每次使用new关键字会执行的步骤: 1、创建一个空的新对象,作为将要返回的对象实例 注:class 定义的类,必须使用new关键字调用,不然会报错, new关键字总是返回一个对象,如果new 普通函数,会返回一个空对象。 隐藏内部细节,不暴露在外面;做到信息的隐藏,不关心具体怎样实现的,只需要知道能达到效果就行了。 具体表现形式: 子类继承父类的所有属性和方法,并且扩展自己的属性和行为。 类与类之间的关系:is a(是一个) 例如:学生——>人类 实现 改变this指向的三个函数实例方法 extends 扩展 从子类,扩展到父类 即继承父类 super 超类 继承父类 用于调用父亲的构造,必须与extends关键字一起使用,且只能在构造函数中所有的this之前书写 1、箭头函数中,没有自己的this,它借用声明箭头函数处(环境中的)的this(就固定这个值) 2、谁调用,指向谁 3、事件监听函数中,this指向,绑定监听函数的那一个元素节点(谁绑,指向谁) 4、当一个函数没有被其他对象调用时,(普通调用),this指向全局对象(严格模式下面是undefined) 5、在执行构造函数时(new),this指向新创建的对象 所有function创建的对象,都叫做函数对象(函数) 所有函数对象上都有一个原型对象,prototype 所有对象上都有一个隐式原型对象,__proto__,指向创建该对象的构造函数的原型对象 所有原型对象上都有一个constructor对象,指向该原型对象所在的构造函数本身 对象可以分为函数对象(所有直接通过function创建的对象)和一般对象(其他对象),所有的对象在创建时,都会创建一个对应的原型对象 函数对象的原型对象为:函数.prototype,函数.prototype上都有一个constructor对象,指向该原型对象所在的构造函数本身 一般对象的原型对象被称为隐式(和函数对象的原型对象相区分)原型对象: 对象.__proto__,指向创建该对象的构造函数的原型对象 一个对象通过自身的__proto__,一直向上链接,直到null,所构成的的链条,就是原型链 当一个对象在访问自身某个属性时,会先在自己身上找,没有找到就通过原型链(__proto__),层层向上找,直到找完为止 若找完整个原型链都没有找到,那么该属性的值就是,undefind。 面向对象JS ES5/ES6 类的书写 继承的实现 new关键字执行 this指向 原型链 标签:nod 编程技术 cal 之间 数据 步骤 var 直接 exe 原文地址:https://www.cnblogs.com/jiayouba/p/12004285.html一 、什么是面向对象?
编程范式
命令式,关注计算机执行的步骤,即一步一步告诉计算机先做什么再做什么。如:js,c++,java,c#,python等
面向过程:
面向对象:二、面向对象的基本概念
1、对象
2、类
类的实现 //混合模式:构造函数模式+原型模式
function Person(name, age) {//构造函数模式
this.name = name; /*属性*/
this.age = age;
this.study = function () {
console.log(this.name + ‘在运动‘);
}
}
//原型模式 prototype,原型链上面的属性会被实例对象共享
Person.prototype.sex = "男";//共有的属性
Person.prototype.exercise = function () {//共有的函数
console.log(this.name + ‘在锻炼‘);
}
//类的静态属性和方法不会被实例对象共享
Person.num = 11234;//定义静态属性
Person.printNum = function () {//定义静态方法
console.log(this.num);
}//注:函数也是一个对象,所谓的静态属性方法,本质就是给名为Person的对象添加了属性和方法
var stu = new Person(‘张三‘, 20);
console.log(stu);//Person { name: ‘张三‘, age: 20, study: [Function] }
console.log(stu.sex);//男
stu.study();//调用自带方法 => 张三在运动
stu.exercise(); //调用原型方法 => 张三在锻炼
console.log(Person.num);//11234 静态属性和方法 通过 类名.方法(属性名) 调用或访问
console.log(stu.num);//undefined 实例对象不能使用
Person.printNum();//11234
stu.printNum();//报错 stu.printNum is not a function
ES6class Person {
constructor(name, age) {//构造函数
this.name = name; /*属性*/
this.age = age;
this.sex = "男";
this.study = function () {
console.log(this.name + ‘在运动‘);
}
}
static num = 11234;//定义静态属性
static printNum() {//定义静态方法
console.log(this.num);
}
exercise() {//共有的函数
console.log(this.name + ‘在锻炼‘);
}
}
var stu = new Person(‘张三‘, 20);
console.log(stu);//Person { name: ‘张三‘, age: 20, sex: ‘男‘, study: [Function] }
console.log(stu.sex);//男
stu.study();//张三在运动
stu.exercise(); //张三在锻炼
console.log(Person.num);//11234
console.log(stu.num);//undefined
Person.printNum();//11234
stu.printNum();//报错 stu.printNum is not a function
关于new
var obj = {};
2、将该对象的__proto__(隐式原型)指向创建该对象的类的原型对象
//假设类叫做 A
obj.__proto__ = A.prototype;
3、将构造函数环境中的this,指向该对象
相当于:this = obj;//意识到位,代码这样写是错误的
4、执行构造函数中的代码,并返回刚刚创建的新对象 关于构造函数constructor
constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。
返回值
构造函数也有返回值,默认返回实例对象(即this),可以更改,若改为基本数据类型的返回值,则不影响函数。
若改为复杂数据类型的返回值,则会直接将该返回值直接返回,会导致返回值不再是原来类的实例对象,三、面向对象三大特征
1、封装
函数 是对于算法的封装
类 是对于属性和方法的封装2、继承
function Student(){
Person.call(this); //对象冒充实现继承 对象冒充可以继承构造函数里面的属性和方法 但是没法继承原型链上面的属性和方法
}
//原型链实现继承 原型链实现继承:可以继承构造函数里面的属性和方法 也可以继承原型链上面的属性和方法
Student.prototype = Object.assigin(Person.prototype); //与拷贝类似,但不同
//Student.prototype=new Person(); //这种方法功能是能实现,但是太矬了
// Student.prototype = Object.create(Person.prototype); //没有将create的储存起来,只是利用原型链找到有属性的父类
var name = 99;
function foo(a, b) {
console.log(this.name, a, b);//this本来指向全局的 name=99
}
let zs = {
name: "zs"
}
let ls = {
name: "ls"
}
//call方法,可以指定函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数第一个参数(对象)为指向。
foo.call(ls, 1, 2);//ls 1 2
//apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数
foo.apply(zs, [2, 3]);//zs 2 3
//bind方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。这个要主动调用
let bar = foo.bind(zs);
bar(3,4);//zs 3 4
ES6// 图形祖宗
class Graph {
constructor(color, top, left) {
this.color = color;
this.top = top;
this.left = left;
this.node = null;
}
creatNode() { }
addNode() {
document.body.appendChild(this.node);
}
}
// 矩形
class Rectangle extends Graph {
constructor(color, top, left, lengthX, lengthY) {
super(color, top, left);
this.lengthX = lengthX;
this.lengthY = lengthY;
}
creatNode() {
this.node = document.createElement(`div`);
this.node.style.position = "absolute";
this.node.style.background = this.color;
this.node.style.top = this.top + "px";
this.node.style.left = this.left + "px";
this.node.style.width = this.lengthX + "px";
this.node.style.height = this.lengthY + "px";
}
}
3、多态
方法(行为) 相同的行为不同的实现 传的参数不一样,决定了实现方法不一样
代码中的多态:
重载 参数的不同,实现不同 js自带,因为js没有严格的指定参数的个数类型
重写 父亲的行为,儿子重写一个覆盖了四、this和原型对象
this指向问题
原型对象
规则:或者这样说:
原型链:
原型链作用:用来找属性
文章标题:面向对象JS ES5/ES6 类的书写 继承的实现 new关键字执行 this指向 原型链
文章链接:http://soscw.com/index.php/essay/81254.html