当前位置: 首页 > news >正文

查漏补缺 - 构造函数,原型,this,原型链,继承

目录

  • 1,构造函数
  • 2,原型
  • 3,this
  • 4,原型链
    • 1,特点
    • 2,Object.prototype.toString()
    • 3,instanceof 运算符
    • 4,Object.getPrototypeOf()
    • 5,创建空原型对象
    • 6,面试题
  • 5,继承
    • 封装继承

1,构造函数

1,作用:创建对象。

通过普通函数返回对象:

function createPerson(firstName, lastName) {var obj = {}obj.firstName = firstNameobj.lastName = lastNameobj.fullName = firstName + lastNameobj.myName = function () {console.log(obj.fullName)}return obj
}const person = createPerson('张', '三')

通过构造函数创建对象

function Person(firstName, lastName) {this.firstName = firstNamethis.lastName = lastNamethis.fullName = firstName + lastNamethis.myName = function () {console.log(this.fullName)}
}const person = new Person('张', '三') // 规定语法

2,js 中所有的对象,都是通过构造函数创建的。

Object() 构造函数,所以 typeof Object === 'function'

var obj = {age: 18
}// 上面是语法糖var obj = new Object()
obj.age = 18

Function()构造函数

每个 js 函数实际上都是一个 Function 对象,通过 Function 构造函数创建时(可以不加 new 关键字)。

const add= new Function("a", "b", "return a + b");
add(2, 6);

2,原型

当构造函数中定义方法时,因为每个构造出的实例都是独立的,所以每次也会创建一个新的方法。

function Foo(a, b) {this.a = athis.b = bthis.sayHi = function () {console.log(this.a + this.b)}
}const foo1 = new Foo(1, 2)
const foo2 = new Foo(1, 2)console.log(foo1.sayHi === foo2.sayHi) // false

这会造成内存空间的浪费,所以出现了原型来解决这个问题。

当访问实例成员时,先找自身,如果不存在,会自动从隐式原型中寻找。

原型也是一个对象,一般会将公共的方法放到原型上。

function Foo(a, b) {this.a = athis.b = b
}Foo.prototype.sayHi = function () {console.log(this.a + this.b)
}const foo1 = new Foo(1, 2)
const foo2 = new Foo(1, 2)console.log(foo1.sayHi === foo2.sayHi) // true

在这里插入图片描述

3,this

1,在函数中使用 this,它的指向完全取决于函数是如何调用的。具体参考

例子,为所有对象添加方法 print,并打印对象的键值对。

Object.prototype.print = function () {for (var key in this) {// 过滤掉 printif (this.hasOwnProperty(key)) {console.log(key, this[key])}}
}var obj = {a: 1,b: 2
}console.log(obj.print())

2,hasOwnProperty

表示对象自有属性(而不是继承来的属性)中是否具有指定的属性。

3,in 运算符

判断属性名是否在对象自身及其原型链上。

4,原型链

在这里插入图片描述

1,特点

  1. Object.prototype 上添加属性,会影响到所有对象,包括函数和数组。

  2. Function.prototype 上添加属性,会有影响到所有函数,所以可以判断一个变量是不是函数。

Function.prototype.isFun = truevar obj = {}
function fun() {}console.log(obj.isFun) // undefined
console.log(fun.isFun) // true

2,Object.prototype.toString()

MDN - Object.prototype.toString()

会把对象转为字符串格式 [object Object],但这种格式并不是每个对象想要的。

所以数组重写了 toString 方法

Array.prototype.toString === Object.prototype.toString // false

如何让数组的 toString 方法使用 Object.prototype.toString

const arr = [1,2,3]
Object.prototype.toString.call(arr)

所以判断一个变量是不是数组的方法:

const arr = [];
console.log(Object.prototype.toString.call(arr)); // [object Array]

如果自己的构造函数希望改变 toString,如何改变?

function User() {}
const user = new User();User.prototype.toString = function () {return "xxx";
};console.log(user.toString()); // xxx

3,instanceof 运算符

MDN - instanceof 运算符

用于检测构造函数的 prototype,是否出现在某个实例对象的原型链上。

function User() {}var user = new User()console.log(user instanceof User) // true
console.log(user instanceof Object) // true

o in C 更多的用来判断对象 o 是不是构造函数 C 的创建的实例。

所以,可以这样理解:

obj instanceof Array // obj 是不是数组
obj instanceof Object // obj 是不是对象
obj instanceof Function // obj 是不是函数

4,Object.getPrototypeOf()

Object.getPrototypeOf()

因为不推荐使用 __proto__,所以有了新的方法来操作隐式原型:Object.getPrototypeOf()Object.setPrototypeOf()

const arr = [];
console.log(Object.getPrototypeOf(arr) === arr.__proto__); // true

5,创建空原型对象

方法1,

const obj = {}
obj.__proto__ = null // 不推荐 直接操作 __proto__Object.setPrototypeOf(obj, null) // 可以使用

方式2,

const obj = Object.create(null)

6,面试题

下面的面试题,都可以用上面的原型链图快速解释。

// 下面的代码输出什么?(京东)
Function.prototype.a = 1;
Object.prototype.b = 2;function A() {}var a = new A();console.log(a.a, a.b); // undefined 2
console.log(A.a, A.b); // 1 2
// 下面的代码输出什么?(字节)
console.log({} instanceof Object); // true
console.log({}.toString instanceof Function); // true
console.log(Object instanceof Function); // true
console.log(Function instanceof Object); // true
// 下面的代码输出什么?
function User() {}
User.prototype.sayHello = function () {};var u1 = new User();
var u2 = new User();console.log(u1.sayHello === u2.sayHello); // true
console.log(User.prototype === Function.prototype); // false
console.log(User.__proto__ === Function.prototype); // true
console.log(User.__proto__ === Function.__proto__); // true
console.log(u1.__proto__ === u2.__proto__); // true
console.log(u1.__proto__ === User.__proto__); // false
console.log(Function.__proto__ === Object.__proto__); // true
console.log(Function.prototype.__proto__ === Object.prototype.__proto__); // false
console.log(Function.prototype.__proto__ === Object.prototype); // true

5,继承

假设有一个会员系统

  • 免费用户
    • 属性:用户名,密码
    • 方法:播放免费视频
  • vip 用户
    • 属性:还有会员过期时间
    • 方法:还有播放vip视频
function User(name, pwd) {this.name = namethis.pwd = pwd
}User.prototype.playFreeVideo = function() {console.log('免费视频');
}function VipUser(name, pwd, expires) {this.name = namethis.pwd = pwdthis.expires = expires
}VipUser.prototype.playFreeVideo = function() {console.log('免费视频');
}VipUser.prototype.playVipVideo = function() {console.log('vip视频');
}

可以看到有冗余的代码。改造下

1,处理构造函数内部的重复。

function VipUser(name, pwd, expires) {User.call(this, name, pwd)this.expires = expires
}

2,处理原型上的重复

需要一个图来表现关系

// VipUser.prototype.__proto__ = User.prototype
Object.setPrototypeOf(VipUser.prototype, User.prototype)

继承就是上面这种关系。

  • 子类的实例,应该自动拥有父类的所有成员。
  • 子类最多只有一个父类
  • 间接父类的成员,会传递给子类

封装继承

function inherit(Child, Parent) {Object.setPrototypeOf(Child.prototype, Parent.Parent)
}
http://www.lryc.cn/news/146660.html

相关文章:

  • C# 学习笔记--个人学习使用 <2>
  • Linux网络编程Socket通信6-Libevent移植与使用
  • c#:委托 泛型委托的使用 泛型约束
  • 大数据之linux入门
  • MPI之MPI_Sendrecv接口以及空进程概念介绍
  • Revit SDK:PointCurveCreation 创建点来拟合曲线
  • 嵌入式Linux开发实操(十五):nand flash接口开发
  • vue2 组件库之vetur提示
  • 慕课网 Go工程师 第三周 package和gomodules章节
  • 【ES6】JavaScript 中的数组方法reduce
  • 数据结构--树4.2(二叉树)
  • 详解Numpy(基于jupyter notbook)
  • uniapp实现:点击拨打电话,弹出电话号码列表,可以选择其中一个进行拨打
  • swc-loader Segmentation fault “$NODE_EXE“ “$NPM_CLI_JS“ “$@“
  • Leetcode78. 子集
  • 百度“AI智障”到AI智能体验之旅
  • R中当并行运算遇到C++函数时,让foreach+Rcpp一起工作
  • 实现带头双向循环链表
  • Mysql 表字符集变更
  • golang抓取tcp包的实现
  • oauth2.0第2季 分布式认证与授权实现单点登录
  • SpringBoot一些困惑及梳理
  • PostgreSQL汉字转拼音首字母
  • HBuilderX修改manifest.json设置,解决跨域问题(CORS、Cross-Origin)
  • AR地图微信小程序:数字化时代下地图应用的新突破
  • 成集云 | 抖店客户静默下单催付数据同步钉钉 | 解决方案
  • C++中的运算符总结(5):按位逻辑运算符
  • 《异常检测——从经典算法到深度学习》22 Kontrast: 通过自监督对比学习识别软件变更中的错误
  • 大数据风控介绍
  • Linux内核学习(九)—— 虚拟文件系统(基于Linux 2.6内核)