[华为云在线课程][JavaScript的面向对象][学习笔记]
【摘要】 第1章,JavaScript的面向对象机制 1.1,JavaScript的面向对象的对象JavaScript对象的概念:现实生活中:万物皆对象,对象是一个具体的事物,看得见摸得着的实物例如,一本书,一辆汽车,一个人可以是"对象",一个数据库,一张网页一个与远程服务器的连接也可以是"对象"在JavaScript中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数...
第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执行该内存
- 执行函数体内部的代码
- 默认返回我们的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
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)