前端要点总结

数据类型

undifined和null区别

undifined指未定义未赋值
null是已赋值,只是值为null

何时赋值为null

  1. 初始赋值:表明一个值为对象的初始赋值
  2. 结束前:让一个对象成为垃圾对象,被垃圾回收器回收

区分变量类型和数据类型

数据类型:

  • 基本类型和
  • 对象类型

变量类型——变量内存值的类型

  • 基本类型:保存基本类型数据
  • 引用类型:保存地址值

===判断类型

能用===的只有undifined和null判断类型,因为这两个类型中都只有一个值
typeof返回字符串,注意小写
type判断类型:number、object、string、boolen——基本数据类型
可以判断function

typeof "a"==="string"
type不能判断: null和object,object和array

instanceof判断类型:Object、Array、Function——引用数据类型
functoin是特殊的object
对象是用来存储数据的,function存的是代码
AinstanceofB:判断A是否为B的实例,其中B为构造函数

调用返回:嵌套函数多一层,后面多一个括号
function a(){
return function (){
return “ssd”;
}
}
let b = a()()

什么是实例

跟实例对应的是类型

实例对象——类型对象
构造函数function是一种类型
function Person(){
}
var p = new Person();//根据类型创建的实例对象

数据、变量、内存

数据:存储在内存中代表特定信息的
数据特点:可运算、可传递
内存:可存储数据的空间
栈存储:全局变量/局部变量
堆存储:对象
变量:每个变量对应一小块内存

在js调用函数时传递变量参数时, 是值传递还是引用传递

理解1: 都是值(基本/地址值)传递

所以实际上传进function中的参数也是拿着其存着的地址值找内存

内存回收

局部变量在执行函数后会自动释放;
指向的对象成为垃圾对象后会再某一时候进行垃圾回收
垃圾回收
当创建对象之后对所有这个对象的变量赋值为null时,这个对象就永远无法被操作,这个对象就称为垃圾
js拥有自动的垃圾回收机制,不需要也不能手动地回收垃圾,能做的只有将不再使用的对象赋值为null

对象

  1. 什么是对象?
    多个数据的封装体
    用来保存多个数据的容器
    一个对象代表现实中的一个事物

  2. 对象的组成
    属性: 属性名(字符串)和属性值(任意)组成
    方法: 一种特别的属性(属性值是函数)

  3. 如何访问对象内部数据?
    .属性名: 编码简单, 有时不能用
    ['属性名']: 编码麻烦, 能通用

  4. 如何调用(执行)函数

  • test(): 直接调用

  • obj.test(): 通过对象调用

  • new test(): new调用

  • test.call/apply(obj): 临时让test成为obj的方法进行调用——可以让一个方法为任意对象进行调用
    obj作为对象输入时,修改了test中this的指向

var obj = {};
function test(){
	this.a = "saf";
}
teat.call(obj)

回调

回调是作为参数传递给另一个函数的函数——把一个函数作为参数传到另一个函数里面,就是回调callback
例子:train(loss_fn)
异步:涉及等待,不再顺序执行步骤

自调用

注意事项:

  1. 使用:(function(){...})()
  2. 如果自调用函数不是第一行,则在调用函数前加;
  3. 调用自调用函数的内部函数——全局变量保存函数
    window.$:把window对象传入这个匿名函数中,并且同时执行这个函数,在页面载入之前就执行
    {test:test}——第一个test是属性名,第二个是test()函数,这是返回一个对象,对象存储了test()函数
    调用时使用\$的test属性,属性值为test函数
  ;(function () {//不会污染外部(全局)命名空间-->举例
    let a = 1;
    function test () { console.log(++a) } //声明一个局部函数test
    window.$ = functio () {  return {te:test} }// 向外暴露一个全局函数
  })()
  $().te()//调用test函数

this

  1. this是什么?
    任何函数本质上都是通过某个对象来调用的,如果没有直接指定就是window
    所有函数内部都有一个变量this
    它的值是调用函数的当前对象
  2. 如何确定this的值?
    以函数方式调用——windows
    以方法方式调用——this指代方法的对象
    test(): window
    p.test(): p
    new test(): 新创建的对象
    p.call(obj): obj

对象

函数的原型是Object

函数前是否写new的区别

函数前没有new(a),则返回函数执行结果——作为函数调用
函数前有new(b),则视为构造函数,返回对象,如果return基本类型,则返回空对象

function Obj(a, b){
    return a+b;
}
Obj.prototype.name = "name2";
var a = Obj(1, 2);
var b = new Obj(1, 2);
console.log(a);//3
console.log(b);//Obj {}

prototype

函数的prototype属性:

  1. 每个函数都有一个prototype属性,默认指向一个object空对象(原型对象)
  2. 原型对象有个属性constructor,指向函数对象

给原型对象添加属性:作用:函数所有实例对象自动拥有原型中的属性(方法)
prototype对象是实现面向对象的一个重要机制。每个函数也是一个对象,它们对应的类就是function,每个函数对象都具有一个子对象prototype。Prototype 表示了该函数的原型,
prototype表示了一个类的属性的集合。当通过new来生成一个类的对象时,prototype对象的属性就会成为实例化对象的属性。

prototype与__proto__(显示原型属性与隐式原型属性)

  1. 名称
    prototype:原型
    _proto_:原型链
  2. 从属关系:
    prototype->函数的一个属性:对象{},这个属性所对应的就是该对象的原型
    _proto_-> 对象Object的一个属性:对象{}
  • 对象的_proto_保存着该对象的构造函数prototype
  • 原型链的最顶层,Object.prototype.__proto__==null
  • 对象显示原型的值等于对象隐式原型的值——>函数里的prototype与实例对象里的__proto__都指向原型对象object
  1. 何时赋值
  • prototype在定义函数时自动添加,默认值是空Object对象Test.prototype={}
  • _proto_创建对象时自动添加,默认值为构造函数constructor的prototype属性值
    test._proto_===Test.prototype
  1. 能操纵显示属性,不能操纵隐形
function Test(){}
let test = new Test;
console.log(test.__proto__===Test.prototype)//true

在这里插入图片描述

原型链—— 作用:查找对象的属性(方法)

原型链:
访问一个对象属性时,

  • 现在自身属性中查找,找到返回
  • 如果没有,沿着__proto__这条链向上查找
  • 如果最终没有,返回undefined
  • 别名: 隐式原型链
  • 作用:**查找队形的属性(方法)**不是变量

所以可以通过test访问父类节点的属性
Object的构造函数是Function
实例test->函数Test->(Test原型)Object实例->Object原型

  1. Test.prototype.__proto__ === Object.prototype,所以Test可以使用Object函数的实例方法,如toString(),上文的Object 是指Object function即Object的构造函数
    以test对象为基准,以__proto__为连接,一直连到Object.prototype为止的链,以对象原型prototype为节点
    原型链上可以从底到顶继承:原型继承
  2. Object原型的__proto__属性是null
  3. 函数Fn显式原型prototype,对应函数实例fn中的隐式原型__proto__,两者指向同一对象:Object实例

在这里插入图片描述

补充:作用域链——进行变量查找

一个变量,函数作用域里面没有就去外层作用域去找,外层没有就去外层的外层作用域去找直到全局作用域这样一层一层的链式结构就是作用域链

原型链的继承

使用functioin Test函数进行new,则继承了Test的属性
Test 继承了Object的属性
当使用某一属性时,从下向上进行查找,test->function Test ->object(Test函数创建时创建的类)

函数的原型

实例对象的隐式原型===构造函数的显示原型

function Foo{}
//相当于
var Foo=new Function()
  1. Foo是函数
    所以Foo.prototype=={}//空的object在这里插入图片描述
  2. Foo是对象,是Function的实例
Foo.__proto__===Function.prototype//实例的__proto__与原型的prototype指向同一个Object对象(Function原型实例化的时候创建的)
  1. Function=new Function
    所以Function.__proto__===Function.prototype->所有函数的__proto__都是一样的->Function.prototype
    Function是所有对象的源头,包括他自己
    Function的构造函数是他自己
  2. Object的构造函数Object function
    Object function是函数 -> Object function是Function的实例 -> Object function.__proto__===Function.prototype
  3. 原型链最终的指向是Object的prototype, 而Object中的__proto__是null
    Object.prototype.__proto__===null
    Foo.prototype===Object实例
    Object实例.__proto===Object构造函数.prototype
    Object构造函数.prototype.__proto__===null
    5.1 问题:Function自循环,怎么指向Object的
    因为Foo作为对象Foo.__proto__===Function.prototype
    而Foo.prototype指向Object构造函数
判断类是否有这一属性

test.hasOwnProperty('a')判断test类是否有a属性
'a' in test判断原型链上(父类)是否有a属性

function Test(){}
let test = new Test;
Test.prototype.a = 1
console.log(test.hasOwnProperty('a'));//test本身属性
console.log('a' in test);//原型链上属性

公理

  1. 函数的显式原型指向的对象默认是空Object实例对象——但是Object不满足,即
    Object.prototype instanceof Object为false
    几乎所有的JavaScript对象都是Object的实例,其原型链上最后一个就是指向Object.prototype。
  2. Function是自身的实例
  3. Object的原型对象是原型链的尽头:Object.prototype.__proto__===null

构造函数constructor

原型对象的方法是给实例对象用的
test.constructor 指向实例test的构造函数Test
对构造函数而言:
在这里插入图片描述
prototype指向Type的原型对象
原型对象的constructor指向Type
两者相互引用
所以可以给函数的原型提供方法,供实例使用

console.log(Test.prototype.constructor===Test);
Test.
原型对象的方法给实例对象使用
function Test(){//函数test的原型
    this.b=1
}
Test.prototype.pri = function (){
    console.log('233');
}
let test = new Test;//实例
test.pri();//输出:233

在这里插入图片描述

原型链属性查找

属性放自身,方法放原型__proto__
读取对象属性时:自动到原型链中查找
设置对象属性时:不回查找原型链,如果没有,直接添加
方法一般定义在原型中,属性一般通过构造函数定义在对象本身

instanceof

  1. 表达式:A实例 instanceof B函数
  2. 如果B函数的显式原型对象在A对象的原型链上,返回true
  3. 实现instanceof
function instanceof1(A, B){//实例A  函数B
    while(true){
        if (A===null||A.__proto__===null)return false;
        if (A.__proto__ == B.prototype)return true;
        A = A.__proto__
    }
}

实例对象能找到Object原型,不能找到Function原型
函数对象都能找到

new过程

在这里插入图片描述
在这里插入图片描述

判断:如果构造函数返回基本类型,则不返回;如果返回引用类型,则返回其类型

function myNew(constrc, ...args) {
 
    // 1. 创建一个空对象
    const obj = {}; 
 
    // 2. 将obj的_proto_属性指向构造函数的原型对象
    obj.__proto__ = constrc.prototype; 
    
    // 3.将constrc执行的上下文this绑定到obj上,并执行
    const result = constrc.apply(obj, args);
 
    //4. 如果构造函数返回的是对象,则使用构造函数执行的结果。否则,返回新创建的对象
    return result instanceof Object ? result : obj; 
}

变量提升与函数提升

函数必须用声明的方式才能使用函数提升,即function(){}
函数提升会优先于变量提升,而且不会被同名的变量覆盖,但是会被变量赋值之后覆盖。

输出undefined

var c=3;
function fn(){
    console.log(c);
    var c=4;
}
fn()
//等价于
var c=3;
function fn(){
	var c;
    console.log(c);
    c=4;
}
fn()

此时c已被定义,但是没有赋值

var c=3;
function c(c){
    console.log(c);
    // var c=4;
}
c(2)//会报错

因为函数变量提升,先将c视为函数,再被赋值var c=3;这个时候就是变量了,所以会报错

执行上下文——执行顺序

  1. 代码分为
  • 全局代码
  • 局部(函数)代码
    全局变量为windows的变量
  1. 全局执行上下文
    • 在执行全局代码前将window确定为全局执行上下文
    • 对全局数据进行预处理
      1. var定义的全局变量->undefined,为window添加属性
      1. function声明的全局函数->赋值(fun),为window添加方法
      1. this->赋值window
  2. 函数执行上下文
  • 调用函数前,准备执行函数体之前,创建对应函数执行上下文
  • 对局部数据进行预处理
    1. 形参变量->赋值(实参)
    1. argumen(伪数组)->赋值(实参列表)
    1. var定义的局部变量->undefined
    1. function声明的函数->赋值
    1. this->赋值
  • 开始执行函数体

执行上下文栈

全局代码执行前,js引擎创建一个栈存储管理所有上下文对象
在全局执行上下文确定后,将其添加到栈中
函数执行上下文后,添加到栈中
在当前函数执行完后,将栈顶的对象移除
所有代码执行完,栈中只剩下window

执行几个上下文:几个函数+1个window

作用域——找变量

  1. 静态的,在编写代码时确定
  2. 分类
    • 全局作用域
    • 函数作用域
    • 块作用域——ES6-if/for
      var是函数作用域,let是块作用域
  3. 作用:隔离变量

作用域与全局上下文

  1. 区别1
    • 全局作用域之外,含赎回创建自己的作用域,作用域在函数定义时确定,
    • 函数上下文在调用函数前,准备执行函数体之前确定
    • 全局执行上下文在全局作用域确定后,js执行前
  2. 区别2
    • 作用域是静态的,定义了就存在,不变化
    • 上下文环境是动态的,调用时创建,结束后上下文环境被释放
  3. 联系
    • 上下文环境是从属于所在的作用域
    • 全局上下文->全局作用域
    • 函数上下文->函数作用域
  4. 作用域链从下向上
    当前作用域->上一级作用域->…->全局作用域->抛出异常
作用域面试题
var c=10;
function fn(){
    console.log(c);
}
function show(f){
    var c=20;
    f();
}
show(fn);//输出全局变量10

因为fn的作用域在编写时已经确定函数fn的上一级作用域就是全局变量,不是show作用域
在这里插入图片描述

题2:

var fn = function (){
    console.log(fn);
}
fn()
/*输出:fn的函数结构
ƒ (){
    console.log(fn);
}
*/
var obj = {
    fn2:function(){
        console.log(fn2);
    }
}
obj.fn2()//报错

!!只有两个东西能形成作用域:全局、函数,函数能切割全局作用域
所以obj的上一级作用域是全局作用域,全局中没有fn2对象,找不到——报错
为什么找不到:
因为fn2不是全局变量,obj是,所以用obj.fn
调用fn2的对象是obj,所以this表示obj也能找到

闭包——对象,被引用变量函数的对象

  1. 如何产生闭包:
    当一个嵌套的内部函数使用了外部(父)函数的变量时,就产生了闭包
  2. 闭包是什么
  • 闭包是嵌套的内部函数——fn2
  • 包含被引用变量(函数)的对象——被引用的num
  1. 闭包的条件
  • 函数嵌套
  • 内部函数引用了外部函数的变量/函数
  1. 缺点:
    执行完后,函数内的局部变量没有释放,占用内存空间变长
    容易造成内存泄露
  2. 注意:及时释放
    请添加图片描述
    执行函数定义,就会产生闭包——fn2

作用域继承:可以从上一级作用域中获取变量

闭包作用:
  1. 使我们在函数外部能够访问到函数内部的变量
  2. 使已经运行结束的函数上下文中的变量对象继续留在内存中,不会被回收
    请添加图片描述
    为什么return fn2函数,因为不能涉及num定义,否则多次调用返回一样的值
function ass(){
    var num=1;
    function fn2(){
        num++;
        console.log(num);
    }
    return fn2;
}
let as = ass()
as()
as()
as()
as=null;//闭包死亡

闭包的生命周期

  1. 产生:在嵌套内部函数定义执行完时产生,不是调用——因为函数提升
  2. 死亡:包含闭包的函数成为垃圾对象
闭包的应用:
  1. 具有特定功能的js文件——库函数
  2. 将所有数据和功能都封装在一个函数内部
  3. 只向外暴露n个方法的对象和函数

暴露方法1:返回对象包含多个方法
使用方法——

let mymodule = mymodule()

在这里插入图片描述
暴露方法2:暴露window的变量——自调用函数,定义window函数保存方法

在这里插入图片描述

内存溢出与内存泄漏

  1. 内存溢出:
    程序运行需要的内存超过了剩余内存
  2. 内存泄漏:
    占用的内存没有及时释放
    内存泄漏多了容易导致内存溢出
    常见的内存泄漏:
    • 没有及时清理的计时器或回调函数
    • 意外的全局变量
    • 闭包
闭包面试
var name = "window";
var object = {
    name:"object",
    getname:function(){——f2
        return function(){——f3
            return this.name;
        }
    }
}
console.log(object.getname()());//返回window

返回window,因为f3没有name属性,向上找,f2没有name属性,向上,object不是函数,没有作用域,找到window,所以输出window

var name = "window";
var object = {
    name:"object",
    getname:function(){
      var that = this;
      return function(){
            return that.name;
        }
    }
}
console.log(object.getname()());
  1. 闭包与递归
function fun(n, o){
    console.log(o);
    return {
      fun: function(m){
        return fun(m, n);//——》fun根据作用域,不是属性fun,是函数fun,因为对象的{}没有作用域
      }
    }
  }
console.log("--------------------");
fun(1, 2).fun(3)

没有调用外部属性,不是闭包

创建对象函数

var p = {
	name:"tom,
	age:18
}
  1. 工厂模式——返回一个对象的函数
    适合对象:对象为Object类型——定义的obj的类型
function creatPerson(name, age){
    var obj = {
        name:name,
        age:age,
        setName:function(name){
            this.name = name
        }
    }
}
  1. 自定义构造器模式:
    在这里插入图片描述
  2. 构造函数+自定义构造器——方法放在原型上
    使用原型链把方法放在父类上
function Person(name, age){
    this.name= name,
    this.age = age
}
Person.prototype.setName = function(name2){
    this.name = name2
}
var ab = new Person("zhang", 18)

原型链继承

  1. 令子类型的原型(prototype)为父类型的实例(new 父)
.prototype = new.prototype.constructor =

因为修改了子的原型链,导致构造函数失效,需要重新指向构造函数
构造函数没有constructor,但是构造函数.prototype(Object)有constructor,指向构造函数本身,保证实例能够找到它的构造函数
在这里插入图片描述
2. 借用构造函数继承——call
在这里插入图片描述
3. 原型链+构造函数
避免单纯原型链创建父类实例时默认输入问题
避免单纯构造函数无法继承方法问题
在这里插入图片描述

进程机制与线程机制

进程:
在这里插入图片描述

在这里插入图片描述
js是单线程运行,但是h5中的web workers可以多线程运行

浏览器内部核心模块:
在这里插入图片描述
顺序:
编译–解析()–dom/css(生成对象)-布局-渲染(喷像素点 元素数据 img-src-w h)

定时器不能保证真正定时执行

正常运行时等待主线程执行完成后执行定时器
alert——暂停当前主线程执行,同时暂停了定时器的执行,直到点击后恢复

js引擎执行代码的基本流程:

先执行初始化代码;包含一些特别代码

  • 设置定时器
  • 绑定监听
  • 发送ajax请求
    然后再某个时刻在执行回调代码

dom由浏览器模块执行

js单线程——只能有一个线程更新操作界面

在这里插入图片描述

事件循环模型

在这里插入图片描述

将函数放入栈中,遇到回调函数,将其放入回调函数队列中,

事件循环:
从任务队列中循环取出回调函数,放入执行栈中处理

async 等于

返回一个Promise对象执行——用其他方式实现Promise
return new Promise.resolve('abc')

await 阻塞下面的代码

DOM 定义了访问文档的标准:
“W3C 文档对象模型(DOM)是中立于平台和语言的接口,它允许程序和脚本动态地访问、更新文档的内容、结构和样式。”
HTML DOM 是关于如何获取、更改、添加或删除 HTML 元素的标准。

onsubmit处理函数返回false,onclick函数返回false,都不会引起表单提交。

事件监听:将调用函数都放在script程序中
在冒泡中,最内侧元素的事件会首先被处理,然后是更外侧的:首先处理 <p> 元素的点击事件,然后是<div>素的点击事件。

在捕获中,最外侧元素的事件会首先被处理,然后是更内侧的:首先处理 <div>元素的点击事件,然后是 <p> 元素的点击事件。

var myTitle = document.getElementById("demo").innerHTML;
==
var myTitle = document.getElementById("demo").firstChild.nodeValue;
==
var myTitle = document.getElementById("demo").childNodes[0].nodeValue;

每个 HTML 元素是元素节点
HTML 元素内的文本是文本节点
每个 HTML 属性是属性节点

setTimeout()方法需要延迟后使用,因此可以在函数内部调用setTimeout——保证后续使用
想要开始就显示,使用onload()载入页面时加载函数

function add{
    setTimeout(add, 1000);
}

运算顺序

=、+=、-=、*=、/=、%=、&=、|=、^=、<、<=、>、>=、>>= 混合赋值运算符 从右向左计算

表单判断

HTMLSelectElement.checkValidity()方法检查元素是否有任何约束以及它是否满足这些约束。如果元素未通过其约束,浏览器会在元素上触发可取消的无效事件,然后返回 false。
如果您只想知道该值是否有效,请使用validity.valid. 但是如果要将表单状态更改为无效,请使用checkValidity().

setCustomValidity()

setCustomValidity(value)value为报错信息,会影响checkValidity和validity.valid的判断,因此需要

  1. 先判断,再修改信息
  2. 修改信息后需要重新填入空值setCustomValidity("")

时间写法:

setInterval(myFunction, 1000);

function myFunction() {
  let d = new Date();
  document.getElementById("demo").innerHTML=
  d.getHours() + ":" +
  d.getMinutes() + ":" +
  d.getSeconds();
}

在这里插入图片描述

H5 web workers多线程

在这里插入图片描述

	//主线程:
    let num = document.getElementById("num");
    document.getElementById("sum").onclick = function(){
        var number = num.value;
        var worker = new Worker("worker.js");
        worker.onmessage = function(event){
            console.log('主线程返回数据'+event.data);
            document.getElementById("feibo").innerHTML = event.data;
        }
        worker.postMessage(number);
        console.log('主线程发送');
    }

流程:

  1. 建立worker
  2. 使用worker.onmessage方法获取函数
  3. 使用worker.postMessage();发送数据
    为什么先发送再获取,因为获取函数是回调函数,需要等待
// worker.js
function fi(n){//计算使用的函数——菲波那切数列
    let temp;
    if(n<=2)temp = 1;
    else temp = fi(n-1)+fi(n-2);
    // list.push(temp);
    return temp;
}

var onmessage = function(event){//调用多线程的模板
    var number = event.data;
    console.log('分线程接收的'+number);
    var s = fi(number)
    postMessage(s);
    console.log('分线程返回的'+s);
}
// onmessage   function(event) event.data;  postMessage(s);//是固定的

分线程的全局变量不再是worker,没有window,所以不能调用dom,不能调用alert等方法,不能更新界面

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值