[华为云在线课程][JavaScript的面向对象][学习笔记]

网友投稿 531 2022-05-30

第1章,JavaScript的面向对象机制

1.1,JavaScript的面向对象的对象

JavaScript对象的概念:

现实生活中:万物皆对象,对象是一个具体的事物,看得见摸得着的实物

例如,一本书,一辆汽车,一个人可以是"对象",一个数据库,一张网页一个与远程服务器的连接也可以是"对象"

在JavaScript中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等

对象是由属性和方法组成的:

属性:事物的特征,在对象中用属性来表示

方法:事物的行为,在对象中用方法来表示

JavaScript创建对象的方式:

利用构造函数创建对象

利用字面量创建对象

利用new Object创建对象

使用对象的优点:

JavaScript中的对象表达结构更清晰,更强大

对象是复杂数据类型object

对象就是一组无序的相关属性和方法的集合

/* * 创建对象三种方式之一:使用对象字面量创建对象 * {} -> 包含表这个具体事物的属性和方法,以键值对形式存在 * 键:相当于属性名称 * 值:相当于属性值,可以是任意值 * */ var star = { "name": "hello", "age": "30", "gender": "男", "height": "200", "sayHi": function () { alert("hello world"); } } /* * 访问对象的属性 * 对象.属性名 * 对象['属性名'] --> 属性名在中括号中必须加引号 * 对象.方法名() --> 方法名后面必须加上() * */ console.log(star.name);//hello console.log(star['age']);//30 console.log(star.sayHi());//hello world

/* * 创建对象三种方式之二:利用 new Object 创建对象 * */ var hello = new Object(); hello.name = "hello's name"; hello.age = "10"; hello.sayHi = function () { console.log("function saiHi()"); }

/* * 创建对象三种方式之三:利用构造函数创建对象 * 提取对象中的一些公共的属性和方法,封装到这个函数里 * 构造函数名首字母要大写 * */ function 构造函数名(形参1, 形参2, 形参3) { this.属性名1 = 参数1; this.属性名2 = 参数2; this.属性名3 = 参数3; } var obj = new 构造函数名(实参1, 实参2, 实参3);

1.2,JavaScript的构造函数

JavaScript构造函数

一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与new运算符一起使用,我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面

利用构造函数创建对象

构造函数的语法格式:

function 构造函数名() { this.属性 = 值; this.方法 = function () { } } new 构造函数名();

JavaScript构造函数和对象案例:

构造函数:如Person(),抽象了对象的公共部分,封装到了函数里面,它泛指某一大类(class)

构造对象:如new Person(),特指某一个对象,通过new关键字创建对象的过程我们也称为对象实例化

只有以new关键字来调用的时候,我们才能说这是一个构造函数

构造函数的执行过程:

当以new关键字调用时,会创建一个新的内存空间

函数体内部的this执行该内存

[华为云在线课程][JavaScript的面向对象][学习笔记]

执行函数体内部的代码

默认返回我们的this

function Person(name, age, gender) { this.name = name; this.age = age; this.gender = gender; this.info = function () { console.log("姓名是:" + this.name + ",年龄是:" + this.age + ",性别是:" + this.gender); }; } var person = new Person("hello", 10, "男"); console.log(person.name);//hello person.info();//姓名是:hello,年龄是:10,性别是:男

1.3,JavaScript的new命令

new命令在执行时会做四件事情:

在内存中创建一个新的空对象

让this指向这个新的对象

执行构造函数里面的代码,给这个新对象添加属性和方法

返回这个新对象(所以构造函数里面不需要return)

JavaScript的new命令案例:

//构造函数 function Stu(name, age, address) { this.name = name; this.age = age; this.address = address; this.showInfo = function () { console.log("姓名:" + this.name + ",年龄:" + this.age + ",地址:" + this.address); }; } //利用new来调用我的构造函数 var stu = new Stu("张三", 10, "地球");//创建一个新的内存 stu.showInfo();//姓名:张三,年龄:10,地址:地球

JavaScript利用字面量创建对象:

对象字面量:就是花括号{}里面包含了表达这个具体事物(对象)的属性和方法

对象的调用:

对象里面的属性调用:对象.属性名,这个小点.就理解为"的"

对象里面属性的另一种调用方式:对象[‘属性名’],注意方括号里面的属性必须加引号

对象里面的方法调用:对象.方法名(),注意这个方法名后面一定加括号

//创建一个Object对象,简写 var p1 = {}; //动态增加属性、方法 p1.name = "hello"; p1.age = 10; p1.sayHi = function () { alert("function: " + p1.name); }; p1.sayHi();

JavaScript利用new Object创建对象

//利用new Object创建对象 //创建了一个空的对象 var obj = new Object(); obj.name = "hello"; obj.age = 1; obj.gender = "男"; obj.sayHi = function () { console.log("world, " + obj.name); }; console.log(obj.name);//hello console.log(obj["age"]);//1 obj.sayHi();//world, hello

JavaScript面向对象之封装

封装就是把抽象出来的属性和对属性的操作封装在一起,属性被保护在内部,程序的其他部分只有通过被授权的操作函数,才能对属性进行操作

function Person(_name, _age, _salary) { //Person类的公开属性,类的公开属性的定义方式是:"this.属性名" this.name = _name; //Person类的私有属性,类的私有属性的定义方式是:"var 属性名" var age = _age; var salary = _salary; //定义Person类的公开方法(特权方法),类的公开方法的定义方式是:"this.functionName=function(){...}" this.Show = function () { //在公开方法里面访问类的私有属性是允许的 console.log("Age=" + age + "\t" + "Salary=" + salary); }; /* * 定义Person类的私有方法(内部方法) * 类的私有方法的定义方式是:”function functionName(){...}“ * 或者var functionName = function(){...} * */ function privateFn() { console.log("我是Person类的私有函数privateFn"); } var privateFn2 = function () { console.log("我是Person类的私有函数privateFn2"); }; } var p1 = new Person("hello", 1, 100); //访问公有属性,这是可以正常访问的 console.log("p1.Name=" + p1.name);//p1.Name=hello //不能使用类的对象去直接访问类私有属性,这是访问不了的,结果都是undefined console.log("p1.Age=" + p1.age + "\t" + "p1.Salary=" + p1.salary);//p1.Age=undefined p1.Salary=undefined //调用类的公共函数,这是允许的 p1.Show();//Age=1 Salary=100 //不能使用类的对象去调用类的私有方法,这里会报错对象不支持此属性或者方法"" console.log("p1.privateFn():" + p1.privateFn() + "p1.privateFn2():" + p1.privateFn2());//Uncaught TypeError: p1.privateFn is not a function

1.4,JavaScript的原型对象

JavaScript中ES5中没有类Class,但是它取了一个新的名字叫"原型对象",因此"类=原型对象"

类(原型对象)是抽象,是概念的,代表一类事物;对象是具体的,实际的,代表一个具体的事物

每个对象一定会有一个原型对象

原型对象实际是构造实例对象的构造器中的一个属性,只不过这个属性是个对象

这个原型对象中的属性与方法,都会被对象实例所共享(类似Java中的类方法,类属性)

原型对象的属性不是对象实例的属性,只要修改原型对象上的属性和方法,变动就会立刻体现在所有对象实例上

JavaScript对每个创建的对象都会设置一个属性__proto__,指向它的原型对象xxx.prototype

JavaScript中,每个函数都有一个prototype属性,这个属性指向函数的原型对象:

函数的prototype指向了一个对象,而这个对象正是调用构造函数时创建的实例的原型,也就是person1和person2的原型

原型的概念:每一个JavaScript对象(除null外)创建的时候,就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型中"继承"属性。

function Person(age) { this.age = age; } Person.prototype.dname = "hello"; var person1 = new Person(); var person2 = new Person(); console.log(person1.dname);//hello console.log(person2.dname);//hello

JavaScript中,每个对象(除null外)都会有的属性,叫做__proto__,这个属性会指向该对象的原型:

function Person() { } var person1 = new Person(); var person2 = new Person(); console.log(person1.__proto__ === Person.prototype);//true console.log(person1.__proto__ === person2.__proto__);//true

JavaScript中,每个原型都有一个constructor属性,指向该关联的构造函数

function Person() { } console.log(Person === Person.prototype.constructor);//true

/* * in操作符 * 只要对象或者原型有一地方存在这个属性,就会返回true * */ function Person() { } Person.prototype.name = "hello"; var p1 = new Person(); p1.sex = "男"; alert("sex" in p1);//对象本身添加的 所以会返回true alert("name" in p1);//原型中存在,所以会返回true alert("age" in p1);//对象原型中都不存在,所以会返回false

function Person() { } Person.prototype.name = "hello"; var p1 = new Person(); p1.sex = "男"; //定义一个函数去判断原型所在的位置 function propertyLocation(obj, prop) { if (!(prop in obj)) { alert(prop + "属性不存在"); } else if (obj.hasOwnProperty(prop)) { alert(prop + "该属性存在此对象中"); } else { alert(prop + "该属性存在此对象的原型中"); } } propertyLocation(p1, "age");//age属性不存在 propertyLocation(p1, "name");//name该属性存在此对象的原型中 propertyLocation(p1, "sex");//sex该属性存在此对象中

第2章,JavaScript的面对对象继承

继承

继承是面向对象语言的一个重要概念

许多面向对象语言都支持两种继承方式:接口继承和实现继承;接口继承只继承方法签名,而实现继承则继承实际的方法

由于函数没有签名,所以ECMAScript只支持实现继承,而实现继承主要是依靠原型链来实现的

2.1,JavaScript原型继承

原型继承

基本思想:利用原型让一个引用类型继承另一个引用类型的属性和方法

核心:将父类的实例作为子类的原型

缺点:父类新增原型方法/原型属性,子类都能够访问到,并且父类一变其他都变了

function Animal() { this.species = "动物"; this.colors = ["白色"]; } function Cat(name, eat) { this.name = name; this.cat = eat; } Cat.prototype = new Animal(); var cat1 = new Cat("猫", "老鼠"); console.log(cat1.species);//动物 console.log(cat1.colors);//['白色']

/* * 原型继承存在的问题: * Cat的所有的实例都会共享colors属性 * */ function Animal() { this.species = "动物"; this.colors = ["白色"]; } function Cat(name, eat) { this.name = name; this.eat = eat; } Cat.prototype = new Animal(); var cat1 = new Cat("猫", "老鼠"); console.log(cat1.species);//动物 console.log(cat1.colors);//['白色'] cat1.colors.push("黑色"); console.log(cat1.colors);//['白色', '黑色'] var cat2 = new Cat("大猫", "鱼"); console.log(cat2.colors);//['白色', '黑色']

构造函数继承:

基本思想:在子类型构造函数的内部调用超类型构造函数。函数只不过是在特定环境中执行代码的对象,因此可通过使用call()和apply()在新创建的对象上执行构造函数

因为属性是绑定在this上面的,所以调用的时候才赋值到了相应的实例中,各个实例的值就不会相互影响了

核心:使用父类的构造函数来增强子类的实例,等于是赋值父类的实例属性给子类(没有用到原型)

缺点:方法都在构造函数中定义,只能继承父类的实例属性和方法,不能继承原型属性/方法,无法实现函数的复用,每一个子类都有父类实例函数的副本,影响性能

function Animal() { this.species = "动物"; this.colors = ["白色"]; } function Cat(name, eat) { Animal.apply(this, arguments); this.name = name; this.eat = eat; } var cat1 = new Cat("猫", "鱼"); //动物 console.log(cat1.species);//动物 cat1.colors.push("黑色"); console.log(cat1.colors);//['白色', '黑色'] var cat2 = new Cat("狗", "狗粮"); console.log(cat2.colors);//['白色']

/* * 构造继承存在问题: * 1,方法都在构造函数中定义,所以没法利用函数的复用 * 2,并且在超类型的原型中定义的方法对于子类型而言是不可见的 * */ function Animal() { this.species = "动物"; this.colors = ["白色"]; } Animal.prototype.getColor = function () { return this.colors; }; function Cat(name, eat) { Animal.apply(this, arguments); this.name = name; this.eat = eat; } var cat1 = new Cat("猫", "鱼"); console.log(cat1.species);//动物 cat1.colors.push("黑色"); console.log(cat1.colors);//['白色', '黑色'] console.log(cat1.getColor()); var cat2 = new Cat("狗", "狗粮");

2.2,JavaScript的组合继承

基本思想:使用原型链实现对原型属性和方法的继承,而通过构造函数实现对实例属性的继承

组合继承是最常用的继承方法

核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后再通过将父类实例作为子类原型,实现函数复用

缺点:调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那一份给屏蔽)

function Animal(species) { this.species = species; this.colors = ["白色"]; } Animal.prototype.getColor = function () { console.log(this.colors); }; function Cat(name, eat) { this.name = name; this.eat = eat; Animal.call(this, name); } //继承方法 Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; Cat.prototype.sayName = function () { console.log(this.name); }; var cat1 = new Cat("猫", "吃鱼"); cat1.colors.push("黑色"); console.log(cat1.colors);//['白色', '黑色'] cat1.getColor();//['白色', '黑色'] cat1.sayName();//猫 var cat2 = new Cat("波斯猫", "吃猫粮"); console.log(cat2.colors);//['白色'] cat2.getColor();//['白色'] cat2.sayName();//波斯猫

JavaScript的面向对象的多态:

同一操作作用于不同的对象上面,可以产生不同的解释和不同的执行结果

var makeSound = function (person) { if (person && person.sound instanceof Function) { person.sound(); } }; var Student = function () { }; Student.prototype.sound = function () { console.log("学生通过发出声音练习英语"); }; var Employee = function () { }; Employee.prototype.sound = function () { console.log("员工通过发出声音沟通工作"); }; makeSound(new Student());//学生通过发出声音练习英语 makeSound(new Employee());//员工通过发出声音沟通工作

2.3,JavaScript的This关键字

普通函数中的this

单独使用this,指的是全局对象,在浏览器中,window就是全局对象,在严格模式下,单独使用this指向的还是全局

在函数中使用this,函数的所属者就会被绑定在this上,在浏览器中,window就是全局对象,严格模式就没有绑定在全局上,this就是undefined

//在es5中 function foo() { //这里的this是window console.log(this); } foo();//Window {window: Window, self: Window, document: document, name: '', location: Location,…}

//在es5中 function foo() { 'use strict'; //这里的this是undefined console.log(this); } foo();//undefined

对象方法中this

在对象中使用this,指向的就是我们的对象

var obj = { info: "tom", showInfo: function () { //这里的this是obj console.log(this.info); } }; obj.showInfo();//tom

构造函数中this

在构造函数中使用,指向具体的某个实例

function Foo(name, age) { //这里的this指的是具体的某个实例f1或f2 this.name = name; this.age = age; this.showName = function () { //这里的this指的是具体的某个实例f1或f2 console.log(this.name); }; } var f1 = new Foo("hello", 1); f1.showName();//hello var f2 = new Foo("world", 2); f2.showName();//world

面向对象中的this

指向的是一个构造函数创建的实例,原型里面就是指通过原型所属构造函数创建出来的实例

function Foo(info) { //这里的this指的是该构造函数创建出来的实例,这个this和原型中的this是同一个指向 this.info = info; } Foo.prototype.showInfo = function () { //原型里面的this指的是通过原型所属的构造函数创建出来的实例 console.log(this.info); }; var f1 = new Foo("hello"); f1.showInfo();//hello

JavaScript

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:疯狂Java之学习笔记(25)-------------修饰符
下一篇:Git之深入解析如何重写提交历史
相关文章