1. js的数据类型有哪些,如何判断?
js的数据类型包括:
-
1.null
-
2.undefined
-
3.boolean
-
4.string
-
5.number
-
6.Symbol
判断js的数据类型方法:
1.typeof
typeof ''; // string 有效
typeof 1; // number 有效
typeof Symbol(); // symbol 有效
typeof true; //boolean 有效
typeof undefined; //undefined 有效
typeof null; //object 无效
typeof [] ; //object 无效
typeof new Function(); // function 有效
typeof new Date(); //object 无效
typeof new RegExp(); //object 无效
2.instanceof
instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。
instanceof (A,B) = {
var L = A.__proto__;
var R = B.prototype;
if(L === R) {
// A的内部属性 __proto__ 指向 B 的原型对象
return true;
}
return false;
}
Tips:数组无法用instanceof判断,ES5 提供了 Array.isArray() 方法 。该方法用以确认某个对象本身是否为 Array 类型。 从原型链可以看出,[] 的 proto 直接指向Array.prototype,间接指向 Object.prototype,所以按照 instanceof 的判断规则,[] 就是Object的实例。依次类推,类似的 new Date()、new Person() 也会形成一条对应的原型链 。因此,instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型。
3. constructor
当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用。
Tips:
-
null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。
-
函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object因此,为了规范开发,在重写对象原型时一般都需要重新给 constructor 赋值,以保证对象实例的类型不被篡改。
4. toString
toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。
对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。
Object.prototype.toString.call('') ; // [object String]
Object.prototype.toString.call(1) ; // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(Symbol()); //[object Symbol]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object global] window 是全局对象 global 的引用
2.Arry有哪些方法
-
concat()链接两个或多个数组;不改变原数组;返回被链接数组的一个副本
-
join()把数组元素放到一个字符串;不改变原数组;返回字符串
-
slice()从已有的数组中返回选定的元素;不改变原数组;返回一个新的数组
-
toString()把数组转为字符串;不改变原数组;返回一个新的数组
-
pop()删除数组最后一个元素,如果数组为空,则不改变数组,返回undefined;改变原有数组;返回被删除的元素
-
push()向数组末尾添加一个或多个元素;改变原数组;返回新数组的长度
-
reverse()颠倒数组中元素的顺序;改变原数组;返回该数组
-
shift()把数组的第一个元素删除,若为空数组,不进行操作,返回undefined;改变原数组;返回第一个元素的值
-
sort()对数组进行排序;改变数组;返回新数组
-
splice()从数组中添加/删除项目;改变数组;返回新数组
-
unshift()向数组的开头添加一个或多个个元素;改变原数组;返回新数组的长度。
3.简单实现字符串trim方法,去掉首位空格,有哪些方法?
<script type="text/javascript">
function trim(str){ //删除左右两端的空格
return str.replace(/(^\s*)|(\s*$)/g, "");
}
function ltrim(str){ //删除左边的空格
return str.replace(/(^\s*)/g,"");
}
function rtrim(str){ //删除右边的空格
return str.replace(/(\s*$)/g,"");
}
</script>
4. Vue实现双向绑定的原理
当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是为什么 Vue 不支持 IE8 以及更低版本浏览器。
每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。
5.为什么vue实例中的data属性要用函数返回
我们都知道基本数据类型存放在栈中,引用数据类型存放在堆中。
当一个组件被定义,data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。
6.状态管理
vue中都包含了一个data()函数,用于要响应的组件。如果模板中使用的data()属性值发生改变,组件视图将会更新。
要想弄清楚状态管理,不得不说组件之间的传值。
1.组件通过props将数据传递给子组件:
props传值我们需要将一个值绑定在子组件的prop属性上。
ParentComponent组件把numbers数组作为同名的props传递给ChildComponent。然后ChildComponent组件进行渲染。
2.子组件通过自定义事件进行传值给父组件
通过上面代码可以看出来子组件通过自定义事件$emit('number-added', Number(number))"传值给父组件,父组件通过@number-added="numbers.push($event)"监听自定义事件接收子组件的传值。
上面说了如何父子之间的传值,但是兄弟组件的传值怎么办?
Vue大致有三种方式可以管理兄弟之间的通讯:
- 使用全局的EventBus
EventBus是一个实例,用于支持独立组件之间发布和订阅自定义事件,换句话说EventBus是使用发布订阅模式进行数据的改变的。
- 使用简单的全局储存
简单的全局存储很接近Flux的状态管理,在store中定义一个初始化对象state和一个addNumbers方法,
import { store } from '../store.js';引入store然后在data中直接获取数据,同时可以在methods中修改方法。
export default {
name: 'NumberDisplay',
data: () => ({
storeState: store.state
}) ,
methods: {
addNumber(numberInput) {
store.addNumber(Number(numberInput))
}
}
}
- 使用类似Flux库的Vuex
Vuex是一个Store库在这个库中可以实现各个组件数据的共享:
State方法:该方法中只是定义需要共享的数据;最简单的用法就是直接在组件的computed计算属性中调用this.$store.state.count;如果在组件中需要多次调用可以使用mapState来简化代码;getter方法,在getter方法中可以过滤一下State里的数据从而获取到符合预期的数据。同时在组件中也可以使用mapGetters来批量获取计算属性。mutation方法:在该方法中主要是修改State方法中的数据,默认第一个参数是State,在组件中使用commint方法调用this.$store.commit('hotel/setPickCity',data);(第一个参数为Store所在的位置,第二个为数据);如果同时要改变多个数据可以使用mapMutations辅助函数来操作;为了避免在mutation中异步同步同时使用,所以统一mutation方法中都是同步事件;action方法:在该方法中只要是异步获取数据,然后使用commint调取mutation里的方法实现改变state里的方法。
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。在组建中我们使用
this.$store.dispatch('xxx')来分发action,或者使用mapAction,进行多个方法的简化;
总的来说vuex中数据改变的方法大致就是:定义一个state函数后,getter函数可以过滤一些数据供其他组件使用,同时mutation来改变state里的数据,action通过调用mutation里的方法改变state数据。
7.computed、methods和watch的使用和区别
computed计算属性,简单的说computed就是可以处理任何复杂逻辑的方法类似于过滤器。在这个方法中可以按照我们的要求处理数据。computed有get和set方法可以使用。
计算属性是基于它们的依赖进行缓存的。只在相关依赖发生改变时它们才会重新求值。
所以如果依赖不变,那么就不会调用computed相对来说性能比较好。
methods方法,这个属性简单的来说就是function,可以定义方法进行属性的修改或者返回。与computed相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。watch侦听属性,当有数据需要根据其他数据的变动而变动的时候就需要用watch进行侦听回调,使用的场景大多用以异步请求。
8.URL从渲染到页面展现发生了什么?
简单的说浏览器打开URL时发生了:
- 第一步:DNS解析把域名解析成了IP地址,
- 第二步:进行TCP协议传输,TCP三次握手
- 第三步:发生HTTP请求,
- 第四步:服务器除了请求并返回HTTP报文
- 第五步:浏览器解析渲染页面
- 第六步:断开连接:TCP四次回收 在这个过程中要明白URL是什么? URL:统一资源定位符,用于定位互联网上的资源,俗称网址; 一般遵循以下语法规则:
scheme://host.domain:port/path/filename
https://www.baidu.com/123
-
scheme:协议类型。常见的协议有http、https、ftp、file,http和https的差别在于https是加密的,http1.0和1.1的差别是1.1支持多个请求对应一个TCP链接,http默认的端口是80,https默认的是443; -
host:定义域主机。默认www还有其他二级域名; -
domain:域名; -
port:端口号; -
path:路径; -
filename:文件名称;
http请求分为三部分,TCP三次握手、http请求响应、关闭TCP连接。
-
TCP三次握手用于同步客户端和服务端序列号和确认号,并交换TCP窗口大小信息。为了避免失效的链接突然传入服务端而进行三次握手。 -
三次握手后开始发送请求报文;请求报文包括:请求行、请求头、请求体。
请求行包括:请求方法、URL、协议版本, 常用的http请求方法包括get、post、put、delet、head、options。get是用于获取数据;post用于提交数据;put用于传输文件,报文主题包含文件内容,保存到对应的URL位置;head获取报文首部,与get类似,只不过返回报文主体,一般验证URL是否有效;delete用于删除文件,与put相反,删除对应的URL位置文件;option查询相应的URL支持的HTTP方法;get和post的差别:get是获取数据传输的数据比较小post是提交数据,传输的数据比较大;get把参数加到URL并且可以作为书签收藏,所以不安全,post相对来说比较安全;他们的最大的区别在于post不是幂等性而get是。 请求头:请求头包括请求的附加信息,由key/value组成,中间由冒号隔开,一般包含host,user-agent等; 请求体:name=tom&password=1234&realName=tomson包含多个请求参数,注意并不是所有请求都有请求数据。 -
响应报文包括:响应行、响应头。响应体。
- 1xx:已接收,正在处理
- 2xx:成功
- 3xx:重定向,304成功 但是数据为改变
- 4xx:客户端请求错误
- 5xx:服务器端错误
响应头和请求头类似,由key/value组成,包含返回的数据格式等。
响应主体包含回车符、换行符和响应返回数据,并不是所有响应报文都有响应数据。
为了保证http请求的简单所以http请求是无状态的一种协议,这个无状态是指无登录状态,http不会记录是那个人发出的请求,这样的好处是使传输更加简单。
为了解决一些需要登录的请求就引入了cookie、session的概念;
cookie是一小段文本信息,http请求时会带上它然后服务器检查cookie传输不同的数据。
session是在服务器端记录用户状态的一个机制,Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。
浏览器拿到响应的HTML文本后会根据浏览器的渲染机制进行渲染:
- 根据HTML解析出DOM树
- 根据css解析生成css规则树(css会阻塞dom的渲染和js的加载)
- 结合DOM树和CSS规则树生成渲染树
- 根据渲染树计算每一个节点信息
- 根据计算好的信息绘制页面
断开连接发起TCP四次挥手。