原型链
引用类型:
__proto__(隐式原型)
属性,属性值是对象
函数:
prototype(原型)
属性,属性值是对象
相关方法
person.prototype.isPrototypeOf(stu)
Object.getPrototypeOf(Object)替换已不推荐的Object._ _ proto _ _
Object.create(instance) 以一个现有对象作为原型,创建一个新对象
class类
ES6前:构造函数和原型链
1.构造函数:this.x=x
2.类方法:构造函数.prototype.fun=function(){}
继承
1.构造函数:父类构造函数.call(this,x)
2.原型链:Dog.prototype = Object.create(Animal.prototype)
3.修正prototype上的构造函数:Dog.prototype.constructor = Dog
// 使用构造函数和原型链定义"类"
function Animal(name) {this.name = name;
}Animal.prototype.speak = function() {console.log(this.name + ' makes a sound.');
};// 创建类的实例
const dog = new Animal('Dog');
dog.speak(); // 输出: "Dog makes a sound."// 继承一个"类"
function Dog(name, breed) {Animal.call(this, name);this.breed = breed;
}
//Object.create() 静态方法以一个现有对象作为原型,创建一个新对象
Dog.prototype = Object.create(Animal.prototype);
//修正构造函数
Dog.prototype.constructor = Dog;Dog.prototype.speak = function() {console.log(this.name + ' barks loudly.');
};const myDog = new Dog('Buddy', 'Golden Retriever');
myDog.speak(); // 输出: "Buddy barks loudly."
ES6:class
constructor可没有(默认会创建)
super必须实现
执行上下文/作用域:执行环境(变量+函数)存于 变量对象
全局执行上下文:this 指向window全局对象
函数执行上下文:每次调用会创建新的执行上下文
作用链=作用域链表
查找不到:原型链undefined,作用域链ReferenceError
this
全局环境(普通函数/匿名函数):window/undefined 严格模式
调用函数的对象
JS预解析/编译(变量提升):var、function变量 创建作用域
闭包:函数返回函数,且子函数 调用 父级作用域的变量
因为js作用域生命周期在于内部脚本是否全部执行完毕才会销毁,并且不会带到父级作用域;
因为被下级作用域内 引用,而没有被释放。就导致上级作用域内的变量,等到下级作用域执行完后 或者 当闭包(子函数)不再被引用时才会被释放。
function createCounter() {let counter = 0const myFunction = function() {counter = counter + 1return counter}return myFunction}const increment = createCounter()const c1 = increment()const c2 = increment()const c3 = increment()console.log('example increment', c1, c2, c3)//1 2 3
- 闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包
- 滥用闭包容易内存泄漏。
- 使用场景 : 防抖、节流、函数套函数避免全局污染
内存泄漏:内存浪费->慢->崩溃
不再使用/为空的引用未被移除:闭包/DOM移除,子节点引用没移除
垃圾回收:自动定期,不需要的引用设置为null
(GC)Garbage Collection
浏览器的js具有自动垃圾回收机制,垃圾回收机制也就是自动内存管理机制,垃圾收集器会定期的找出不可访问的值,然后释放内存,所以将不需要的对象设为null即可。
模块化规范:一个模块=实现特定功能的一组方法。
-
几个函数:全局变量的污染,模块间没有联系。
// 模块A
var ModuleA = {func1: function() {// ...},func2: function() {// ...}
};// 模块B
var ModuleB = {func3: function() {// ...}
};
- 后面提出了对象,通过将函数作为一个对象的方法来实现,但是这种办法会暴露所 有的所有的模块成员,外部代码可以修改内部属性的值。
- 现在最常用的是立即执行函数的写法,通过利用闭包来实现模块私有作用域的建立,同时不会对全局作用域造成污染。
//IIFE(立即调用函数表达式)
//创建一个私有作用域,避免变量之间的冲突。然后,通过返回一个对象或函数来暴露模块的公共部分
// 模块A
var ModuleA = (function() {var privateVar = "private";function privateFunc() {// ...}return {publicVar: "public",publicFunc: function() {// ...}};
})();
- ES6 :使用 import 和 export 的形式来导入导出模块。
ES6新增
数据类型:基本Symbol,Bigint(ES10),引用/(Object)对象Set ,Map,Promise(解决回调地狱)
let bnum=1684424684321231561n //方式1:数组后加n
bunm=BigInt("1684424684321231561")//方式2:调用BigInt
运算符
变量的解构赋值:从数组/对象中取值
// 提取部分数组元素,其余元素放在剩余数组中
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;
console.log(first); // 输出: 1
console.log(second); // 输出: 2
console.log(rest); // 输出: [3, 4, 5]// 从对象中提取属性并赋值给变量
const person = { firstName: 'John', lastName: 'Doe' };
const { firstName, lastName } = person;
console.log(firstName); // 输出: John
console.log(lastName); // 输出: Doe// 提取属性并赋值给变量,并指定默认值
const { age = 30, occupation = 'Engineer' } = person;
console.log(age); // 输出: 30 (因为age属性不存在)
console.log(occupation); // 输出: Engineer (因为occupation属性不存在)const nestedObject = {outer: {inner: {deep: 'Hello, nested!'}}
};const { outer: { inner: { deep } } } = nestedObject;
console.log(deep); // 输出: Hello, nested!
数组/对象:扩展运算符(浅拷贝)
函数
箭头函数:简洁
继承上一层作用域链的this
不绑定arguments,用rest参数
因为没有function声明,所以没有原型prototype,所以不能作为构造函数
rest 参数:...真正的数组
function sum(...numbers) {let total = 0;for (let number of numbers) {total += number;}return total;
}console.log(sum(1, 2, 3)); // 输出 6
ES7 的async/await函数替代了ES6 的Generator 函数
字符串方法:${ },单反引号
块级作用域:let,const
ES6 前作用域: 全局变量 与 函数内的局部变量。
块级作用域{}:if(){},for(){}等
var:重复声明,变量提升
let、const:块作用域里访问,无重复声明,变量提升
const :必须初始化(语法错误SyntaxError),栈值/内存地址不变(类型错误TypeError)
定义类的语法糖(class)
模块化import/export
类型转换
Number
显式类型转换
Number(任意类型):若string含非数字,会返回NaN
parseInt(string[,radix]):基数radix是2-36之间的整数
parseFloat(string):解析一个参数并返回一个浮点数
隐式转换:+str-,含boolean的相加
str = '123'
-
str - 1 //122
-
+str+1 // 124
-
str+1 // '1231'
string
显式类型转换
除了null/undefined.toString()
String(任意类型)
隐式转换:含str的相加
Boolean
显式类型转换
Boolean():0, ''(空字符串), null, undefined, NaN会转成false,其它都是true
隐式转换 :!!
判断数据类型
运算符
typeof:判断 基本数据类型
typeof null=Object 类型标签均为000
实例
instanceof 构造函数
:判断原型链,和isPrototypeOf
Object.prototype.isPrototypeOf({})// true
{} instanceof Object// true
方法
构造函数.
prototype.isPrototypeOf(实例)
:判断原型链
(数据).constructor === 数据类型:不包含继承类型
显示:toString,valueOf 除了null,undefined
valueOf:this
值转换成对象。除了Date都是返回数据本身
console.log
toString:重写对象的类型转换。console.log
松散相等==(可自动转换类型) 和 严格相等===
比较的是内存单元的内容
set判断===相等
//Set用===判断是否相等
const set= new Set();
const obj1={ x: 10, y: 20 },obj2={ x: 10, y: 20 }
set.add(obj1).add(obj2);console.log(obj1===obj2);//false
console.log(set.size);// 2set.add(obj1);
console.log(obj1===obj1);//true
console.log(set.size);//2
DOM事件流:捕获->冒泡
- 事件捕获:由外往内,从事件发生的根节点开始,逐级往下查找,一直到目标元素。
- 事件冒泡:由内往外,从具体的目标元素触发,逐级向上传递,直到根节点。
element.addEventListener(event, function[, useCapture]);
//useCapture 默认为false,即冒泡阶段调用事件处理函数,
//为ture时,在事件捕获阶段调用处理函数
遍历(str,num,set,map)
for of:val,Object.keys(obj)自身属性
for in:idx ,包括继承的可枚举属性
可遍历对象的 公有 可枚举属性(除symbol 属性)
obj.hasOwnProperty(prop) 避免遍历原型链上的属性
forEach(value[,index,arr]):不改变原数组,返回undefined
无法中断( break (Illegal break statement)和 return (无效))
map(value[,index,arr]):返回新的数组
执行速度优于forEach(底层做了优化)
高阶函数:params / return func
函数柯里化:return func
手写
改变this
call
-
typeof this !== 'function'
-
context = context || window
-
context._this = this
-
delete context._this
// 给function的原型上面添加一个 _call 方法Function.prototype._call = function (context) {// 判断调用者是否是一个函数 this 就是调用者if (typeof this !== 'function') {throw new TypeError('what is to be a function')}// 如果有 context 传参就是传参者 没有就是windowcontext = context || window// 保存当前调用的函数context._this = this // 截取传过来的参数/*argumentsa: 1fn: ƒ fns()*/// 通过 slice 来截取传过来的参数const local = [...arguments].slice(1)// 传入参数调用函数let result = context._this(...local)// 删属性delete context._thisreturn result}let obj = { a: 1 }function fns(a, b) {console.log(a, b);console.log(this)}fns._call(obj, 23, 555)
bind: return _this.apply(context, [...arguments].slice(1));
深拷贝
-
!arr|| arr == null || typeof arr != 'object'
-
arr instanceof Array ? [] : {}
-
for (const key in arr)
-
result[key] = cloneDeep(arr[key])
function cloneDeep(arr = {}) {// 终止递归 if (!arr|| arr == null || typeof arr != 'object' ) return arr// 用 instanceof 判断原型链上是否有该类型的原型 是 Array => [] ! Arrays =>{}let result=arr instanceof Array ? [] : {}// forin 循环对象的key值for (const key in arr) {// 对象 key 赋值 resultresult[key] = cloneDeep(arr[key])}return result}