面向过程与面向对象
面向过程时一步一步去做一件事,面向对象是多个功能组合在一起,去完成这件事。
面向对象的特性:继承性,封装性,多态性
通过概述应该知道面向过程和面向对象的优缺点
封装性
大家要玩游戏,当对于英雄的各个属性和方法该如何存储?用对象存储。将相关的属性和方法存储到一个对象上。
但是对象如果存储函数,或者是同一个对象等会比较浪费内存。有原型对象可以节省内存,原型对象
静态变量存储在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。
防抖与节流
鼠标移动mousemove只要移动1px就会触发事件。事件同时到任务队列,会一起执行。最后渲染。
只要触发就会不断执行。我们给事件触发设置的函数会关闭定时器,然后再开启定时器,如果又触发,又关,只有一个定时器在秒数限制内没有触发才去执行。
引入lodash.min.js,内有_.debounce函数,函数第一个参数写执行的函数,第二个参数写时间,和手写的一样。
节流
lodash的这个函数传入函数和时间,最后的结果就是触发事件会调用这个函数,但是当前一个定时器有,定时器可以让函数在多少秒后执行,但是已经有返回值,当前一次触发的定时器的事件没有执行完再次触发事件,函数没有效果。
防抖 | 节流 |
是触发事件,会不断关闭前一次的定时器,等到时间内不再触发执行最后一次的事件 | 是第一次执行,在下一次执行过程中,触发无效果,等执行完毕,再触发事件有效果 |