js之前端知识积累

1. let,const 和 var

var

如果使用关键字 var 声明一个变量,那么这个变量就属于当前函数作用域
如果声明是发生在任何函数的顶层声明,那么这个变量就属于全局作用域。

let

ES6新增,用于声明变量,用法和 var 类似,但是所声明的变量只在let 命令所在的代码块内有效

举个例子:

  • 对于var:
var a=[]
    for(var i=0;i<10;i++){
        a[i] = function(){
            console.log(i)
        }
    }
    a[6](); //10

在这个代码中,变量i 是var声明的,在全局范围内都有效,所以全局只有一个变量 i,每一次循环,变量i 的值都会发生改变,而循环内,被赋给数组a 的函数内部console.log(i) 中的i 指向全局的i 。也就是说,所有数组a的成员中的i 所指向的都是同一个i ,导致运行时最后输出的是最后一轮的i 值

  • 对于 let
var a=[]
    for(let i=0;i<10;i++){
        a[i] = function(){
            console.log(i)
        }
    }
    a[6](); //10

在这个代码中,变量 i 是let声明的,当前的i 只在本轮循环内有效,所以每一次循环的i 其实都是一个新的变量
问题1
如果每一轮循环的变量 i都是重新声明的,那它怎么知道上一轮循环的值从而计算出本轮循环的值?

这是因为js 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算

问题2
for 循环有一个特别之处,就是设置循环变量的那部分其实是一个父作用域,而循环体内部是一个单独的子作用域。标明函数内部的变量 i和循环变量i不在同一个作用域,而是各有各自单独的作用域。

区别:

  1. 不存在变量提升
// var
console.log(foo)//undefined
var foo = 2 

// let
console.log(bar)
let bar = 2; //ReferenceError

let 改变了语法行为,它所声明的变量一定要在声明后使用,否则就会报错

  1. 暂时性死区

本质
只要进入当前作用域,所要使用的变量就已经存在,但是不可获取,只有等到声明变量的那一行代码出现时,才可以获取和使用该变量


在这里我涉及一点也是面试官问到我的问题:有关作用域,

  • 对于var而言,只要进入该作用域,所要使用的变量就已经存在,会被赋值为undefined,可以使用和和获取
  • 而对于let而言,只要进入该作用域,所要使用的变量也会存在,但是不能使用和获取
    (我想,这应该是面试官想听见的)

只要块级作用域里内存在let命令,它所声明的变量就绑定这个区域,不再受外部的影响

var tmp = 123
if(true){
	tmp = 123 //ReferenceError
	let tmp 
}

注意
ES6规定,如果区块中存在let 和const 这两个命令,则这个区块对这些命令声明的变量从一开始就形成封闭作用域。

  1. 不允许重复声明
    let 不允许在相同作用域内重复声明一个变量
//Error
function(){
	var a = 15;
	let a = 2;
}
//Error
function() {
	let a = 15;
	let a = 8;
}

const

  • 声明一个只读的常量,一旦声明,常量的值就不可以改变。
  • const一旦声明常量,就必须立即初始化,不能留到以后赋值
  • const 命令声明的常量作用域与let相同,只在声明所在的块级作用域有效,不会变量提升,同样存在暂时性死区,只能在声明后使用

本质
实际上保证的并不是变量的值不得改动,二是变量指向的那个内存地址不得改动;
const 只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,这不能控制


顶层对象的属性

顶层对象

  • 在浏览器中指的是windows对象
  • 在node中指的是global对象
  • ES5中,顶层对象与全局变量是等价的

  • var命令和 function 命令生成的全局变量是顶层对象的属性
  • let,const,class 命令声明的全局变量不属于顶层对象的属性
letconstvar
变量常量变量
不存在变量提升不存在变量提升存在变量提升(undefined)
暂时性死区暂时性死区不存在暂时性死区
不允许重复声明不允许重复声明允许重复声明
声明后允许不赋值(undefined)声明后必须初始化声明后允许不赋值(undefined)

2. mvc 和 mvvm

mvc = Model View Controller

模型 - 视图 - 控制器

  1. model 和 view 永远不能相互通信,只能通过 controller 传递
  2. controller 可以直接与 model 对话(读写调用model),model 通过notification 和 kvo 机制与controller 间接通信
  3. Controller可以直接与View对话,通过outlet,直接操作View,outlet直接对应到View中的控件,view 通过action向controller报告事件的发生(比如用户touch我了)。controller是view的直接数据源(数据很可能是controller 从model 中取得并经过加工了)。controller 是view 的代理。

缺点
在通常的开发中,除了简单的model,view 以外的所有部分都被放在了controller中,controller 负责显示界面,响应用户的操作,网络请求以及与model交互,这就导致了controller

  1. 逻辑复杂,难以维护
  2. 和view 紧耦合,无法测试

mvvm = model - viewmodel -view

一个 MVC 的增强版,我们正式连接了视图和控制器,并将表示逻辑从 Controller 移出放到一个新的对象里,即 View Model。MVVM 听起来很复杂,但它本质上就是一个精心优化的 MVC 架构

  • model: 数据的拥有者,实现具体的业务逻辑
  • ViewModel: 属于view+model,是一个放置用户输入验证逻辑,视图显示验证,发起网络等其他的地方。换句话说,就是把原来的View Controller 层的业务逻辑和页面逻辑等剥离出来放到viewModel层
  • view层:就是view层和viewController层,他的任务就是从view层获得数据,然后显示
    mvvm

mvvm的优点

  1. mvvm降低了一个视图控制器的复杂性
  2. mvvm与现有的mvc架构兼容
  3. mvvm使程序更容易测试
  4. mvvm适合使用绑定机制

mvvm 采用数据双向绑定,v的变动直接反应在vm上,m的变化也直接反应在vm上

数据双向绑定

文章详情:https://github.com/DMQ/mvvm

实现双向绑定的做法

  1. 发布者- 订阅模式(backbone.js)
    一般通过sub,pub的方式实现数据和视图的绑定监视,更新数据的方式通常是vm.set('property',value)
    我们更希望的是通过vm.set('property',value)这种方式更新数据,同时更新视图、

  2. 脏值检查(angular.js)
    angular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,angular只有在指定的事件触发时进入脏值检测(最简单的方式就是通过setInterval()定时轮询检测数据变动)

  3. 数据劫持(vue.js)
    vue.js是通过采用 数据劫持 的方式结合 发布者-订阅者 的方式,通过object.definePrpperty()来劫持各个属性的settergetter在数据变动时发布消息给订阅者,触发相应的监听回调

vue是什么?

vue是一个构建用户界面的框架库,目标是通过尽可能简单的api 实现相应的数据绑定和组合的视图集合,vue自身不是一个全能的框架,核心只是关心视图层。

3. js作用域和闭包

作用域

记得之前写过一篇作用域的文章
https://blog.csdn.net/Welkin_qing/article/details/80673682

先来介绍三个职位:

  • 引擎: 从头到尾,负责整个js 程序的编译及执行过程
  • 编译器: 引擎的好朋友之一,负责语法分析及代码生成等脏活和累活
  • 作用域: 引擎的另一位好朋友,负责收集并维护由所有变量(声明的标识符)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些变量的访问权限

作用域分为两个步骤:1. 声明 2. 查找
首先编译器会在当前作用域声明一个变量(如果之前没声明过),其次,在运行时引擎会在作用域查找该变量,如果找到会对它赋值。

闭包

  • 简单的理解是函数的嵌套形成闭包,闭包包括函数本身以及它的外部作用域
    闭包是指有权访问另一个函数作用域中的变量的函数(闭包就是能够读取其他函数内部变量的函数)
  • 创建闭包的常见方式就是:在一个函数内部创建另一个函数
  • 使用闭包可以形成独立的空间,延长变量的生命周期,包括中间状态值
  • 在本质上:闭包就是将函数内部和函数外部连接起来的一座桥梁

闭包的作用

  1. 读取函数内部变量值
  2. 让这些变量始终保存在内存中
  3. 可以形成独立的空间,延长变量的生命周期,保存中间状态值

注意
4. 闭包谨慎使用,不滥用,不乱用
5. 由于函数内部的变量都被保存在内存中,会导致内存消耗大

function outer(){
	var num = 1;
	function(){
		var n=2;
		alert(n+num)
	}
	return inner;
}
outer()();

4. v-model

引述:https://blog.csdn.net/xidongdong1/article/details/79539243

v-model虽然很像使用了双向数据绑定的 Angular 的 ng-model,但是 Vue 是单项数据流,v-model 只是语法糖而已。

第一行的代码其实只是第二行的语法糖。

<input v-model="sth" />
<input v-bind:value="sth" v-on:input="sth = $event.target.value" />

然后第二行代码还能简写成这样:

<input :value="sth" @input="sth = $event.target.value" />

要理解这行代码,首先你要知道 input 元素本身有个 oninput 事件,这是 HTML5 新增加的,类似 onchange ,每当输入框内容发生变化时,就会触发oninput,把最新的value传递给 sth。

我们仔细观察语法糖和原始语法那两行代码,可以得出一个结论:

在给元素添加v-model属性时,默认会把value作为元素的属性,然后把’input’事件作为实时传递value的触发事件

5. toast

引述:https://www.jianshu.com/p/ae0c4a055cce
步骤:

  1. 初始化toast:
    使用section设计toast 弹出内容,确保一个页面只有一个toast,对这个toast 设置隐藏使用section设计toast 弹出内容,确保一个页面只有一个toast,对这个toast 设置隐藏
  2. 显示toast
    • 显示toast时,需要确保上一个TimeOut已经被清空
    • 判断弹出内容,不能为空
  3. 隐藏toast
    判断TimeOut 是否存在,若存在则清空
/**
 * 用原生 JS 封装一个 Toast 组件
 */
var Toast = {
    // 隐藏的 setTimeOut 引用
    hideTimeOut: null,
    /**
     * 初始化
     */
    init: function () {
        var toastNode = document.createElement('section');
        toastNode.innerHTML = '<i class="iconfont icon-success"></i><i class="iconfont icon-error"></i><span class="text">111</span>';
        toastNode.id = 'toastWaka'; // 设置id,一个页面有且仅有一个Toast
        toastNode.setAttribute('class', 'toast');   // 设置类名
        toastNode.style.display = 'none';   // 设置隐藏
        document.body.appendChild(toastNode);
    },
    /**
     * 显示Toast
     * @param text 文本内容
     * @param type 类型 success error
     * @param duration 持续时间
     */
    show: function (text, type, duration) {
        // 确保上一次的 TimeOut 已被清空
        if (this.hideTimeOut) {
            clearTimeout(this.hideTimeOut);
            this.hideTimeOut = null;
            // console.error('上一次的 TimeOut 还未走完!');
            // return;
        }
        if (!text) {
            console.error('text 不能为空!');
            return;
        }
        var domToastWaka = document.getElementById('toastWaka');
        console.log('domToastWaka', domToastWaka);
        if (!domToastWaka) {
            console.error('toastWaka DOM 不存在!');
            return;
        }
        var domIconSuccess = domToastWaka.querySelector('.icon-success');   // 成功图标
        var domIconError = domToastWaka.querySelector('.icon-error');   // 错误图标
        var domToastText = domToastWaka.querySelector('.text');   // 文字
        domToastText.innerHTML = text || '';
        switch (type) {
            case 'success':
                domIconSuccess.style.display = 'inline';
                domIconError.style.display = 'none';
                break;
            case 'error':
                domIconSuccess.style.display = 'none';
                domIconError.style.display = 'inline';
                break;
            default:
                domIconSuccess.style.display = 'none';
                domIconError.style.display = 'none';
                break;
        }
        domToastWaka.style.display = 'block';
        // 不传的话默认2s
        var that = this;
        this.hideTimeOut = setTimeout(function () {
            domToastWaka.style.display = 'none';
            that.hideTimeOut = null;    // 置 TimeOut 引用为空
        }, duration || 2000);
    },
    /**
     * 隐藏 Toast
     */
    hide: function () {
        // 如果 TimeOut 存在
        if (this.hideTimeOut) {
            // 清空 TimeOut 引用
            clearTimeout(this.hideTimeOut);
            this.hideTimeOut = null;
        }
        var domToastWaka = document.getElementById('toastWaka');
        if (domToastWaka) {
            domToastWaka.style.display = 'none';
        }
    }
};

Toast.init();
Toast.show('123', 'success', 10000);
setTimeout(function () {
    Toast.hide();
}, 3000);

6. session,cookies

cookies

cookie是由服务器产生,保存在客户端本地的一个文件

  1. cookie 包含什么信息?
    可以记录你用户的id,密码,浏览过的网页,停留的时间等信息。
    当你再来到该网站时,网站通过读取cookies得知你的相关信息,就可以做出相应的动作(例如:显示标语,或者可以不用输入id、密码就直接登录等),一个网站只能读取他自己放置的信息,不能读取其他网站的cookie文件,因此,cookie文件还保存了host属性(网站的域名和ip)
    这些属性以名值对的方式进行保存,为了安全,内容进行了加密处理,cookie 文件的命名格式是:用户名@网站地址[数字].txt
  2. cookie的作用
    cookie的作用是与服务器进行交互(在浏览器和服务器来回传递),作为HTTP规范的一部分而存在。
    服务器和客户端都可以访问,大小只有4kb左右;存在有效期,过期后将会被删除。
    Cookies 的大小是受限的,并且每次你请求一个新的页面的时候Cookies都会被发送过去,这样无形浪费了带宽,另外,cookie还需要指定作用域,不可以跨域调用。
  3. cookie的优点
    • 给用户更人性化的使用体验,如记住“密码功能”,老用户登录欢迎语
    • 弥补了http无连接特性
    • 站点统计访问人数的一个依据
  4. cookie的缺点
    • 无法解决多人共用一台电脑的问题,带来不安全因素
    • cookie 文件容易被误删
    • cookie欺骗,修改host文件,可以非法访问目标站点的cookie

Web Storage

web storage 仅仅是为了在本地“存储”数据而生。
除此之外,web Storage 拥有setItem,getItem,removeItem,clear 等方法,不像cookie 需要前端开发者自己封装setCookie,getCookie。

  • session:(sessionStorage)中的数据,这些数据只有在同一个会话找那个的页面才能访问,并且当会话结束后数据也随之销毁,因此session 不是一种持久化的本地存储,仅仅是会话级别的存储。

  • localStorage:(本地存储)用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期。只有本地浏览器端可以访问数据,服务器不能访问本地存储直到故意通过POST 或者GET的通道发送到服务器;每个域5MB,没有过期数据,它将保留直到用户从浏览器清除或者使用js 代码清除。

cookie 和 sessionStorage localStorage

  • sessionStorage 和 localStorage 的存储空间更大
  • sessionStorage 和 localStorage 有更多的丰富易用的接口
  • sessionStorage 和 localStorage各自独立的存储空间

7. 中间件

引文:http://expressjs.com/en/guide/using-middleware.html
我之前写过一篇博客:https://blog.csdn.net/Welkin_qing/article/details/84175499

提及一下express:
express 是一个路由和中间件Web框架,它具有自己的最小功能:Express应用程序本质上是一系列中间件函数调用。

Express 应用程序可以使用以下类型的中间件:

  • 应用程序级中间件
  • 路由器级中间件
  • 错误处理中间件
  • 内置中间件
  • 第三方中间件

可以使用可选的装载路径加载应用程序级和路由器级中间级。还可以将一系列中间件功能加载在一起,从而在安装点创建中间件系统的子堆栈。
(详情见引述)


中间件函数是可以访问请求对象(req),响应对象(res)以及应用程序的请求,去响应周期中的下一个中间件函数的函数,下一个中间件函数通常由名为 next 的变量表示。

中间件的功能可以执行以下任务:

  • 执行任何代码
  • 更改请求和响应对象
  • 结束请求 - 响应循环
  • 调用堆栈中的下一个中间件函数

如果当前的中间件函数没有结束请求 - 响应周期,则必须调用 next() 以将控制传递给下一个中间件函数。否则,请求将被挂起。

8. js数据类型

  • 基本数据类型(7种)
String
Boolean
number
undefined
Null
Symbol
  • 引用数据类型
object(Array,Date,RegExp,Fuction)

  • js中的 typeof 返回哪种数据类型
object
number
function
boolean
undefined
string

在我最近看的书中,作者有介绍到:
js语言的每一个值都属于某一种数据类型,js语言规定了7中语言类型。语言类型广泛用于变量,函数参数,函数返回值等场合。根据最新的语言标准,这7种语言类型是:

  1. Undefined
  2. Null
  3. Boolean
  4. String
  5. Number
  6. Symbol
  7. Object

如何判定某变量是否为数组数据类型

  1. slice()
    可以自己给变量定义slice方法,但有时候会失效
  2. obj instanceof Array (在某些ie 版本中不正确)
  3. 在ES5中规定了Array.isArray() ,为了保证其兼容性,最好使用toString.call()
    toString.call() 常常用于判定数组,正则这些复杂类型
toString.call(18);  //[object Number]
toString.call(""); // [object String]

typeof 与 运行时类型的区别

typeof 的设计是有一定的缺陷的

示例表达式typeof结果运行时类型行为
nullobjectnull
{}objectobject
(function(){})functionobject
3numbernumber
“ok”stringstring
truebooleanboolean
void 0undefinedundefined
Symbol("a’)symbolsymbol

undefined null

所有的编程规范使用void 0 代替 undefined

  • undefined
    undefined 类型表示未定义。他的类型只有一个值,就是undefined。任何变量在赋值之前都是undefined 类型。且值为undefined。
    一般我们可以使用全局变量 undefined (就是名为undefined 的这个变量)来表达这个值,或者使用void 运算来把任何一个表达式变成undefined值。
    因为在js代码中undefined 是一个变量,而并非是一个关键字(这是js 语言公认的失误之一),所以,为了避免无意的篡改,建议使用void 0 来获取undefined的值
  • null
    null 表示“定义了但是为空”,所以,在实际编程中,我们一般不会把变量赋值为 undefined ,这样可以保证所有的值为 undefined 的变量,都是从未赋值的自然状态
    null 类型也只有一个值,就是null ,它的语义表示空值,与undefined 不同,null 是js关键字,所以在任何代码中,都可以放心使用null 关键字来获取null 值。

9. 箭头函数

  1. 允许使用箭头定义函数
var f = v => v
var f = function(v) {
	return v;
}
  1. 使用圆括号代表参数部分
var f = () => 5;
var f = function(){
	return 5
}

var sum = (num1, num2) => num1 + num2
var sum = function(num1, num2){
	return num1 + num2
}
  1. 如果箭头函数的代码块多于一条语句,就要使用大括号将其括起来,并使用return 返回
var sum = (num1, num2) => num1 + num2
var sum = function(num1, num2){
	return num1 + num2
}
  1. 如果箭头函数直接返回一个对象,必须在对象外面加上括号
var getTempItem = id => ({id: id,name:"Temp"})
  1. 箭头函数可以与变量解构结合使用
const full = ({first, last}) => first + '' + last
function full(person){
	return person.first + '' + person.last
}
  1. 简化回调函数
[1,2,3].map(function (x){
	return x*x;
})
// 箭头函数
[1,2,3].map(x => x*x)
//even
const isEven = n => n%2==0;
//square
const quare = n => n*n

注意事项

  • 箭头函数体内的this 对象就是定义时所在的对象,而不是使用时所在的对象
    this对象的指向是可变的,但在箭头函数中它是固定的
    箭头函数可以让this 指向固定化,有利于封装回调函数

this指向固定化原因
this指向固定化并不是因为箭头函数内部由绑定this的机制,实际原因是箭头函数根本没有this,导致内部的this 就是外层代码块的this(正是因为没有this 所以不能用作构造函数)

由于箭头函数没有自己的this,当然不能用call(),apply(),bind()这些方法改变this 的指向

function foo(){
	setTimeout(() =>{
		console.log('id:', this.id);
	}, 100)
}
var id = 21;
foo.call({id:42})
//id:42

如果是普通函数,执行时this 应该指向全局对象window,即应该输出21
箭头函数导致this 总是指向函数定义生效时所在的对象


  • 不可以当做构造函数。也就是说,不可以使用new命令,否则就会抛出一个错误
  • 不可以使用arguments 对象,该对象在函数体内不存在。如果要使用,可以使用rest 参数代替
  • 不可以使用 yield 命令,因此箭头函数不能用作Generator 函数

函数绑定运算符

:: 并排的双冒号
双冒号左边是一个对象,右边是一个函数

  1. 该运算符会自动将左边的对象作为上下文环境(即this对象)绑定在右边的函数上
foo;:bar;
//bar.bind(foo)

  1. 如果双冒号左边为空,右边是一个对象的方法,则等于将该方法绑定在该对象上
var method = obj::obj.foo
// var method = ::obj.foo

10. http

引述:http://www.sudu.cn/info/19700101/120044.html
在http中,客户端和服务端之间的会话总是由客户端通过建立连接和发送http请求包初始化,服务器不会主动联系客户端或者要求与客户端建立连接。
浏览器和服务器都可以随时中断连接。

HTTP请求里包括些什么内容?
http请求包(get post等其他请求方法)由三个部分组成
请求包的头部还会包含许多有关客户端环境和请求正文的有用信息

  • 方法-URL-协议版本
  • 请求头
  • 请求正文
    get请求
GET /index.jsp HTTP/1.1 //方法-URI-协议/版本:
  //index.jsp表示URI。URI指定了要访问的网络资源。//HTTP/1.1是协议和协议的版本。
Accept-Language: zh-cn
Connection: Keep-Alive 
Host: 1Array2.168.0.106
Content-Length: 37  //正文的长度
userName=new_andy&password=new_andy

HTTP响应里包括些什么内容?

  • 协议-状态代码-描述
  • 应答头
  • 应答正文
HTTP/1.1 200 OK
Server: Microsoft-IIS/4.0  //服务器类型
Date: Mon, 3 Jan 2005 13:13:33 GMT //日期时间
Content-Type: text/html  //内容类型
Last-Modified: Mon, 11 Jan 2004 13:23:42 GMT
Content-Length: Array0

HTTP应答包的第一行类似于HTTP请求的第一行,表示所用的协议是HTTP 1.1,服务器处理请求的状态码200。
  应答头也和请求头一样包含许多有用的信息,例如服务器类型、日期时间、内容类型和长度等。应答的正文就是服务器返回的HTML页面。应答头和正文之间也用CRLF分隔。


http状态码

  • 100-199 用于指定客户端响应的某些动作
  • 200-299 用于表示请求成功
    • 200 请求资源成功
  • 300-399 用于已经移动的文件并且常被包含在定位头信息中指定的新的地址信息
    • 301 被请求资源永久移动到新位置(并且将来对此资源的任何引用都应该使用本响应返回的若干URL之一)
    • 302 请求资源在临时从不同的URL响应请求(临时重定向)客户端应当继续向原有地址发送以后的请求
  • 400-499 用于指出客户端的错误
    • 400 客户端请求语法错误,不能被服务器所理解
    • 401 当前请求需要用户验证
    • 403 服务器已经理解请求,但是拒绝执行它
    • 413 请求资源过大
    • 404 请求资源不存在
  • 500-599 用于支持服务器错误
    • 500 服务器端错误
    • 503 服务器不可用(服务器当前不能处理客户端请求,一段时间可恢复)

http状态码

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值