个人笔记——面向对象(创建对象、原型、继承),未完待续...
一、创建对象
1.构造函数object()来创建
var obj = new object();
obj.name='tom'
2. 字面量创建
var obj ={
name: " tom"
}
obj .sex='boy';
3.工厂函数方法创建
function createPerson(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
console.log(this.name);
};
return o;
}
var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");
4. 自定义构造函数创建
function Students(name,age){
this.name = name;
this.age = age;
this.sayName = function(){
console.log(this.name);
};
}
var p= new Students("tom",19);
5. 原型模式创建---重点笔记
function Students(name,age){
this.name = name;
this.age = age;
this.sayName = function(){
console.log(this.name);
};
}
var p= new Students("tom",19);
二、对象的方法(defineProperty)和属性
1、方法:Object.defineProperty(),vue2.0钱的双向绑定用的就是这个,之后改用了更强大的Proxy
(1)、这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符(descriptor)对象的属性必须是:configurable、enumerable、writable 和 value。设置其中的一或多个值,可以修改对应的特性值。
(2)属性列表:
a、configurable:表示能否通过 delete 删除属性从而重新定义属性,默认true,false不可删除;
b、enumerable:表示能否通过 for-in 循环返回属性,默认true,false不可返回;
c、writable:表示能否修改属性的值,默认true,false不可修改;
d、value:包含这个属性的数据值,默认true,默认值为 undefined。
(3)、语法,例如:
var person = {};
Object.defineProperty(person, "name", {
writable: false,
value: "Nicholas"
});
console.log(person.name); //"Nicholas"
person.name = "Greg";
console.log(person.name); //"Nicholas"
(3)、访问器属性:get 和set函数
a、get:在读取属性时调用的函数,默认值为 undefined;
b、set:在写入属性时调用的函数,默认值为 undefined
var book = {
age: 2004,
edition: 1,
name:"西游记",
};
Object.defineProperty(book, "year", {
get: function() {
console.log("defineProperty——读取属性");
return this.age;
},
set: function(newValue) {
console.log("defineProperty——写入属性");
if (newValue > 2004) {
this.age = newValue;
this.edition += newValue - 2004;
}
}
});
book.name = '三国演义'
console.log(book.name);
const proxy = new Proxy(book, {
get(target, key) {
console.log("Proxy——读取属性")
return target[key]
},
set(target, key, value) {
console.log("Proxy——写入属性")//可以打印出来
target[key] = value
callback(key, value)
}
})
book.name = '三国演义'
console.log(proxy.name);
总结:由此可见,我们可以利用属性方法对对象的一些属性做一些特定的要求,比如禁止修改、删除操作,还可以利用访问器 get 和set函数对对象的已有属性进行拦截,然后做一些满足我们需求的操作,但是defineProperty只能监听到已存在的属性,对于对象属性的删除和添加无法监听到。
三、对象的读取属性的特性--Object.getOwnPropertyDescriptor()方法
介绍:该方法接收两个参数:属性所在的对象和要读取其描述符的属性名称,返回值是一个对象。如果
是访问器属性,这个对象的属性有 configurable、enumerable、get 和 set;如果是数据属性,这
个对象的属性有 configurable、enumerable、writable 和 value。
1、语法:
Object.getOwnPropertyDescriptor(obj, prop);
obj 需要查找的目标对象
prop 目标对象内属性名称
2、数据属性:如果属性不存在访问的对象身份 则返回undefined
var book = {
age: 2004,
edition: 1,
name: "西游记",
};
let descriptor = Object.getOwnPropertyDescriptor(book, 'age');//访问数据属性
console.log(descriptor);
//返回:configurable: true enumerable: true value: 2004 writable: true
3、访问器属性:如果属性不存在访问的对象身份 则返回undefined
var book = {
age: 2004,
edition: 1,
name: "西游记",
};
Object.defineProperty(book,'age',{
get:function(){
return this.age
},
set:function(){
this.age='520'
}
})
let descriptor = Object.getOwnPropertyDescriptor(book, 'age');//访问数据属性
console.log(descriptor);//返回结果有:configurable、enumerable、get 和 set
此时:不可以设置对象数据属性 writable和value的描述,因为get 函数作用是读取这个
对象数据属性, set是修改和添加作用。如果此时设置value和writable,存在冲突问题,程序会报错。
总结:getOwnPropertyDescriptor 作用主要是查看指定对象所在的某个属性具体的描述属性情况。
四、原型
1、通过构造函数创建对象 ,每个函数都会有prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
function Student() {}
function Teacher() {};
Student.prototype.name = '张飞';
Student.prototype.age = '28';
Student.prototype.sayName = function() {
//this指向构造函数Student 后面会打印undefined 是因为 sayName 方法没有返回值
console.log(this.name)
}
let p1 = new Student();
let p2 = new Student();
let t1 = new Teacher();
console.log(p1)
console.log(p2)
console.log(p1.sayName()) //张飞
console.log(p2.sayName()) //张飞
console.log(p1.sayName == p2.sayName) //true
console.log(p1.prototype == p2.prototype) //true
// p1和p2的 constructor都指向Student函数
console.log(Student.prototype.isPrototypeOf(p1)); //true
console.log(Student.prototype.isPrototypeOf(p2)); //true
console.log(Student.prototype.isPrototypeOf(t1)); //false
p1、p2、Student,三者直接的关系图:
1600408809(1).jpg
小结:
a、当访问p.name的时候,会进行2次搜索,先看自身有没有该属性,有则返回,没有再往其原型上查找。
b、p1和p2对象实例都可以访问保存在原型中的值,指向Student的prototype,因此可以直接使用该原型上所有的属性和方法,可以用 isPrototypeOf 去检测调用对象是否在另一个对象的原型链上,利用Object.getPrototypeOf(p1) 可以返回p1对象的所有原型。
2、hasOwnProperty() 、 in操作符 、 hasPrototypeProperty()
a、 hasOwnProperty() 用于检测访问的某个属性,是实例自身的属性,还是访问到了是原型属性
语法:object.hasOwnProperty(propertyName)
参数说明:propertyName 参数表示要检测的属性名称。
返回值:返回一个布尔值。如果 propertyName 是自有属性,那么返回 true,否则返回 false。
function Student(){};
Student.prototype.name='赵云';
let p=new Student();
console.log(p.hasOwnProperty("name"))//false
p.name='赵云';
console.log(p.hasOwnProperty("name"))//true
console.log(p.hasOwnProperty("age"))//false
小结:第一个返回false是因为这个属性在该实例的原型身上,第二个返回true,
这个实例自身有这个属性,第三个是它自身和原型上都没有,肯定返回false
b、in操作符in 操作符会在通过对象能够访问给定属性时返回 true,无论该属性存在于实例中还是原型中。
function People() {};
People.prototype.name = '诸葛亮';
let p = new People();
console.log("打印1:", p.hasOwnProperty('name'))//false
console.log("打印2:", 'name' in p)//true
总结 :in 操作符只要通过对象能够访问到属性就返回 true,hasOwnProperty()只在属性存在于实例中时才返回 true
五、继承
//1、继承:
function People() {
this.sex = '男';
}
People.prototype.age = '18';
People.prototype.SayHi = function() {
console.log('hi')
}
function Heart() {}
Heart.prototype = new People();
let h1 = new Heart();
console.log(h1)
//2、 call,apply继承,无法继承构造函数原型链上的方法属性
function People() {
this.sex = '男';
}
People.prototype.age = '18';
People.prototype.SayHi = function() {
console.log('hi')
}
function Heart() {
People.call(this);
// this.__proto__ = People.prototype 用此方法来继承构造函数原型链上的方法属性
}
let h1 = new Heart();
console.log(h1)
//3、 组合继承(伪经典继承)弊端会调用两次超类(构造函数)
function aA(name) {
this.name = name || '';
this.sex = 18
}
aA.prototype.heaght = '170'
function bB(name, age) {
aA.call(this, name);
this.age = age;
}
bB.prototype = new aA();
let b = new bB('诸葛亮', 26);
console.log(b)
// 4、寄生组合式继承
function inheritPrototype(subType, superType) {
var myprototype = Object(superType.prototype); //创建对象
myprototype.constructor = subType; //增强对象
subType.prototype = myprototype; //指定对象
}
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function() {
console.log(this.age);
};
let sub1 = new SubType('诸葛亮',36)
console.log(sub1);