javascripta原型详解(图文)和实例演示 - Go语言中文社区

javascripta原型详解(图文)和实例演示


文章目录

1.javascript中构造函数和类
2.对象的原型(_proto_)就是构造函数的prototype
3.Object对象上的的方法
4.通过原型找到构造函数
5.判断构造函数是否在该原型链
6.call方法借用其它原型链上的方法
7.__proto__本质上是getter 和 setter
8.对象继承的实质
9.extend方法对于原型继承的封装


要点(废话)

这篇文章中,我把每个对象的原型当作其长辈,当你缺失了某项东西时候,你会去向长辈求助(大概率。。咳咳),也就是说,当你定义一个构造函数的时候,尽管在该构造函数上没有你想要的方法或者属性,但是它会向上追溯,调用父类的方法或属性

1.javascript中构造函数和类

js中创建一个对象可以字面量创建或构造函数创建
例如:

// 字面量创建对象
    var student = {
        name:"小明"
        speak:function(){
            console.log("我是",+this.name);
        }
    }

但如果需要创建多个同一类型的对象(类似于python中类的概念),使用字面量不合适,可以使用构造函数创建

// 声明构造函数的语法和普通函数相同,但是构造函数的函数名首字母大写
function Student(name,stuID){
        // 通过new调用时,构造函数中的this表示正在创建的对象
        // 在构造函数中,需要把参数赋值给创建的对象的属性
        this.name = name;
        this.stuID = stuID;
        // 属于同一类的多个对象,属性值可以不同,但是方法都是相同的
        this.study = function(){
            console.log("正在学习");
        }
    }

个人认为js中的类和构造函数并没有什么区别,唯一的区别在于写法和叫法
例如:

class Student{
	constructor(name){
		this.name = name
		
	}
	show(){
		console.log("我是一个学生,名字是:" + this.name)
	}
}
function User(){
	this.name = name
	this.show = function(name){
	console.log("我是一个学生,名字是:" + this.name)
	}
}

我们首先看构造函数(不管名称是不是大写开头)的结构,和class类的结构一致

其次是对象和数组的结构在这里插入图片描述
在这里插入图片描述

我们可以很清楚的看到,数组,对象之所以能够调用方法,这是因为他们的长辈,也就是原型链(___proto___)上有方法,他们才能调用

2.对象的原型(_proto_)就是构造函数的prototype在这里插入图片描述

3.Object对象上的的方法

更详细内容:Javascript标准参考教程

(1)静态方法(所谓“静态方法”,是指部署在Object对象自身的方法)
	1.遍历对象的属性
				Object.keys():方法返回可枚举的属性
				Object.getOwnPropertyNames():方法还返回不可枚举的属性名
	2.对象属性模型的相关方法			
				Object.getOwnPropertyDescriptor():获取某个属性的描述对象。
				Object.defineProperty():通过描述对象,定义某个属性。
				Object.defineProperties():通过描述对象,定义多个属性。
	3.控制对象状态的方法
				Object.preventExtensions():防止对象扩展。
				Object.isExtensible():判断对象是否可扩展。
				Object.seal():禁止对象配置。
				Object.isSealed():判断一个对象是否可配置。
				Object.freeze():冻结一个对象。
				Object.isFrozen():判断一个对象是否被冻结。
	4.原型链相关方法
				Object.create():该方法可以指定原型对象和属性,返回一个新的对象。
				Object.getPrototypeOf():获取对象的Prototype对象。
(2)Object 的实例方法(定义在Object.prototype对象上,并且所有Object的实例对象都继承了这些方法)
		Object.prototype.valueOf():返回当前对象对应的值。
		Object.prototype.toString():返回当前对象对应的字符串形式。
		Object.prototype.toLocaleString():返回当前对象对应的本地字符串形式。
		Object.prototype.hasOwnProperty():判断某个属性是否为当前对象自身的属性,还是继承自原型对象的属性。
		Object.prototype.isPrototypeOf():判断当前对象是否为另一个对象的原型。
		Object.prototype.propertyIsEnumerable():判断某个属性是否可枚举。

4.通过原型找到构造函数

此处参考了七月老师的代码

class A {
    constructor() {
        this.nameA = 'a'
    }
    validateA() {
        console.log("A")
    }
}

class B extends A {
    constructor() {
        super()
        this.nameB = 'b'
    }

    validateB() {
        console.log("B")
    }
}

class C extends B {
    constructor() {
        super()
        this.nameC = 'c'
    }

    validateC() {
        console.log("C")
    }
}

function findMembers(instance, fieldPrefix, funcPrefix) {

    // 递归函数
    function _find(instance) {
         //基线条件(跳出递归)
        if (instance.__proto__ === null)
            return []

        let names = Reflect.ownKeys(instance)
        names = names.filter((name)=>{
            // 过滤掉不满足条件的属性或方法名
            return _shouldKeep(name)
        })
        
        return [...names, ..._find(instance.__proto__)]
    }

    function _shouldKeep(value) {
        if (value.startsWith(fieldPrefix) || value.startsWith(funcPrefix))
            return true
    }

    return _find(instance)
}



var c = new C()

// 编写一个函数findMembers

const members = findMembers(c, 'name', 'validate')
console.log(members)

5.判断构造函数是否在该原型链

(1)instaceof
例如:在校验参数错误类型时

class ParameterException extends Error{
	constructor(){
		super()
		}
	console.log("这是参数错误类型")
}

class AuthedException extends Error{
	constructor(){
		super()
		}
	console.log("这是授权错误类型")
}
const AuthedError = new AuthedException()
const ParameterError = new ParameterException()
if(AuthedError instanceof AuthedException){
	return "这是授权错误类型"
}
if(ParameterError instanceof ParameterException){
	return "这是参数错误类型"
}

(2)Object.isPrototypeOf判断对象是否在原型链上
例如:

const a = {}
const b = {}
const c = {}

Object.setPrototypeOf(a,b) //把a的原型指向b
Object.setPrototypeOf(b,c) //把b的原型指向c
console.log(b.isPrototypeOf(a)) //true  b在a的原型链上
console.log(c.isPrototypeOf(c)) //true  c在a的原型链上
console.log(a.isPrototypeOf(c)) //false  a在不在c的原型链上

6.call方法借用其它原型链上的方法

例如:需要借用数组的filter方法,获取特殊属性的button标签

<button class="red"/>
<button>

let buttons = document.querySelectorAll('button')
Array.prototype.filter.call(buttons,item=>{
	return item.hasAttribute('red')  //得到有red属性的button标签
})

7.__proto__本质上是getter 和 setter

小结:__proto__是非正规的属性,他会自动判断你设置的是属性还是方法,因此无法直接对__proto_赋值,只能对__proto_赋值对象
在这里插入图片描述
会神奇的发现,尽管对对象的原型赋值之后,仍然无法覆盖掉原型上的方法

因此__proto__属性的实质是以下代码

const xiaoming = {
	name:"xiaoming"
	get proto(){
		return this.name
	},
	set proto(obj){
		if(obj instanceof Object){
			conole.log(obj)
		}
		
	}
}

若希望强行对__proto__赋值属性,可以如下,消除对象的原型

let xiaoming = [}`在这里插入代码片`
xiaoming = Object.create(null)
xiaoming.__proto__ = "laowang"
console.log(xiaoming.__proto__ ) // "laowang"

8.对象继承的实质

(1)利用Object.create()方法

function User(name) {
            this.name = name
        }
        User.prototype.show = function() {
            console.log(this.name)
        }

        function Student(name) {
            this.name = name

        }

        Student.prototype = Object.create(User.prototype)
        Student.prototype.constructor = Student
        let xiaoming = new Student("xiaoming")
        xiaoming.show() //xiaoming

在这里插入图片描述
该方法的实质如图所示,就是创建一个空白的原型,赋值给子类原型,使其指向父类原型

(2)直接赋值原型

Student.prototype = User.prototype
        let xiaoming = new Student("xiaoming")
        xiaoming.show()	//xaioming

9.extend方法对于原型继承的封装

function extend(sub, sup) {
            //sup是父类,sub是子类
            sub.prototype = Object.create(sup.prototype)
            Object.defineProperties(sub.prototype, "constructor", {
                value: sub,
                enumerable: false
            })
        }

最后,向大家推荐b站上后盾人的关于原型链的一门超赞的课,下面是传送门

传送门

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_44752117/article/details/104445031
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-04-11 14:26:23
  • 阅读 ( 705 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢