【学习前端第二十六课】 JavaScript面向对象(三)

本文详细介绍了JavaScript中面向对象编程的基础概念,包括变量名作为属性名、对象的属性和遍历(for...in,Object.keys(),Object.getOwnPropertyNames()),以及对象的继承(通过call/apply和原型实现)和包含关系。
摘要由CSDN通过智能技术生成

JavaScript面向对象(三)

变量名作为属性名

在定义对象的时候,对象里面的属性可以是字符串,也可以是数字

var obj1 = {
	name:"zhangsan",
	1:"数字属性",
	"a-b":"字符串属性"
};

var str = "age";  //能不能把str当成对象的属性名?

var obj2 = {
	name:"lisi",
	str:18
}

现在有没有种可能,我想把age当成属性名调用18

var str = "age";

var obj3 = {
	name:"zhaowu",
	[str]:18
}

/*
这个时候obj3的里面实际上就是下面这样的
{
	name:"zhaowu",
	age:18
}
*/
console.log(obj3.age);

对象的遍历

在之前对象学习中,我们就提到过对象遍历的问题,现在我们实际看下

通过for…in进行遍历

语法:

for(var 变量 in 对象){
	document.write(变量);
}

举例:

for(var i in window){
    document.write(i + "<br>");
}
//这里我们把window对象中的所有属性都遍历了出来

ECMAScript对象的属性是没有顺序的,因此,for-in循环输出的属性名的顺序是不可预测的,具体来讲,所有属性都会返回一次,但是返回的先后顺序可能会因浏览器而异

如果要遍历的对象的属性的值是null或者是undefined,for-in语句会报错,但是在ES5当中修改了这个问题,对于这种情况不再报错,但是不执行循环体

**注意:**for-in在遍历的时候,对象内部 enumerable:false 的属性是遍历不出来的

通过Object.keys() 来遍历对象

在js的内部,有一个方法叫做Object.keys() 它可以获取对象内的所有属性名

注意: 这个方法可以获取到也只有是 ``enumerable:true`的属性

var obj = {
    name:"zhangsan",
    sex:"nan",
    age:18
}

Object.defineProperty(obj,"hobby",{
    writable:true,
    configurable:false,
    enumerable:false,
    value:"play game"
})

var arr = Object.keys(obj);
arr.forEach(function(item,index,_arr){
    console.log("属性名:" + item + "------属性值:" + obj[item]);
})

Object.keys(对象) 会将对象里面所有可以遍历出来的属性拿出来组成一个数组返回出来,如果现在想遍历出来所有的属性怎么办?

通过 Object.getOwnPropertyNames() 来遍历

通过这个方法,可以获取到自己对象的所有属性名,把所有属性名组成数组返回出来

var obj = {
    name:"zhangsan",
    sex:"nan",
    age:18
}

Object.defineProperty(obj,"hobby",{
    writable:true,
    configurable:false,
    enumerable:false,
    value:"play game"
})

var arr = Object.getOwnPropertyNames(obj);
arr.forEach(function(item,index,_arr){
    console.log("属性名:" + item + "------属性值:" + obj[item]);
})

注意: 这种方式的遍历会把 enumerable:false 的属性也遍历出来,它获取的是对象的所有属性名称

判断某一个对象是否具备某一个属性

var stu = {
	name:"xiaofang",
	age:18
}
Object.defineProperty(stu,"hobby",{
	value:"sleep",
	enumerable:false
})

现在有这么个对象,我们想判断一下,这个对象是否有name,sex,hobby这三个属性怎么判断?

第一种方式

我们采用刚才才学习过的遍历的方式来完成

var arr = Object.getOwnPropertyNames(stu);  //返回一个装有所有属性名的数组

if(arr.indexOf("name") != -1){
	console.log("name属性存在");
}else{
	console.log("name属性不存在");
}

if(arr.indexOf("sex") != -1){
	console.log("sex属性存在");
}else{
	console.log("sex属性不存在");
}

if(arr.indexOf("hobby") != -1){
	console.log("hobby属性存在");
}else{
	console.log("hobby属性不存在");
}

第二种方式

判断一个对象当中是否存在一个属性,在js当中有一个关键字可以实现,这个关键字是 in

"name" in stu;  //如果返回true就说明存在,返回false说明不存在
"sex" in stu;   //false
"hobby" in stu;  //true

in的检测,如果过返回true代表存在,返回false不存在

说明一下:

in只是检测属性是否存在,跟属性是否可以被遍历出来是两码事

第三种方式

通过继承来检测,当我们在控制台输出对象的时候,我们可以在对象的体内找到一个 _ _proto _ _的属性,这个属性我们可以理解成当前对象的父对象是谁,而子对象是可以从父对象中继承来一些方法和属性的,其中我们在父对象中可以找到一个叫做 hasOwnProperty() 通过它我们可以判断当前对象内是否具备这个属性

stu.hasOwnProperty("name");  //返回true或false来检测是否有该属性

对象与对象之间的关系

对象之间的关系两种

1、对象继承对象,男人,女人都是对象但是他们都属于人这个类别

2、对象包含对象,比如有一个班级,班级有学生,那么两个对象之间就包裹状态

对象的继承关系

对象的继承是面向对象编程中最大的一个特点,它可以将多个对象的公共特征提取出来,然后再封装成一个对象,然后通过继承的方式再将原来公共的部分再给到具体的对象

通过call/apply去实现继承
//现在又一个学生,他有姓名,性别,年龄,学号4个属性,还有一个sayHello的方法,还有一个study的方法
function Student(userName,sex,age,sid){
    this.userName = userName;
    this.sex = sex;
    this.age = age;
    this.sid = sid;
    this.sayHello = function(){
        console.log("大家号,我叫" + this.userName + "我今年" + this.age + "岁了");
    }
    this.study = function(){
        console.log(this.userName + "在学习");
    }
}

//现在又一个老师,他有姓名,性别,年龄,教师编号4个属性,有一个sayHello的方法和一个teaching方法
function Teacher(userName,sex,age,tid){
    this.userName = userName;
    this.sex = sex;
    this.age = age;
    this.tid = tid;
    this.sayHello = function){
        console.log("大家号,我叫" + this.userName + "我今年" + this.age + "岁了");
    };
    this.teaching = function(){
        console.log(this.userName + "在教书");
    }
}

//可以创建2个学生
var stu1 = new Student("小明","男",20,"s001");
var stu2 = new Student("小红","女",18,"s002");

//创建老师对象
var t1 = new Teacher("邢国忠","男",18,"t001");

我们现在分别创建了2个构造函数Student和Teacher我们发现他们都有一些一样的特征,学生和老师都具备姓名,性别,年龄三个属性,同时还有一个共同的方法sayHello,针对这种现象,我们能不能进一步简化我们的代码?

我们可以很明显的感觉到里面有很多相同的代码,我们能不能把相同的代码提取出来创建一个新的对象呢?

也就是说,我们能不能将公共的对象提取出来,在用到我们面向对象当中的继承

继承有一个特点,子对象继承了父对象以后就可以把父对象中的某些属性和方法拿过来用

//将原来两个对象公共的部分提取出来,当作父对象来使用
function Person(userName,sex,age){
    this.userName = userName;
    this.sex = sex;
    this.age = age;
    this.sayHello = function(){
        console.log("大家号,我叫" + this.userName + "我今年" + this.age + "岁了");
    }
}


//现在又一个学生,他有姓名,性别,年龄,学号4个属性,还有一个sayHello的方法,还有一个study的方法
function Student(userName,sex,age,sid){			
    this.sid = sid;			
    this.study = function(){
        console.log(this.userName + "在学习");
    }
    //call在这里改变了this的指向
    Person.call(this,userName,sex,age);
    /*
    this.userName = userName;
    this.sex = sex;
    this.age = age;
    this.sayHello = function(){
        console.log("大家号,我叫" + this.userName + "我今年" + this.age + "岁了");
    }
    */
}

//现在又一个老师,他有姓名,性别,年龄,教师编号4个属性,有一个sayHello的方法和一个teaching方法
function Teacher(userName,sex,age,tid){
    this.tid = tid;
    this.teaching = function(){
        console.log(this.userName + "在教书");
    }
    Person.apply(this,[userName,sex,age]);
}

//可以创建2个学生
var stu1 = new Student("小明","男",20,"s001");
var stu2 = new Student("小红","女",18,"s002");

//创建老师对象
var t1 = new Teacher("邢国忠","男",18,"t001");
console.log(stu1,stu2);

上面的方法中我们已经通过call / apply 去实现了继承的关系,但是通过这种方法实现的继承有一个缺点,就是在数据结构上不能表现出继承关系

通过原型来实现继承

首先我们要弄清楚什么是原型

function Student(userName,sex,age){
	this.userName = userName;
	this.sex = sex;
	this.age = age;
}

var s1 = new Student("小明","男",20);

s1 instanceof Student  //true
//s1对象是由Student构造出来

然后我们可以在控制台打印s1,我们可以在原型中找到一个属性 __proto__ ,这是一个对象的特殊属性,他指向的就是对象的原型,对象原型可以理解成是对象的父级,那么我们现在通过这个属性来实现对象的继承关系

有一点先说明:

在JavaScript的面向对象当中,有这么一句话,一个对象的__proto__ 应该是等于这个对象的构造函数的prototype

s1.__proto__ === Student.prototype   //true  

__proto__ 可以设置对象的父级,那么 prototype 应该也是可以设置对象的父级的,所以现在根据这个特点我们来尝试去完成对象的继承

function Person(){
    this.height = height
	this.sayHello(){
		chonsole.log("大家好,我叫" + userName);
	}
}

function Student(userName,sex,age){
	this.userName = userName;
	this.sex = sex;
	this.age = age;
}

//我现在想让Student继承自Person
var s1 = new Student("小明","男",20);
var s2 = new Student("小芳","女",19);

第一种

s1.__proto__ = new Person();
s1.sayHello();

s2.__proto__ = new Person();
s2.sayHello();

这种方式可以实现继承,但是每次创建对象之后都要手动去设置 __proto__ 这样很麻烦

第二种

根据之前的结论

Student.prototype = new Person();

通过第一种或第二种办法我们发现还有缺点的

function Person(userName,sex,age){
	this.userName = userName;
	this.sex = sex;
	this.age = age;
	this.sayHello = function(){
		chonsole.log("大家好,我叫" + userName);
	}
}

function Student(userName,sex,age,sid){
    this.sid = sid;
    this.study = function(){
        console.log(this.userName + "在学习");
    }
}
//怎么样让Student继承Person之后还可以传参

怎么样让Student继承Person之后还可以传参

Student.prototype = new Person(姓名参数,性别参数,年龄参数);
//现在Person需要三个参数,但是我们的Student现在还没有创建(调用),所以压根就不知道要传什么东西过去

还是牢牢记住一句话一个对象的__proto__ 应该是等于这个对象的构造函数的prototype

最终办法

function Student(userName,sex,age,sid){
    this.sid = sid;
    this.study = function(){
        console.log(this.userName + "在学习");
    }
    this.__proto__ = new Person(userName,sex,age);
    //s1.__proto = Person构造出来的对象
    //Person构造出来的对象就成了s1的父级对象
    //Person在new的时候接收到了 Student在调用是赋值的实参,然后再把参数传给Person自己内部需要调用的地方
}

如果说以上逻辑暂时不台理解的话,我们可以这么来看问题,记住两点

1、如果想实现继承,在子对象的构造函数中,将 this.__proto__ 赋值父对象的构造函数的执行

2、父对象的构造函数中需要传递的参数,全部添加到子对象的构造函数上面去

对象的包含

对象的包含主要指的就是一个对象里面包含另外一个对象

//人的构造函数
function Person(userName,sex,age){
	this.userName = userName;
	this.sex = sex;
	this.age = age;
}

//学生的构造函数
function Student(userName,sex,age,sid){
    this.sid;
    this.study = function(){
        console.log(this.userName + "在学习");
    }
    this.__proto__ = new Person(userName,sex,age)
}

//老师的构造函数
function Teacher(userName,sex,age,tid){
    this.tid = tid;
    this.teaching = function(){
        console.log(this.userName + "在教书");
    }
    this.__proto__ = new Person(userName,sex,age);
}

var t1 = new Teacher("邢国忠","男",18,"t001");
var s1 = new Student("小明","nan",18,"s001");
var s2 = new Student("小红","nv",20,"s002");

//假设有一个班级对象
var classInfo = {
    className:"H2203",
    classAddress:"金融港",
    teacher:t1,
    student:[s1,s2]
}

现在我们就看到了一个班级里面包含了一个老师对象,也包含了学生对象的数组

练习:

1、现在有个动物分别是小猫cat和小狗dog,Cat构造函数里面有性别,年龄,昵称和体重四个属性,而Dog构造函数里面有性别,年龄,昵称,身高四个属性,猫与狗有一个共同的方法叫sleep睡觉,但是猫有一个方法miao,狗有一个方法wang

现在请列举出Cat和Dog的构造函数,并提取公共部分使用继承

突然之间又有一个小动物,农家田园犬Pastoral,他也属于狗的类别,也具备Dog的所有属性,但是它还有一个方法是看门

现在请创建Pastoral的构造函数,并实现继承关系

//动画的构造函数
function Animal(sex, age, nickName) {
    this.sex = sex;
    this.age = age;
    this.nickName = nickName;
    this.sleep = function () {
        console.log(this.nickName + "在睡觉");
    }
}

//猫的构造函数
function Cat(sex, age, nickName, weight) {
    this.weight = weight;
    this.miao = function () {
        console.log("喵喵喵");
    }

    //相当于继承了Animal
    // Animal.call(this, sex, age, nickName);
    this.__proto__ = new Animal(sex, age, nickName)

}
//狗的构造函数
function Dog(sex, age, nickName, height) {
    this.height = height;
    this.wang = function () {
        console.log("㕵㕵㕵");
    }
    //继承了Animal
    // Animal.call(this, sex, age, nickName);
    this.__proto__ = new Animal(sex, age, nickName)
}

//农家田园犬
function Pastoral(sex, age, nickName, height) {
    this.janitor = function () {
        console.log("看门");
    }
    // Dog.call(this, sex, age, nickName, height);
    // Dog.apply(this,[sex, age, nickName, height]);
    this.__proto__ = new Dog(sex, age, nickName, height)
}

var xiaohua = new Cat("母", 3, "小花", 4);
var dahuang = new Dog("公", 5, "大黄", 100);

var heizi = new Pastoral("公", 7, "黑子", 100);
console.log(heizi);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值