前端笔记整理(JS)
Posted Leatitia
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端笔记整理(JS)相关的知识,希望对你有一定的参考价值。
前端基础知识
- 数据类型
- 函数
- 原型链
- 单体内置对象
- Date类型
- arguments类数组转换为数组的方法
- 语句
- 执行上下文
- Promise
- websocket
- cookie、webStorage
- 实现浏览器多个标签页通信
- 跨域
- 缓存
- js延迟加载的方式
- XSS和CSRF区别
- HTTP和HTTPS的区别
- 防抖和节流
- call、apply、bind
- `XML`和`JSON`的区别?
- 性能优化
- HTML5的文件离线存储怎么使用,工作原理是什么?
- BOM
- DOM
- 在浏览器中输入url到页面显示出来的过程发生了什么?
- 从一行代码里学点js
数据类型
JS数据类型
- 基本类型:number、string、null、symbol、boolean、undefined
- 对象类型:Object(Array、RegExp、Math、Map等)、Function
不可以使用
var col = [1,2,]
这样可能会创建2个或者3个长度的数组,因浏览器不同
数组
检测数组
- ES5新方法:
Array.isArray(arr)
兼容写法:
function isArray(arr)
return Object.prototype.toString.call(arr) == "[Object Array]"
- 只有一个全局执行环境时:
arr instanceof Array
迭代方法
every((item,index,array)=>)
:所有的数组项都符合判断时返回true,否则返回false;some((item,index,array)=>
:只要数组项其中一项符合判断时返回true,否则返回false;filter((item,index,array)=>
:对数组项进行过滤,然后将符合条件的数组项添加到一个新的数组,返回新数组;map((item,index,array)=>
:遍历且返回执行函数后的结果组成的新数组,返回新数组;forEach((item,index,array)=>
:仅遍历,不进行返回;
转换方法
toString()
返回以逗号拼接的数组各项值的字符串toLocalelString()
join(",")
返回以指定字符串拼接的数组各项值的字符串
栈方法(后进先出)
push()
接收任意数量的参数,逐个添加至数组末尾,返回修改后的数组的长度pop()
移除数组末尾最后一项,返回移除的项
队列方法(先进先出)
shift()
移除数组中的第一项并返回该项unshift()
接收任意数量的参数,逐个添加至数组前端,返回新数组长度
重排序方法
reverse()
:反转数组顺序sort()
:按升序排列数组项(sort()
会调用每个数组项的toString()方法,比较字符串)
sort()
可接受一个比较函数作为参数,优化比较
var arr = [1,5,2,9,11,6];
arr.sort(function(a,b)
return a-b
)
console.log(arr) //[11,9,6,5,2,1]
操作方法
concat(a1,a2)
复制一个副本,并且向当前副本添加接收到的参数,可接受任意类型参数(除Object) ,返回新构建的副本slice(start,end)
接收一个或者2个参数。用于截取数组参数,并返回截取到的项组成的新数组splice(start,num,...args)
接收至少2个参数,返回删除的项组成的数组(没有删除时返回[]
),用途:- 删除:
arr.splice(0,2)
—— 删除数组前两项 - 插入:
arr.splice(2,0,"dsdg","svsdfg")
—— 删除项数量为0,从当前数组的2位置开始添加2项:“dsdg”,“svsdfg” - 替换:
arr.splice(2,1,"123")
—— 向指定位置插入任意数量的项,且同时删除任意数量的项
- 删除:
位置方法(全等比较)
indexOf(value[,index])
:从数组起始位置查找,返回项在数组中的位置索引lastIndexOf(value[,index])
:从数组末尾位置开始查找,返回项在数组中的位置索引
其它:
- ES6中find(value)
:返回第一个符合传入测试(函数)条件的数组元素;
- findIndex(value)
:返回符合传入测试(函数)条件的数组元素索引;
- includes(value)
:判断一个数组是否包含一个指定的值。
归并方法
reduce((pre,cur,index,array)=>)
:从第一项开始迭代reduceRight((pre,cur,index,array)=>)
:至少一项返回true,则返回true从最后一项开始迭代
函数返回的任何值都会自动传递给下一项。第一次迭代发生在数组的第二项上
var values = [1,3,5,8,9];
var sum = values.reduce(function(prev,cur,index,arr)
return prev+cur
)
console.log(sum) //26
类数组(Array-like)对象
slice 方法可以用来将一个类数组(Array-like)对象/集合转换成一个新数组。你只需将该方法绑定到这个对象上。 一个函数中的 arguments 就是一个类数组对象的例子。
function list()
return Array.prototype.slice.call(arguments);
var list1 = list(1, 2, 3); // [1, 2, 3]
简化使用:[].slice.call(arguments)
对象
for(let i in obj)
属性类型
ECMAScript有两种属性:
数据属性
和访问器属性
- 数据属性(包含一个数据值的位置):
[[Configurable]]
:是否可修改属性特性、删除属性、把属性修改为访问器属性(默认为true
)[[Enumerable]]
:是否可以通过for-in循环返回属性(默认为true
)[[Writable]]
:是否可以修改属性值(默认为true
)[[Value]]
:包含这个属性的数据值(默认为undefined
)
修改属性特性,需要使用ECMAScript5的
Object.definedProperty(属性所在对象,属性名,描述符对象)
方法,其中描述符必须是数据属性之一。设置一个或者多个值,可以修改对应的特性值
把[[Configurable]]
设置为false后,则调用Object.definedProperty()
方法也无法修改
- 访问器属性:
[[Configurable]]
:是否可修改属性特性、删除属性、把属性修改为访问器属性(默认为true
)[[Enumerable]]
:是否可以通过for-in循环返回属性(默认为true
)[[Get]]
:在读取属性时调用的函数(默认为undefined
)[[Set]]
:在写入属性时调用的函数(默认为undefined
)
访问器属性不能直接定义,必须使用Object.definedProperty()
定义
读取属性的特性(ECMAScript5)
Object.getOwnPropertyDescriptor(属性所在对象,描述符名称)
可以取得给定属性的描述符
String类型
- 字符串方法:
str.charAt(index)
返回给定位置的字符str.charCodeAt(index)
返回给定位置的字符的字符编码ES5
中可以使用str[index]
访问指定位置的字符
- 字符串操作方法
concat()
字符串拼接substr(start,num)
返回从起始位置截取num个字符(参数为负值时,-start+字符串长度,-num=0)substring(start,end)
返回从起始位置到结束位置的字符(参数为负值时,全部转为0)slice(start,end)
返回从起始位置到结束位置的字符(参数为负值时,负值+字符串长度进行转换)
- 字符串位置方法
indexOf(str,start)
和lastIIndexOf(str,start)
返回字符在字符串中的位置
- trim()方法(
ES5
新提供)—— 删除字符串首尾空格 - 字符串大小写转换
toLowerCase
toUpperCase
- 字符串的模式匹配方法
match(type)
match只接收一个正则或者RegExp对象
返回数组:serach(type)
search只接收一个正则或者RegExp对象
返回字符串中第一个匹配项的索引replace(type,str|function)
split(str,length)
基于一个分隔符将字符串分割成多个字符串并存于一个数组中,可以指定数组长度
类型判断
- typeof :基本类型的数据中除了null,其它类型都可以通过typeof判断;对于对象类型来说,除function以外,其它类型判断的值均为object;
- instanceof :通过原型链的方式来判断是否为构建函数的实例,常用于判断具体的对象类型;
- Object.prototype.toString.call(v) ;
- isXXX API :isArray、isNaN;
typeof null // object
[] instanceof Array // true
Object.prototype.toString.call(null) // "[object Null]"
Array.isArray([]) // true;
isNaN(',') // true
null
和undefined
的区别
-
null
是一个表示"无"的对象,转为数值时为0;undefined
是一个表示"无"的原始值,转为数值时为NaN
。 -
undefined
表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:- 变量被声明了,但没有赋值时,就等于
undefined
- 调用函数时,应该提供的参数没有提供,该参数等于
undefined
- 对象没有赋值的属性,该属性的值为
undefined
- 函数没有返回值时,默认返回undefined
- 变量被声明了,但没有赋值时,就等于
-
null
用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。典型用法是:- 作为函数的参数,表示该函数的参数不是对象
- 作为对象原型链的终点。
0.1+0.2 !== 0.3
JS中浮点数用二进制表示的时候是无穷的,因为精度问题,两个浮点数相加会造成截断丢失精度,因此再转换成十进制就会出问题。
手写instanceof
function myInstanceof(obj,pro)
obj = obj.__prpto__;
pro = pro.prototype;
while(obj)
if(obj === pro) return true;
obj = obj.__proto__;
return false;
typeof和instanceof类型判断
- typeof可以准确判断除了null的基本类型,null和对象都会返回object
- instanceof能准确判断对象的类型,对于基本类型都返回false,内部机制根据原型链来判断,如果沿着A的原型链,同时沿着B的原型链来找,如果能找到同一个引用,就返回true。
类型转换
- 强制转换:转换成特定的类型(Number()、 v.toString())
- 转换Boolean规则:undefined、null、false、NaN、0,都转换为false;其它都为true,包括所有对象;
- 转换Number规则:true为1,false为0;null为0,undefined为NaN ,symbol报错;字符串是数字或者进制值就正常转,否则NaN ,对象隐式转换;
- 隐式转换:valueOf()、toString() (只有当加法运算符时,有字符串类型则统一转字符串类型,其它只要有数字类型,就都转数字);
[]==![] // -> ? 输出为true
- == 和===的区别
- ==, 两边值类型不同的时候,要先进行类型转换,再比较
- ===,不做类型转换,类型不同的一定不等;
- 特殊数据类型解析
- Number()、parseIn(value, 基数)、parseFloat()
- toString(基数)、String()
- Object:
constructor
保存用于创建当前对象的函数hasOwnProperty(name)
检测给定属性在当前对象实例中是否存在isPrototypeOf(object)
检测传入的对象是否是当亲对象的原型propertyIsEnumerable(name)
检查给定的属性是否能够使用 for-in枚举toLocalString()
范湖对象的字符串表示toString()
valueOf()
返回对象的字符串、数值或者布尔值表示
toString()和valueof()的区别
toString()
方法返回一个表示该对象的字符串。如果是对象返回,toString()
会返回’[object type]’,其中type就是对象类型;valueof()
方法返回指定对象的原始值。JS会利用valueof()
把对象转换为原始类型的值(数值、字符串、布尔值)。
var array = ['aa','bb','cc'];
console.log(array.toString()); //aa,bb,cc
console.log(array.valueOf());//['aa','bb','cc']
深浅拷贝
引用类型复制:将存储在变量对象中的值(指针,指向存储在堆中的一个对象)复制到新变量分配的空间上。复制完成,两个变量将引用同一个对象
- 两个对象第一层的引用不相同就是浅拷贝的含义。可以通过
assign
、扩展运算符等方式来实现浅拷贝;- 两个对象内部所有的引用都不相同就是深拷贝的含义。可以通过递归的方式解决;
//深拷贝
//1. JSON.stringfy(obj)
//2. 递归
function deepClone(data)
let type = Object.prototype.toString.call(data);
let obj;
if(type === '[object Array]')
obj = [];
for(let i=0;i<data.length;i++)
obj.deepClone(data[i]);
else if(type === '[object Object]')
obj = ;
for(let i in data)
obj[i] = deepClone(data[i]);
else
return obj
return obj
变量提升
var声明的变量存在声明提升情况,即提升到变量所在作用域的顶端执行,再到变量位置进行赋值操作;ES6中let声明变量不存在声明提升情况
function test ()
console.log(a); //undefined
var a = 123;
;
a = 1;
var a;
console.log(a); //1
函数提升
函数提升存在两种方式,即:
- 函数声明式;该情况是将函数整个代码块提升到它所在的作用域最开始执行;
- 函数字面量式;同var声明类似,该声明函数只是一个具体的值。
var、let、const的区别
- var声明的变量,其作用域为该语句所在作用域内,存在变量提升现象;
- let 声明的变量,其作用域为该语句所在函数内,不存在变量提升现象,存在暂时性死区;且相同作用域下,不可重复定义;
- const声明的变量声明时必须立即赋值,且不允许修改;
ES6箭头函数
特点:
- 箭头函数
this
为父作用域的this
,不是调用时的this
; - 箭头函数不能作为构造函数,不能使用
new
; - 箭头函数么有arguments、caller、callee;
- 箭头函数通过call和apply 调用,不能改变
this
的指向,只会传入参数; - 箭头函数没有原型属性;
- 箭头函数返回对象时,要加一个小括号
函数
函数是对象,函数名是指向函数对象的指针。一个函数可以有多个函数名。
函数定义方式:
- 函数声明 (存在
函数声明提升
)- 函数表达式 变量 = 匿名函数
参数
arguments
类数组对象,主要用于保存参数
arguments
的属性callee
:指针,指向拥有这个arguments对象的函数,递归调用的时候使用arguments.callee()
,可以避免因为函数名重复时造成的bugthis
引用的是函数执行的环境对象(全局作用域调用函数时,this引用的是window对象)caller
:ES5
规范的函数对象属性,保存调用当前函数的函数的引用,可可以使用arguments.callee.caller
严格模式下,访问arguments.callee()
会报错;不能为caller赋值
函数调用过程中,值传递、参数不对等处理上,不管实参的数目大于还是小于形参,数据类型是否准确,调用的函数都会被执行
理解:JS中的参数在内部是用数组表示的。函数接收的始终是个数组(arguments对象),可以通过下标来获取传入的每一个元素(arguments[0]),也可以用length属性来气确定传递进来的参数个数
function hello(name,msg)
console.log("hello ' + arguments[0] +arguments[1])
console.log(arguments.length)
function say()
console.log("hello ' + arguments[0] +arguments[1])
console.log(arguments.length)
hellow('lili',',how are you');
say('lili',',how are you');
//以上都会输出:hello lili ,how are you
返回值
函数要么有返回值要么没有返回值,否则容易造成调试不便。
未指定返回值的函数返回的是一个特殊值undefined
属性和方法
- 每个函数都包含两个非继承而来的方法:
apply()
和call()
,两者作用相同,仅仅是接收参数的格式不同
fun.apply(obj,[...arguments])
fun.call(obj,...arguments)
作用:
- 用于在特定的作用域中调用函数,即重新定义函数体内this对象的值
- 扩充函数作用域,对象不需要与方法有任何的耦合关系,函数中操作使用this指向
ES5
中新定义方法:bind()
创建一个函数的实例,其this值会绑定到传给bind()函数的值
函数重载
函数没有签名(接收的参数类型和数量),所以ECMAScript没有函数重载。定义相同名称的函数,只会执行最后一个。
递归
定义:一个函数通过名字调用自身
arguments.callee()
可以解决函数重定义情况
arguments.callee()
是一个指向正在执行的函数的指针,可用来代替函数名,因此可以用来实现递归调用- 严格模式下
arguments.callee()
访问时会报错,可用命名函数表达式解决
var factorial = (function f(num)
if(num < 1)
return 1
else
return num*f(num -1)
)
原型链
this
this
对象是指运行时基于函数的执行环境决定的,指向调用函数的对象。全局函数中,this指向window;当函数作为某个对象的方法调用时,this指向那个对象;匿名函数的执行环境具有全局性,其this对象指向window。
- call()、apply()、bind()会改变this指向,优先级仅次于new;
- 箭头函数:箭头函数没有this。箭头函数中,this只取决于定义时的环境。
var a = 1
const fn = () =>
console.log(this.a)
const obj =
fn,
a: 2
obj.fn() //1
const a =
b: 2,
foo: function () console.log(this.b)
function b(foo)
// 输出什么?
foo()
b(a.foo) //undefined
内存泄漏
内存泄漏:指任何对象在不再拥有或需要它之后仍然存在;
操作:
setTimeout
的第一个参数使用字符串而非函数的话,会引发内存泄漏。- 闭包、控制台日志、死循环(在两个对象彼此引用且彼此保留时,就会产生一个循环
- 过度递归
- 无效的全局变量
闭包
- 定义:假如一个函数能访问外部的变量,那么这个函数就是一个闭包。闭包常用来访问私有变量。
this
和argument
对象:与外层函数无关,只与调用自己时的对象以及传的参数有关。- 特性:
- 函数嵌套函数
- 函数内部可以引用外部的参数和变量
- 参数和变量不会被垃圾回收机制回收
for (var i = 0; i < 6; i++)
setTimeout(() =>
console.log(i)
)
//输出6 解决办法:let定义i
-
数据存放在堆中还是栈中?(栈是有结构的,先进后出,数据查询速度:栈>堆)
JS中基本类型值在内存中固定大小,保存在栈内存中;引用类型是对象,保存在堆内存中;JS在定义变量时就分配了内存,使用时候就是对内存的读写操作,内存释放依赖于浏览器的垃圾回收机制; -
垃圾回收
JS每次创建字符串、对象、数组等,解释器都必须动态分配内存来存储实体。这种动态分配了内存的,最终都要释放这些内存一遍他们能够再利用,否则系统内可用内存会被消耗完,造成系统崩溃。
常用回收方法
- 标记清除;
- 引用计数
- 闭包的优缺点
- 优点
- 读取私有变量;
- 可封装对象的私有属性和私有方法;让这些变量时装保存在内存中;
- 缺点
- 占用更多内存;滥用闭包可能会造成网页性能问题,在IE中可能导致内存泄漏(解决办法:退出函数之前,将不适用的局部变量删除)
new
- new操作费、符创建一个空对象,并且
this
变量引用该对象,同时还继承了该函数的原型。- 属性和方法被加入到
this
引用的对象中。- 新创建的对象由
this
所引用,并且最后隐式的返回this
。
//手写实现一个new
// 构造器函数
let Parent = function (name, age)
this.name = name;
this.age = age;
;
Parent.prototype.sayName = function ()
console.log(this.name);
;
//自己定义的new方法
let newMethod = function (Parent, ...rest)
// 1.以构造器的prototype属性为原型,创建新对象;
let child = Object.create(Parent.prototype);
// 2.将this和调用参数传给构造器执行
let result = Parent.apply(child, rest);
// 3.如果构造器没有手动返回对象,则返回第一步的对象
return typeof result === 'object' ? result : child;
;
//创建实例,将构造函数Parent与形参作为参数传入
const child = newMethod(Parent, 'echo', 26);
child.sayName() //'echo';
作用域
定义:变量的可访问性。
分类:
- 全局作用域
- 函数作用域
- 块级作用域(ES6中的let、const)
作用域链:作用域的嵌套。往上遍历查找。
问:箭头函数和普通函数的区别
- 箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()
- 普通函数的this指向调用它的那个对象
作用域链
作用域链本质上是一个指向变量对象的指针列表,只是引用但不实际包含变量对象。
模仿块级作用域
javascript没有块级作用域的概念。js可多次声明同一变量,可多次执行初始化。匿名函数可以用来模仿块级作用域,限制向全局作用域中添加过多的变量和函数
;(function()
//块级作用域
)();
原型
原型是什么?
- 所有对象都有一个属性
__proto__
指向一个对象,也就是原型;- 每个对象的原型可以通过
constructor
找到构造函数,沟站函数也可以通过prototype
找到原型;- 对象之间通过
__proto__
连接起来,这样称之为原型链;当前对象上不存在的属性可以通过原型链一层层往上查找,直到顶层Object
对象,最后就是null
了
继承
即使是ES6中的class
也不是其它语言中的类,本质就是一个函数。
class Person ;
Person instanceof Function //true
ES6和ES5中的继承的区别:
- ES6 继承的子类需要调用 super() 才能拿到子类,ES5 的话是通过 apply 这种绑定的方式
- 类声明不会提升,和 let 这些一致
- JS 如何实现继承
JS实现继承主要是依靠原型链。主要有6种继承方式:
- 原型链:利用原型让一个引用类型继承另外一个引用类型的属性和方法;
- 借用构造函数:在子类型构造函数的内部调用超类构造函数,通过使用call()和apply()方法可以在新创建的对象上执行构造函数;
function SuperType()
this.colors = ["red","blue","green"];
function SubType()
SuperType.call(this);//继承了SuperType
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors);//"red","blue","green","black"
var instance2 = new SubType();
console.log(instance2.colors);//"red","blue","green"
- 组合继承
- 原型式继承
- 寄生式继承
- 寄生组合市继承
- 通过原型实现的继承和class有什么区别?
类从类继承并创建子类关系;原型是一个工作对象实例。对象直接从其他对象继承。
单体内置对象
Global
对象
所有在全局作用域中定义的属性和函数,都是Global对象的属性和方法
- URI 编码方法
encodeURI()
、encodeURIComponent()
、decodeURI()
、decodeURIComponent()
evval(str)
方法
eval() 类似一个JavaScript解析器,只接收一个参数(要执行的javascript字符串)
- 在
eval()
中定义的变量和函数都不会被提升;只在eval()执行的时候创建 - 严格模式下,在外部无法访问
eval()
中定义的任何变量或者函数 - 使用eval(),存在代码注入的恶意攻击危险
window
对象
在全局作用域中声明的变量和函数,都成为了window对象的属性
Math
对象
min()
和max()
方法
可接收任意多个数值参数。求数组中以上是关于前端笔记整理(JS)的主要内容,如果未能解决你的问题,请参考以下文章