学习《JavaScript高级程序设计》----day08


一、理解对象

点击前往查看

二、理解原型

1.原型与构造函数、对象之间的关系

  1. 无论何时,只要创建一个函数,就会按照特定的规则为这个函数创建一个prototype属性(指向原型对象)。

  2. 原型对象会自动获取一个名为constructor的属性,指向与之关联的构造函数。例如Person.prototype.constructor指向Person。

  3. 在自定义构造函数时,原型对象默认只会获得constructor属性,其它的所有方法都继承自Object。

  4. 构造函数有一个prototype属性引用其原型对象,而这个原型对象也有一个constructor属性引用这个构造函数,两者循环引用。

    function Person(){}
    console.log(typeof Person.prototype);
    console.log(Person.prototype.constructor === Person);//true
    
    //Object原型的原型是null
    console.log(Object.prototype.__proto__ === null);//true
    
    //正常的原型链都会终止与Object
    console.log(Person.prototype.__proto__ === Object.prototype);//true
    
    //实例通过__proto__链接到原型对象
    const person = new Person();
    console.log(person.__proto__.constructor === Person);//true
    
    //构造函数通过prototype链接到原型对象
    console.log(Person.prototype === person.__proto__);//true
    
    //同一个构造函数创建的多个实例共享同一个原型对象
    const p1 = new Person();
    const p2 = new Person();
    console.log(p1.__proto__ === p2.__proto__);//true
    console.log(person.__proto__ ==p1.__proto__);//true
    
    //构造函数的原型与其实例的原型对象是同一个
    console.log(p1.__proto__ === Person.prototype);//true
    

2.原型的相关方法

  1. isPrototypeOf():确定两个对象之间的原型关系。
    //isPrototypeOf()
    console.log(Person.prototype.isPrototypeOf(p1));//true
    
  2. Object.getPrototypeOf():返回原型对象。
    //Object.getPrototypeOf()
    console.log(Object.getPrototypeOf(p1) === Person.prototype);//true
    

3.原型层级

  1. 在访问对象的属性和方法是会按照原型层级(原型链)来搜索==。例如,访问对象p的属name,如果该对象自身有该属性,则返回该属性值,否则会去搜索p的原型对象q是否包含该属性,依此不断搜索,直到搜索Object的原型对象中是否包含有该属性。
    //原型层级(原型链)---访问属性
    function Dog(){}
    Dog.prototype.name = "小灰";
    const dog1 = new Dog();
    const dog2 = new Dog();
    dog1.name = "小黄";
    console.log(dog1.__proto__ === dog2.__proto__);//true
    console.log(dog1.name);//小黄,来自实例dog1
    console.log(dog2.name);//小灰,来自原型对象
    
  2. hasOwnProperty():确定某个属性是否来自实例或者来自原型。
    //hasOwnProperty()
    console.log(dog1.hasOwnProperty("name"));//true
    console.log(dog2.hasOwnProperty("name"));//false
    
  3. Object.getOwnPropertyNames():获取对象的所有属性名(无论是否可以枚举)。
    //Object.getOwnPropertyNames()
    console.log(Object.getOwnPropertyNames(dog1));//['name']
    console.log(Object.getOwnPropertyNames(dog1.__proto__));//["constructor", "name"]
    console.log(Object.getOwnPropertyNames(Object));
    
  • 注意:Object.getOwnPropertyDescriptor()方法只对实例对象有效。要得到原型的属性描述符,必须在原型对象上使用该方法。

4.原型和in操作符:

  • in:
    该操作符可以确定某个属性是否在实例中或在实例的原型中,在就返回true;否则返回false。
    //in操作符
    console.log("name" in dog1);//true,name来自实例
    console.log("name" in dog2);//true,name来自原型
    
    //通过hasOwnProperty()和in操作符确定属性是否存在于原型中
    console.log(!dog2.hasOwnProperty("name") && ("name" in dog2));//true
    
  • for-in
    在循环中使用,循环迭代对象属性(可枚举属性)。
    //for-in
    for(const property in dog1){
    	console.log(property);
    }
    
  • 属性枚举
    1.for-in、Object.keys()这两个方式枚举顺序是不确定的。
    2.Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()、Object.assign()枚举的顺序是确定的。
  • 对象迭代
    Object.keys()Object.values()Object.entries()
    //对象迭代
    const o = {
    	name:'bar',
    	baz:"1",
    	arr:[1, 2, 3],
    	obj:{}
    };
    
    //Object.keys()
    for(const key of Object.keys(o)){
    	console.log(key);
    }
    
    //Object.values()
    for(const val of Object.values(o)){
    	console.log(val);
    }
    
    //Object.entries()
    for(const [key, val] of Object.entries(o)){
    	console.log(key, val);
    }
    

三、创建对象

1.工厂模式

该模式的不足就是没有解决新创建的对象是什么类型。
//示例1---工厂模式创建对象
function createObject(name, age, gender){
	const o = {};
	o.name = name;
	o.age = age;
	o.gender = gender;
	o.sayHello = function(){
		console.log(`"Hello, I'm ${this.name}"`);
	}
	return o;
}
const obj1 = createObject("Lili", 23, "女");
console.log(obj1);
obj1.sayHello();

2.构造函数模式

  1. 通过使用new操作符加构造函数创建对象。使用new 后,会进行以下几个操作:
    1.在内存中创建一个新对象。
    2.这个新对象的[[Prototype]]特性被赋值为构造函数的prototype属性。
    3.构造函数的this指向这个新对象
    4.执行构造函数内部的代码。
    5.如果构造函数返回非空对象,则返回该对象;否则返回这个新对象。
    //示例2---构造函数创建对象
    function Person(name, age, gender) {
    	this.name = name;
    	this.age = age;
    	this.gender = gender;
    	this.sayHello = function(){
    		console.log(`"Hello, I'm ${this.name}"`);
    	}
    }
    const obj2 = new Person("Liling",24,"男");
    const obj3 = new Person("Liming",24,"男");
    console.log(obj2);
    console.log(obj2.sayHello === obj2.sayHello);//false
    obj2.sayHello();
    
  2. 构造函数的问题:
    定义在构造函数内部的方法没有被它的每个实例所共享,而是没创建一个实例都会为其创建相应的方法。
    //示例2---构造函数创建对象(改进)
    function Person(name, age, gender) {
    	this.name = name;
    	this.age = age;
    	this.gender = gender;
    	this.sayHello = sayHello;
    }
    function sayHello(){
    	console.log(`"Hello, I'm ${this.name}"`);
    }
    const obj2 = new Person("Liling",24,"男");
    const obj3 = new Person("Liming",24,"男");
    console.log(obj2);
    console.log(obj2.sayHello === obj2.sayHello);//true
    obj2.sayHello();
    

3.原型模式

  1. 主要是利用函数的prototype来共享方法和属性。
    //示例3---原型模式
    function Dog(){}
    Dog.prototype.eat = function() {
    	console.log("eating bone!!");
    };
    Dog.prototype.type = "中华田园犬";
    const dog1 = new Dog("小灰","grey");
    const dog2 = new Dog("小黄","yellow");
    console.log(dog2.eat === dog1.eat);//true
    console.log(dog1.eat());
    
  2. 原型模式的问题是它弱化了构造函数传递参数的能力。

4.组合模式

一般是混合构造函数和原型两种模式来创建对象,即私有属性在构造函数中来定义,共享属性和方法在原型中定义。

//组合模式---构造函数模式和原型模式的组合
function Cat(name, color,type){
	this.name = name;
	this.color = color;
	this.type = type;
}
Cat.prototype.eat = function(){
	console.log("eats fish!");
}
const cat1 = new Cat("喵喵", "grey", 1);
const cat2 = new Cat("小喵", "yellow", 2);
console.log(cat1.__proto__ === cat2.__proto__);//true
cat1.eat();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值