IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> JS面向对象编程 -> 正文阅读

[JavaScript知识库]JS面向对象编程

目录

1.创建对象

ECMAScript中没有类的概念,可以把 ECMAScript的对象想象成一张散列表,其中的内容就是一组名/值对
属性的类型分两种:数据属性和访问器属性

(1)工厂模式:每次返回都会返回包含属性和方法的对象

function createPerson(name, age, job) {
    let o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function() {
        console.log(this.name);
    };
    return o;
}
let person1 = createPerson("Nicholas", 29, "Software Engineer");
let person2 = createPerson("Greg", 27, "Doctor");

(2)构造函数模式

person1 和 person2 分别保存着 Person 的不同实例。这两个对象都有一个constructor 属性指向 Person?

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function() {
        console.log(this.name);
    };
}
let person1 = new Person("Nicholas", 29, "Software Engineer");
let person2 = new Person("Greg", 27, "Doctor");
person1.sayName(); // Nicholas
person2.sayName(); // Greg

constructor属性instanceof 操作符都可以用来确定对象类型?

console.log(person1.constructor == Person); // true
console.log(person1 instanceof Person); // true

优点:相比于工厂模式,自定义构造函数可以确保实例被标识为特定类型
缺点:?其定义的方法会在每个实例上都会重新创建一遍

(3)原型模式?

每个函数都会创建一个 prototype 属性,这个属性指向一个原型对象。该对象可以让所有对象实例共享一些属性和方法。?
原型对象有一个名为 constructor 的属性,指回与之关联的构造函数。
每次调用构造函数创建一个新实例,该实例内部的[[Prototype]]指针就会指向构造函数的原型对象。
也就是说:实例与构造函数原型之间有直接的联系,但与构造函数之间没有。

function Person() {} //使用函数表达式也可以let Person = function() {};
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function() {
    console.log(this.name);
};
let person1 = new Person();
person1.sayName(); // "Nicholas"
let person2 = new Person();
person2.sayName(); // "Nicholas"
console.log(person1.sayName == person2.sayName); // true

isPrototypeOf()方法可以确定对象实例和构造函数之间的关系

console.log(Person.prototype.isPrototypeOf(person1)); // true

Object.getPrototypeOf() 方法,返回对象实例的内部特性[[Prototype]]的值,也就是原型对象。

console.log(Object.getPrototypeOf(person1) == Person.prototype); // true

通过对象访问属性时,会先搜索对象实例本身,如果该实例上有指定属性,则返回对应的值。如果没有,就会沿着指针进入原型对象,到原型对象上继续搜索。?

hasOwnProperty() 方法用于确定某个属性是在实例上还是在原型对象上,在实例上返回true,在原型对象上返回false。

//还是上面那个构造函数
let person1 = new Person();
let person2 = new Person();

person1.name = "Greg";
console.log(person1.hasOwnProperty("name")); // true

console.log(person2.name); // "Nicholas",来自原型
console.log(person2.hasOwnProperty("name")); // false

delete person1.name; //delete可以删除实例上的属性
console.log(person1.hasOwnProperty("name")); // false

原型和 in 操作符?

in 操作符会在可以通过对象访问指定属性时返回 true ,无论该属性是在实例上还是在原型上。

// 确定某个属性是否存在于原型上
function hasPrototypeProperty(object, name){
    return !object.hasOwnProperty(name) && (name in object);
}

for-in循环中使用in操作符,可通过对象访问且可被枚举的属性都会返回,包括实例属性和原型属性。?
获得对象上所有可枚举的实例属性,可以使用 Object.keys()
想列出所有实例属性,无论是否可以枚举,可使用Object.getOwnPropertyNames()

更简单的写法

function Person() {
}
Person.prototype = {
    //用字面量的形式创建创建一个原型对象,此时constructor属性指向Object对象
    //所以这里要指回去
    constructor: Person, 
    name: "Nicholas",
    age: 29,
    job: "Software Engineer",
    sayName() {
        console.log(this.name);
    }
};

缺点:原型上的所有属性是在实例间共享的,但一般来说,不同的实例应该有属于自己的属性副本

(4)组合使用构造函数模式和原型模式

构造函数用于定义实例属性
原型对象用于存放共享的方法和属性

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Shelby", "Court"];
}
Person.prototype = {
    constructor: Person,
    sayName: function() {
        console.log(this.name);
    }
}
let person1 = new Person("Nicholas", 29, "Software Engineer");
let person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Court,Van"
alert(person2.friends); //"Shelby,Court"

2.继承

①原型链?

由于接口继承只继承方法签名,而由于JS中的函数没有签名,所以JS无法实现接口继承
可以依靠原型链来实现继承
基本思想:?利用原型让一个引用类型继承另一个引用类型的属性和方法
所有引用类型都继承自 Object ,这也是通过原型链实现的

function SuperType() {
    this.property = true;
}
SuperType.prototype.getSuperValue = function() {
    return this.property;
};
function SubType() {
    this.subproperty = false;
}
// 继承 SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function () {
    return this.subproperty;
};
let instance = new SubType();
console.log(instance.getSuperValue()); // true

?确定原型与继承关系

// instanceof 操作符
console.log(instance instanceof Object); // true
console.log(instance instanceof SuperType); // true
console.log(instance instanceof SubType); // true
// isPrototypeOf() 方法
console.log(Object.prototype.isPrototypeOf(instance)); // true
console.log(SuperType.prototype.isPrototypeOf(instance)); // true
console.log(SubType.prototype.isPrototypeOf(instance)); // true

以对象字面量方式创建原型方法会破坏之前的原型链

// 继承 SuperType
SubType.prototype = new SuperType();
// 通过对象字面量添加新方法,这会导致上一行无效
SubType.prototype = {
    getSubValue() {
        return this.subproperty;
    },
    someOtherMethod() {
        return false;
    }
};
let instance = new SubType();
console.log(instance.getSuperValue()); // 出错!

问题

①对象实例共享所有继承的属性和方法
②在创建子类型的实例时,不能向超类型的构造函数中传递参数?

②借用构造函数

基本思路:在子类构造函数中调用父类构造函数。
相比于使用原型链的优点:可以在子类构造函数中向父类构造函数传参。?

function SuperType(name){
    this.name = name;
}
function SubType() {
    SuperType.call(this, "Nicholas"); // 继承 SuperType 并传参
    this.age = 29; // 实例属性
}
let instance = new SubType();
console.log(instance.name); // "Nicholas";
console.log(instance.age); // 29

问题:必须在构造函数中定义方法,因此函数不能重用。

③组合继承

综合了原型链和盗用构造函数

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);     // 第二次调用SuperType构造函数
    this.age = age;
}
// 继承方法
SubType.prototype = new SuperType(); // 第一次调用SuperType构造函数
SubType.prototype.sayAge = function() {
    console.log(this.age);
};

let instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
console.log(instance1.colors); // "red,blue,green,black"
instance1.sayName(); // "Nicholas";
instance1.sayAge(); // 29
let instance2 = new SubType("Greg", 27);
console.log(instance2.colors); // "red,blue,green"
instance2.sayName(); // "Greg";
instance2.sayAge(); // 27

?问题:会调用两次超类型的构造函数,见上

④寄生式组合继承

function inheritPrototype(subType, superType) {
    let prototype = object(superType.prototype); // 创建对象
    prototype.constructor = subType; // 增强对象
    subType.prototype = prototype; // 赋值对象
}
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);
};
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-06-03 23:55:30  更:2022-06-03 23:56:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 9:09:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码