Object classification: 1. Built-in objects. 2. Host objects: BOM, DOM. 3. Self-built object
The first way to define a self-built object: use new object (not recommended)
let student = new Object();
student.Sex = "Female";//定义的同时如果没有赋值就是undefined。这种方法创建的对象属性可以不赋值
console.log(student.Sex);//不写=XXX则输出undefined
student.Score = 40;
console.log(student.Score);
delete student.Score;//删除对象属性值
console.log(student.Score);//undefined
//用中括号也可以定义属性和赋值。更灵活(同样的,这种方式定义的属性也可以不赋值)
student["Age"] = 23;
student["telephone"] = "132423";
let flag = "Age";
console.log(student[flag]);//改的时候只要改flag的string从Age改成telephone
student.PrintInformation = function () {
console.log("Sex is:" + this["Sex"] + ",Age is:" + this["Age"]);//不在块级作用域里,用点.调不到?虽然写了也没报错?
}
student.PrintInformation();
console.log(student);//直接输出对象名则会打印所有属性名和值和函数名称
The second way to define self-built objects: use object literals (recommended):
let Teacher =
{
Name: "ZhangSan",
Age: 19,
Sex: undefined,//和第一种方法不同的是,这里如果定义时不想为属性赋值不能空着不写,空着会报错
PrintInformation: function () {
console.log("Name is:" + this.Name + ",Age is:" + this.Age);
},//记得有逗号
InsertSex: function (Sex) {
//JS中形参不声明类型!最好给所写的函数添加类似的实参类型检查逻辑(这里没写)
this.Sex = Sex;
console.log("Sex is " + this.Sex);
return 1;
}//最后一条的逗号可以不加
};//分号可以加也可以不加
Teacher.PrintInformation();
let result = Teacher.InsertSex("Male");
//对象也可以当作对象的属性
let Person = {
child: Teacher
};
console.log("Teacher对象的性别是:" + Person.child.Sex);
function fun1() {
console.log("直接定义一个函数,不和对象绑定")
}
fun1();
(function ()//函数用()包起来并且不写函数名表示这是一个匿名函数,不写函数名(在其他场景,如事件,可以省略最外侧的()括号)
{
console.log("这是立即执行函数");//立即执行函数声明完马上调用,仅用一次。立即执行函数会形成一个单独的作用域,我们可以封装一些临时变量或者局部变量,避免污染全局变量
})()//最后的括号表示立即调用(不加的话就相等于一个匿名函数)
//for in 遍历对象的属性
for (let teacherKey in Teacher) {
console.log(teacherKey);//遍历属性名
console.log(Teacher[teacherKey]);//遍历属性值(只能用中括号,用点没用)
}
//在全局中,this指向window对象
console.log(this);
Second method: use constructor:
1. Use factory methods to create objects in batches (reference, not recommended)
function CreateObj(age, sex) {
let obj =
{
Age: age,
Sex: sex,
ShowMes: function () {
console.log("age:" + this.Age + " " + "Sex:" + this.Sex);
}
}
return obj;
}
let obj1 = CreateObj("13", "Male");
let obj2 = CreateObj("11", "Female");
obj1.ShowMes();
obj2.ShowMes();
2. Create objects using constructors
//声明一个函数,那么浏览器就会在内存中创建一个原型对象,而且每个函数都默认会有一个属性 prototype 指向了这个对象
//通过构造函数new的对象会存在一个默认的不可见的属性,来指向了构造函数的原型对象。 这个不可见的属性我们一般用 [[prototype]] 来表示,只是这个属性没有办法直接访问到。
function Person(firstname, lastname) {
//在JavaScript中,this通常指向的是我们正在执行的函数本身,或者是指向该函数所属的对象(运行时)
this.firstname = firstname;
this.lastname = lastname;
this.changeFirstname = changeFirstname;
this.age;
//js的构造函数除了定义对象的属性也能定义方法
//方法只不过是附加在对象上的函数。
function changeFirstname(changeFirstname) {
this.firstname = changeFirstname;
}
//prototype存在于构造函数中(括号外也可以访问到),他指向了这个构造函数的原型对象。
///给Person函数的原型对象中添加属性
Person.prototype.firstname = "Wang";
Person.prototype.lastname = "Er";
Person.prototype.age = "24";
}
//new 和不 new的区别:
//如果 new 了函数内的 this 会指向当前这个 Person 并且就算函数内部不 return 也会返回一个对象。
//如果不 new 的话函数内的 this 指向的是 window。
let person01 = new Person("Zhang", "San");
console.log("FirstName:" + person01.firstname + ",LastName:" + person01.lastname);
person01.changeFirstname("Li");
console.log("FirstName:" + person01.firstname + ",LastName:" + person01.lastname);
//构造方法创建的对象通过__proto__属性访问原型对象
console.log("原型对象的FirstName:" + person01.__proto__.firstname + ",LastName:" + person01.__proto__.lastname);
//访问person01中的一个属性age,如果在该对象中找到,则直接返回。如果该对象中没有找到,
// 则直接去person01对象的[[prototype]]属性指向的原型对象中查找,如果查找到则返回。(如果原型中也没有找到,则继续向上找原型的原型—原型链。)
console.log("原型对象的age:" + person01.age);//因为没有给person01的age属性赋值,所以找到输出的是原型对象的值
person01.age = "14";
console.log("person01的age:" + person01.age);//给person01 age属性赋予值之后,无法再通过它访问原型对象的属性
//可以通过函数的prototype属性给对象的构造函数添加新的属性
Person.prototype.Sex = "Male";
console.log("原型对象的Sex:" + person01.Sex);
//当然也可以给对象的构造函数添加新的方法
Person.prototype.SaySex = function () {
console.log("性别是:" + this.Sex);
}
person01.__proto__.SaySex();//等同于person01.SaySex();因为person01没有实现该方法,所以指向它的原型对象的该方法(和上文写的属性原理是一样的)
//constructor属性存在于原型对象中,该属性指向构造函数
console.log(Person.prototype.constructor === Person);//true
直接给Person构造函数的原型对象指定对象字面量的话,则这个函数的原型对象的constructor属性不再指向该函数(但是构造函数还是指向该原型对象的)
Person.prototype = {
Score: 75
//如果constructor对你很重要,应该在Person.prototype中添加一行这样的代码--让constructor重新指向Person函数
//constructor : Person
};
let person02 = new Person("Zhi", "ling");
console.log("原型对象的分数:" + person02.__proto__.Score);//验证此时构造函数依然指向原型对象
console.log(Person.prototype.constructor === Person);//false 原型对象不再指向构造函数
//hasOwnProperty方法,可以判断一个属性是否来自对象本身
console.log(person02.hasOwnProperty("Age"));//false person02没有赋予age属性值(但原型对象有,如果此时调用输出的就是原型对象的age值了)
//为对象添加私有属性(通过构造函数生成的实例对象有什么用?最主要的作用就是用来存放实例对象的公有属性和公有方法)
person01.shengao = "180cm";
console.log("person01身高:" + person01.shengao);//180cm
//判断person02是否有shengao属性(这里没有定义所以结果应该是没有)
//(VVV不推荐VVV)可以判断但是存在缺陷。最特殊的情况就是我们有该字段,而它的值偏偏就是 undefined
console.log("person02身高:" + person02.shengao);//undefined(原型链上如果某个属性不存在就会返回undefined)
//(VVV推荐VVV)使用 in 运算符,用法是属性名 in 对象,如果存在返回 true,反之为 false
console.log("person02身高真的存在吗?:" + 'shengao' in person02);//false
//函数在js中,也算是一种特殊的对象,在js中,所有函数都可以看做是Function()构造函数生成的实例对象(原型对象)
console.log(Person.constructor === Function);//true(Person看作原型对象)
//Function()函数的原型对象就是Function自己,Function对象的构造函数就是Function()函数自己
console.log(Person.__proto__ === Function.prototype);//true
console.log(Function.__proto__ === Function.prototype);//true
console.log(Function.constructor === Function);//true
**总结:**
构造函数访问原型对象:prototype
构造函数new出来的实例对象访问原型对象:__proto__
原型对象访问构造函数:constructor
声明一个函数本质上就是生成Function函数的对象