对象的结构、原型、原型的作用、修改原型、instanceof和hasOwn、旧类、new运算符、对象总结——JS面向对象

28 篇文章 0 订阅
21 篇文章 2 订阅

目录

一、对象的结构

二、原型

三、原型的作用

四、修改原型

五、instanceof 和 hasOwn

六、旧类

七、new运算符

八、对象总结

一、对象的结构

对象中存储属性的区域实际有两个:
        1. 对象自身

         - 直接通过对象所添加的属性,位于对象自身中

         - 在类中通过 x = y 的形式添加的属性,位于对象自身中

        2. 原型对象(prototype)

         - 对象中还有一些内容,会存储到其他的对象里(原型对象)

         - 在对象中会有一个属性来存储原型对象,这个属性叫做_ _proto_ _

         - 原型对象也负责为对象存储属性,

                当我们访问对象中的属性时,会优先访问对象自身的属性,

                对象自身不包含该属性时,才会去原型对象中寻找

                (也就是当对象自身和原型对象中含有同一个属性名时,会访问对象自身中的该属性)

        - 会添加到原型对象中的情况

                1. 在类中通过xxx(){ }方式添加的方法,位于原型中

                2. 主动向原型中添加的属性或方法

	<script>
		class Person{
			//在类中通过x = y 的形式添加的属性,位于对象自身中
			name = "孙悟空"
			age = 18
			//直接通过对象所添加的属性,位于对象自身中
			constructor(){
				this.gender = "男"//与p.address = '花果山'效果相同,均是为其添加属性
			}
			sayHello(){
				console.log("Hello,我是",this.name);
			}
		}

		const p = new Person()
        p.address = '花果山'
		p.sayHello = "嘻嘻"
		console.log(p.sayHello);//输出“嘻嘻”,若没有上一行添加的sayHello属性,
							//则输出ƒ sayHello(){console.log("Hello,我是",this.name);}
	</script>

二、原型

访问一个对象的原型对象: 对象._ _proto_ _(开头是下划线或者其他特殊的表示不希望被访问的)

                                    或    Object.getPrototypeOf(对象)  (更安全)

原型对象中的数据:

        1. 对象中的数据(属性、方法等)

        2. constructor (对象的构造函数,也就是对象所在的类)

注意:原型对象也有原型,这样就构成了一条原型链,根据对象的复杂程度不同,原型链的长度也不同,如在下面代码中的p对象和obj对象的原型链长度就不同:

        p对象的原型链:p对象  -->  原型  -->  原型  -->  null

        obj对象的原型链:obj对象  -->  原型  -->  null

	<script>
		class Person{
			name = '孙悟空'
			age = 18
			constructor(){
				this.gender = '男'
			}
			sayHello(){
				console.log("hello,我是" + this.name)
			}
		}
		const p = new Person()
		const obj = {}
		p.address = "花果山"
		console.log(p.__proto__)
		console.log(p.__proto__.__proto__)
		console.log(p.__proto__.__proto__.__proto__)
		console.log(obj.__proto__);
		console.log(obj.__proto__.__proto__);
	</script>

原型链:读取对象属性时,会优先读取对象自身属性

              如果对象中有,则使用,没有则去对象的原型中寻找

              如果原型中有,则使用,没有则去原型的原型中寻找

              直到找到Object对象的原型(Object的原型没有原型(为null))

                   如果依然没有找到,则返回undefined

注意:

作用域链,是找变量的链,找不到会报错;

原型链,是找属性的链,找不到会返回 undefined 。

三、原型的作用

所有的同类型对象它们的原型对象都是同一个

        也就意味着,同类型对象的原型链是一样的

原型的作用:

        原型就相当于是一个公共的区域,可以被所有该类实例访问,可以将一个该类实例中所有的公共属性(方法)统一存储到原型中,这样我们只需要创建一个属性,即可被所有实例访问。

JS的继承就是通过原型来实现的

        当继承时,子类的原型就是一个父类的实例

在对象中有些属性值是对象独有的,像属性(name, age , gender)每个对象都应该有自己的值

但是有些值对于每个对象来说都是一样的,像各种方法,对于一样的值没必要重复的创建

<script>
		class Person{
			//在类中通过x = y 的形式添加的属性,位于对象自身中
			name = "孙悟空"
			age = 18
			sayHello(){
				console.log("Hello,我是",this.name);
			}
		}
		class Dog{

		}
		const p = new Person()
		const p2 = new Person()
		const d = new Dog()
		console.log(p)
		console.log(p2)
		console.log(p === p2);//false
		console.log(p.__proto__ === p2.__proto__);//true
		console.log(p.__proto__ === d.__proto__);//false

	</script>
	<script>		
		class Animal{
		}
		class Cat extends Animal{
		}
        class TomCat extends Cat{

		}
        // TomCat --> cat -->  Animal实例 --> object --> object原型 -->null
		// cat --> Animal实例 --> object --> object原型 --null
		const cat = new Cat()
		console.log(cat);//Cat {}
		console.log(cat.__proto__);//Animal {constructor: ƒ}
		console.log(cat.__proto__.__proto__);//{constructor: ƒ}
		console.log(cat.__proto__.__proto__.__proto__);
		//{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
		console.log(cat.__proto__.__proto__.__proto__.__proto__);//null
	</script>

尝试:

        函数的原型链是什么样的?

        Object的原型链是什么样的? 

四、修改原型

大部分情况下不需要修改原型对象

注意:千万不要通过类的实例去修改原型

        原因:1.通过一个对象影响所有同类对象,这么做不合适

                   2.修改原型先得创建实例,这么做麻烦

                   3.危险

除了通过__proto__能访问对象的原型外,

        还可以通过类的prototype属性,来访问实例的原型

        修改原型时,最好通过类去修改

        好处:

            1. 一修改就是修改所有实例的原型

            2. 无需创建实例即可完成对类的修改

        原则:

            1. 原型尽量不要手动改

            2. 要改也不要通过实例对象去改

            3. 通过 类. prototype  属性去修改

            4. 最好不要直接给 prototype 去赋值 

	<script>
		class Person{
			name = '孙悟空'
			age = 18
			sayHello(){
				console.log('hello,我是' + this.name);
			}
		}
		class Dog {

		}
		const p = new Person()
		const p2 = new Person()
		// 通过对象修改原型,像原型中添加方法,修改后所有同类实例都能访问该方法
		// p.__proto__.run = ()=>{
		// 	console.log('我再跑~');
		// }
		console.log(Person.prototype);//访问Person实例的原型对象,相当于p.__proto__
		Person.prototype.fly = ()=>{
			console.log('我在飞~');
		}
		p.fly()
		p2.fly()
	</script>

五、instanceof 和 hasOwn

Instanceof 用来检查一个对象是否是一个类的实例

        - instanceof 检查的是对象的原型链上是否有该类实例

             只要原型链上有该类实例,就会返回true

        - Object 是所有对象的原型,所以任何对象和Object 进行 instanceof 运算都会返回 true

	<script>
		class Animal{
		}
		class Dog extends Animal{
		}
		const dog = new Dog()
		console.log(dog instanceof Dog);//true
		// dog -> animal的实例 -> Object实例 -> Object原型
		console.log(dog instanceof Animal);//true
		console.log(dog instanceof Object);//true
		const obj = Object()
		console.log(obj.__proto__);
		console.log(Object.prototype);//读取object的原型,两种方式
	</script>

in 

        - 使用 in 运算符检查属性时,无论属性在对象自身还是在原型中,都会返回true

 对象.hasOwnProperty(属性名)(不推荐使用)

        - 用来检查一个对象的自身是否含有某个属性,现在不太用这种方法了 

Object.hasOwn(对象,属性名)(推荐使用)

        - 用来检查一个对象的自身是否含有某个属性

	<script>
		class Person{
			name = '孙悟空'
			age = 18
			sayHello(){
				console.log('hello,我是' + this.name);
			}
		}
		const p = new Person()
		console.log('name' in p);//true,用 in 检查对象中是否有该属性
		console.log('sayHello' in p);//true
		console.log(p.hasOwnProperty('name'));//true
		console.log(p.hasOwnProperty('sayHello'));//false
		console.log(p.hasOwnProperty('hasOwnProperty'));//false
		console.log(p.__proto__.hasOwnProperty('hasOwnProperty'));//false
		console.log(p.__proto__.__proto__.hasOwnProperty('hasOwnProperty'));//true
		console.log(Object.hasOwn(p,'sayHello'));//false
	</script>

六、旧类

早期的JS中,直接通过函数来定义类

        - 一个函数如果直接调用 xxx( ), 那么这个函数就是一个普通函数

        - 一个函数如果通过new 调用 new xxx( ) 那么这个函数就是一个构造函数

等价于:class Person{ }

静态属性   Person.staticProperty = 'xxx'

静态方法   Person.staticMethod = function(){}

 

	<script>
		// function Person(name,age){
		// 	//在构造函数中,this表示新建的对象
		// 	this.name =name
		// 	this.age = age
		// 	// this.sayHello = ()=>{
		// 	// 	console.log(this.name);
		// 	// }
		// }
		// //向原型中添加属性(方法)
		// Person.prototype.sayHello = function(){
		// 	console.log(this.name);
		// }
		// // 静态属性
		// Person.staticProperty = 'xxx'
		// // 静态方法
		// Person.staticMethod = function(){}
		// 但是目前这样的话,对于Person的操作分段了,可能会在那一块就创建了实例对象
		// 故应采用闭包将其放在一起,如下所示
		var Person = (function(){
			function Person(name,age){
			//在构造函数中,this表示新建的对象
				this.name =name
				this.age = age
			// this.sayHello = ()=>{
			// 	console.log(this.name);
			// }
			}
		//向原型中添加属性(方法)
			Person.prototype.sayHello = function(){
			console.log(this.name);
			}
		// 静态属性
			Person.staticProperty = 'xxx'
		// 静态方法
			Person.staticMethod = function(){}
			return Person
		})()
		const p = new Person('孙悟空', 18)
		console.log(p);
		var Animal = (function(){
			function Animal(){
			}
			return Animal 
		})()
		var Cat = (function(){
			function Cat(){
			}
			// 继承Animal
			Cat.prototype = new Animal()
			return Cat
		})()
	</script>

七、new运算符

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new

- 当使用 new 去调用一个函数时,这个函数将会作为构造函数调用,

        使用new调用函数时,将会发生这些事:

        1.创建一个普通的JS对象(Object对象{ }),为方便,我们称其为新对象

        2. 将构造函数的prototype属性设置为新对象的原型

        3. 使用实参来执行构造函数,并且将新对象设置为函数中的 this

        4. 如果构造函数返回的是一个非原始值,则该值会作为new 运算的返回值返回(千万不要这么做),

            如果构造函数的返回值是一个原始值或者没有指定返回值,则新的对象将会作为返回值

           通常不会为构造函数指定返回值

	<script>
		function MyClass(){
			// var newInstance = {}
			// newInstance.__proto__ = MyClass.prototype
			// return {name:'孙悟空'}	
			return 1	
		}
		var mc =new MyClass()
		console.log(mc);
	</script>

八、对象总结

面向对象本质就是,编写代码时所有的操作都是通过对象来进行的。

        面向对象的编程的步骤:

                1.找对象

                2.搞对象(对对象进行操作)

        学习对象:

                1. 明确这个对象代表什么,有什么用

                2.如何获取到这个对象

                3. 如何使用这个对象(对象中的属性和方法)

        对象的分类:

                内建对象

                       - 由ES标准所定义的对象,比如 Object  Function String Number......

                宿主对象

                       -  由浏览器提供的对象,如document

                       - BOM、DOM

                自定义对象

                       - 由开发人员自己创建的对象

  

                       - 

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值