JS笔记-面向对象、原型

面向对象是什么?

是一种编程思想,是基于面向过程实现的,不需要关注底层是如何实现的,直接调用即可

创建对象的方式

1. 字面量创建

let obj = {
    name: "zhangsan",
    age: 18,
    like:()=>console.log("run")
}

2. 内置构造函数创建

let stu = new Object();
stu.name = "zhangsan";
stu.age = 18;
stu["like"] = ()=>console.log("run");

let variable = 'grender';
stu[variable] = '男';
console.log(stu1);  // {name: "zhangsan", age: 18, grender: "男", like: ƒ}

3. 工厂函数创建

// 构建工厂函数
function createObj(){
    var obj = new Object();
    // 往对象添加成员
    obj.name = "zhangsan";
    obj.age = "18";
    obj.like = ()=>console.log("run");
    return obj;
}

// 使用工厂函数创建对象
var objStr1 = createObj();
var objStr2 = createObj();

4. 自定义构造函数创建对象

function Person(name,age,gender){
    this.name = name;
    this.age = age;
    this.gender = gender;
}

var ps1 = new Person("zhangsan",18,"男");
var ps2 = new Person("xiaofang",17,"女");

通过new构造函数创建对象,做了以下几个事情

1. 在内存开辟了一个空间

2. 将关键字 this 指向了这个空间

3. 执行构造函数中的代码(添加数据)

4. 将 this 指向的实例对象返回

构造函数的使用

// 自定义手机的构造函数
function Phone(name, banner, size, color, price) {
    this.name = name;
    this.banner = banner;
    this.size = size;
    this.color = color;
    this.price = price;
    this.call = () => console.log('打电话....');
}

// 实例化对象
let apple1 = new Phone('苹果12', 'iphone', '6.7', '玫瑰紫', 12999);
let apple2 = new Phone('苹果13', 'iphone', '6.7', '玫瑰紫', 15999);

console.log(apple1); // 结果就是一个对象包含成员属性和值
// 对象函数调用
apple1.call(); // 打电话....
apple2.call(); // 打电话....
// 成员属性值获取
console.log(apple1.price); // 12999 
console.log(apple1["price"]); // 12999
// 对象属性的修改
apple1.price = 19999;
console.log(apple1.price); // 19999


console.log(apple1.call == apple2.call); // false
这里会发现同一个构造函数创建的方法,实现的效果一样,但是调用的是两个方法
如果创建了多个对象,则每个对象都需要给call方法开辟方法空间,造成内存冗余

原型

为了解决构造函数的缺点(多个对象使用了一样的函数,占用了多个内存空间浪费)

prototype

每一个函数自带的一个成员,是一个对象空间,即构造函数也是函数,也有这个对象空间

function Person() {}

console.log(Person.prototype) 
// 是一个对象
// Object
// constructor: ƒ Person()
// __proto__: Object

// 往该对象放入属性和属性值
Person.prototype.name = "zhangsan";
Person.prototype.sayHi = function () {
    console.log("打电话...");
}

在函数的prototype里面存储的内容,不是给函数使用的,是给函数每一个实例化对象使用的

__proto__

每一个对象都自带的一个成员,是一个对象空间,即实例化对象也是对象,也有这个对象空间

这个对象空间是给每一个对象使用的

constructor

这个属性在对象的__proto__里面,存在于原型对象中,是指当前这个对象所属的构造函数

function Person(name) {
   this.name = name;
   // this.call = function(){
   //   console.log("打电话");
   // }
}
// 在构造函数的原型对象中添加方法
Person.prototype.call = function () {
    console.log("打电话...");
}
let per1 = new Person("zhangsan");
// 向原型对象中添加方法或属性,不推荐通过对象的__proto__向原型中添加属性或方法
per1.__proto__.eat = function () {
    console.log('好吃就多吃点..');
}
let per2 = new Person("lisi");

console.log(per1);  // zhangsan 
console.log(per2);  // lisi
per1.eat() // 好吃就多吃点..
per1.call() // 打电话...

// 构造器
console.log(per1.__proto__.constructor === Person); // true
console.log(Person.prototype.constructor === Person); //true
// 将方法写到构造函数中,会造成内存的浪费
console.log(per1.call== per2.call); // true
console.log(per1.__proto__ === Person.prototype); // true

原型总结

1. 每一个函数都有prototype属性,指向构造函数的原型对象,一个标准属性

2. 每一个对象都有__proto__属性,指向创建这个对象的构造函数的原型对象,一个非标准属性

3. prototype和__proto__所属的构造函数是同一个对象空间

4. 在原型对象中都一个constructor属性,这是原型对象的构造器,constructor属性指向这个原型的构造函数

5. 创建构造函数的时候,属性写在函数体内,方法写在原型上

原型链

// 自定义构造函数
function Person(name) {
    this.name = name;
}
// 向原型对象中添加方法
Person.prototype.call = function () {
    console.log("打电话...");
}
// 实例化对象
let p1 = new Person("zhangsan");

console.log(p1);   // name: "zhangsan" __proto__
console.log(Person); // 函数体
console.log(Person.prototype);  // call()  constructor __proto__
console.log(p1.__proto__.__proto__);    // constructor.....
console.log(p1.__proto__.__proto__ === Object.prototype); // true
console.log(p1.__proto__.__proto__.__proto__); // null
console.log(Object.prototype);  // constructor.....
console.log(Object.prototype.__proto__);   // null

内置构造函数Object的prototype指向的原型对象的__proto__属性指向是一个null
原型的终点指向null


构造函数的prototype指向的原型对象和实例化对象的__proto__指向的原型是同一个
对象都有一个__proto__属性,指向原型对象
原型对象也是对象,原型对象中也有__proto__属性,指向的也是一个原型对象
原型对象的原型一直往下找,最终都会找到顶级对象Object构造函数的prototype的原型
而Object的prototype指向的原型对象的__proto__指向的是一个null
__proto__串联起来的对象链状结构叫做原型链


对象访问属性或方法的访问规则
1. 先在对象自身查找,如果有该属性或者方法则直接使用
2. 如果没有,就去__proto__原型中查找,找到直接使用
3. 如果没有,就去__proto__指向的原型中查找,找到直接使用
4. 如果没有,则继续向原先对象的原型中查找,直到找到Object的prototype指向的原型
   还是没有则返回undefined

特殊的原型链

let div = document.querySelector('div');

// 查看元素对象
console.dir(div);
console.log(div.__proto__ === HTMLDivElement.prototype);  // true
console.log(div.__proto__.__proto__ === HTMLElement.prototype); // true
console.log(div.__proto__.__proto__.__proto__ === Element.prototype); // true
console.log(div.__proto__.__proto__.__proto__.__proto__ === Node.prototype); // true
console.log(div.__proto__.__proto__.__proto__.__proto__.__proto__ === EventTarget.prototype) // true
console.log(div.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__ === Object.prototype) // true
console.log(div.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__) // null

对象的赋值

function Person(name) {
    this.name = name
}
Person.prototype.age = 18;


let p1 = new Person("zhangsan");
// 给对象赋值一个 age = 20属性
p1.age = 20;
console.log(p1.age); // 20

let p2 = new Person("lisi");
console.log(p2.age); // 18

console.log(p1);  // name:"zhangsan"  age:20
console.log(p2); // name:"lisi"   __proto__ 能看到age:18


给实例对象的属性赋值,不会改变原型中的数据
只会给这个对象动态的添加属性:属性值
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值