原型对象与对象原型,理解Function与Array和Object,在instanceof下的关联

发布时间:2024年01月11日

面向过程与面向对象

面向过程时一步一步去做一件事,面向对象是多个功能组合在一起,去完成这件事。

面向对象的特性:继承性,封装性,多态性

通过概述应该知道面向过程和面向对象的优缺点

封装性

大家要玩游戏,当对于英雄的各个属性和方法该如何存储?用对象存储。将相关的属性和方法存储到一个对象上。

但是对象如果存储函数,或者是同一个对象等会比较浪费内存。有原型对象可以节省内存,原型对象

静态变量存储在jvm的方法区,且这一块内存,看类/构造函数能调用,其他不行,在JS上,且函数存储也是存在一块内存上。变量创建的内存上。存储在原型对象上,是类的静态变量上prototype

变量存储的是对象,这个对象上的属性可以被任何一个该构造函数创建的对象来访问。

因此如果在每个对象都创造一样的函数,浪费内存,不如在原型对象上写方法只开辟一块内存。每个对象也能够使用方法。函数在不一样的内存上也不是一个。

每个方法区内的类的静态变量都自动创建了prototype对象,该对象内Constructor指向构造函数内存。只要是对象都含有__proto__属性,该属性指向构造函数的原型对象,原型对象的该属性指向构造函数父级的原型对象。

构造函数内调用时,会有隐式形参this,赋值赋得是调用的new创建对象

我们this默认赋值时看得是代码前调用的对象

如果实例对象obj.__proto__.a()调用a函数时传递的是前面obj.__proto__,是原型对象。但是__proto__可以省略,也可以找,这是赋值的是obj赋给this

作用域链是找作用域内的变量,是从内向外作用域。

作用域链是找变量,原型链是找对象上的变量时是找原型对象。每一个实例创造时都有constructor属性也是指向构造函数地址。

原型对象可以改地址,改对象,但是原型对象需要有constructor属性指向构造函数,则是constructor对象。即使改了也没事。会将实例对象的__proto__属性被赋值赋了原型对象的地址。

最高级的构造函数的原型对象是Object原型对象prototype存的是null

实例对象与不同的构造函数的原型对象关联形成的链状结构,称为原型链

每一个数组对象都能调用map等方法,对象上创建时,没有创建,是在Array原型对象上创建的,实例对象可以访问到。

typeof 字面值 整体 表示的是什么类型的字面值

问题2:

实例对象 instanceof 构造函数,实例对象的原型链是否包括该构造函数的原型对象.,

也可也是构造函数 instanceof 构造函数?

原理

A instanceof B

内部是将A._ _proto_ _是否等于 B.prototype

A._ _proto_ _ . _ _proto_ _是否等于 B.prototype

A._ _proto_ _ . _ _proto_ _. _ _proto_ _是否等于 B.prototype

到A._ _proto_ _ . _ _proto_ _. _ _proto_ _...===null

由构造函数创建的对象,原型对象的constructor指向构造函数

构造函数的_ _proto_ _指向Function函数的原型对象。

对象的__proto__指向原型对象

构造函数的prototype指向原型对象

构造函数的constructor(和对象一样,是被谁创建出来的)指向Function函数。

构造函数和Function的原型对象的constructor都指向Function函数。

Function的prototype和_ _proto_ _指向原型对象。

Function的constructor指向自身。

原型对象Array的_ _proto_ _指向继承的构造函数的原型对象Object,

Object原型对象的_ _proto_ _是null。

Function的原型对象的_ _proto_ _指向Object原型对象。

例子1

Array instanceof Array

Array. _ _proto_ _是Function函数的原型对象

Array.prototype是Array构造函数的原型对象

Array. _ _proto_ _. _ _proto_ _. _ _proto_ _===null都不等,返回false

例子2

Object instanceof Object

Object. _ _proto_ _是Function函数的原型对象

Object. _ _proto_ _. _ _proto_ _是Object构造函数的原型对象

Object.prototype是Object构造函数的原型对象

找到返回true

深拷贝和浅拷贝

开发当中我们可能需要复制一个对象,在不同的内存上存载着一样的属性和属性值。

浅拷贝

浅拷贝是复制的对象存储的变量可能与原对象指向同一个内存。

浅拷贝的方法

拷贝对象

1.Object.assgin(A,B)/展开运算符{...obj}

这种A对象内存上会存储B内存一样的属性名,但是如果属性值是基本数据类型就存储一样的值,如果是对象,存储的是地址。因此指向同一个地址。展开运算符也可以是展开对象,展开之后...obj,obj可以是对象,也可以是数组,无论是对象还是数组,展开之后内存储的是地址。

Object.values(obj)遍历,如果是对象,是将地址拿到输出成数组。

拷贝数组

2.浅拷贝 [...arr]/Array.prototype.concat()

这两个最后得到的数组都是浅拷贝得出的数组。遍历得到数组变量的值,将每个值都赋给新数组。

递归函数

递归函数是函数内写了调用自身的代码,以至于当调用一次递归函数,内部就会重复调用该函数。如果要递归函数结束,要加结束条件。

如果加了结束条件,某一次调用该函数时,结束条件使得不在进行下一次调用,这一次调用结束,着上一次调用函数执行,也会结束。最终调用函数的代码也会结束。return是结束函数执行,遇到return函数不在执行,结束。??

递归和setTimeout可以形成和setInte...一样的效果。

深拷贝

深拷贝是复制对象与原对象,属性名相同,且属性值也是一样,只不过不是一个内存执行,如果是对象,是创建了新内存存储这个。

实现深拷贝的方法

以下两个方法都能拷贝数组和对象。

1.递归
2.lodash

1.将lodash.min.js文件引入,该文件写了函数_.cloneDeep,参数写要被复制的对象。

该函数内已经书写拷贝的代码。返回值返回一个对象。

2.调用该函数。返回值就是复制的对象,已经在堆上创建了。

变量名和函数名,大写-,递归写法

.一个变量名称可以由数字、字母、下划线、美元符号($) 组成,不能由关键字,且不能数字开头

属性名可以是任何字符,如果—连接的属性名,对象【】,或者—后字母大写。

3.JSON.stringify(实例对象)

JSON.stringify(obj)最后返回值是字符串,且是将对象改为JSON字符串

JSON.parse(JSON字符串)会根据这个字符串内,创建新对象,对象的属性值即使是对象,也是new一个新对象,没有原对象的地址。

异常处理

throw

程序代码当运行到错误时,会自动弹出错误,但是有些时候,程序执行不出的错误,我们需要抛出错误,以下代码。x/y有没输入,抛出错误,但是如果不自己写代码,手动抛出错误,不会报错,我们需要报错,自己可以手动抛出错误,这种throw/系统自动抛出错误的,是不让代码继续执行,当执行到抛出错误。系统抛出错误,自动抛出,且会看是什么错误,抛出对应的错误。手动抛出错误,throw后面写字面值,将字面值输出到控制台,如果是Error对象,会更为详细。其他对象和基本数据类型一样。

try...catch...finally

try...catch和throw不一样,throw只要执行,就会停止运行,输出错误信息,但是try...catch

是try如果有错误,就去执行catch的代码,不会因为try出现的错误,系统自动抛出错误,而是去执行catch代码。try内出现的错误可以是手动throw也可以是自动throw。都会阻止抛出错误,而去执行catch代码。try内的代码能捕获错误,其他地方的都不会。catch上(e)是e是throw抛出的信息。try内执行到错误的代码就会去执行catch的代码。执行完catch的代码会去执行下一行代码。只要try有不让错误抛出,代码不再执行的功能,其他地方没有,catch内的代码和写在别处的代码一样,都是执行完就执行下一行。catch的代码和普通的代码一样,如果catch内有错误,也会自动/手动抛出,代码不再运行,如果try执行没有错误,finally的代码就在try执行完再去执行,如果执行了catch,catch如果代码块内没有return/throw的代码,会等catch执行完再去执行,如果catch有这种会在这一条语句前执行finally。catch/finally上的代码都没有捕获错误的功能和普通代码一样,写了return/throw或有原本的功能。

改变this指向

this只有函数内才有,无论什么函数都会自动形成this变量。无论是什么函数,this都是函数隐式变量,不在对象上,但是this是函数作用域上,指向实例对象。这些都是在没有

this不允许在函数执行代码上直接改变的。

但是以下方法可以改变this指向。但是构造函数new的时候this指向无法改变的new的时候就this有指向,且是不可改的。this是形参但是new的时候控制不让改。

普通函数调用时只是隐式参数传参,因此可以改。

1.call

每一个函数底层都有静态方法call,bind,apply等方法,函数.call这个方法会调用这个函数,且call调用函数时的参数的第一个会传给隐式参数this。将第二个参数,第三个参数都传给写了的形参,且一定参数都以,隔开。将,隔开的整体传。call方法内部接收到这些参数,调用时将参数依次传给函数。返回值就是fun的返回值。

2.apply

函数有静态方法apply,当调用静态方法时,执行这个函数,接收参数,只接收两个,第一个改变函数的this,后调用函数,遍历第二个数组,调用函数时将数组元素传。这个方法的返回值我们调用fun函数的返回值作为返回值。

apply与call的区别就是写方法,参数是数组是否。

3.bind方法

前两个方法是调用函数,且调用函数时这一次传参传另一个给this,但是当下次调用还是默认的this。没有传参给this的了,但是函数的bind方法写参数会生成一个函数且这个函数每次都给这个参数传给this。

对象原型和原型对象

原型对象是构造函数的prototype指向的对象。

对象原型是实例对象的_ _proto_ _属性。

防抖与节流

鼠标移动mousemove只要移动1px就会触发事件。事件同时到任务队列,会一起执行。最后渲染。

只要触发就会不断执行。我们给事件触发设置的函数会关闭定时器,然后再开启定时器,如果又触发,又关,只有一个定时器在秒数限制内没有触发才去执行。

引入lodash.min.js,内有_.debounce函数,函数第一个参数写执行的函数,第二个参数写时间,和手写的一样。

节流

lodash的这个函数传入函数和时间,最后的结果就是触发事件会调用这个函数,但是当前一个定时器有,定时器可以让函数在多少秒后执行,但是已经有返回值,当前一次触发的定时器的事件没有执行完再次触发事件,函数没有效果。

防抖节流
是触发事件,会不断关闭前一次的定时器,等到时间内不再触发执行最后一次的事件是第一次执行,在下一次执行过程中,触发无效果,等执行完毕,再触发事件有效果
文章来源:https://blog.csdn.net/qq_61990666/article/details/135511462
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。