1,手写vue数据双向绑定
Object.defineProperty()
姓名: <span id="spaName"></span>
<input type="text" id="inpName">
<script>
var obj = {
name: ''
}
var newObj = JSON.parse(JSON.stringify(obj))
Object.defineProperty(obj, 'name', {
get () {
return newObj.name
},
set (val) {
if (val === newObj.name) return
newObj.name = val
observer()
}
})
function observer () {
spaName.innerHTML = obj.name
inpName.value = obj.name
}
setTimeout(() => {
obj.name = 'haha'
},1000)
inpName.oninput = function () {
obj.name = this.value
}
</script>
Object.defineProperty()的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性
Object.defineProperty(obj, prop, desc)
obj 需要定义属性的当前对象
prop 当前需要定义的属性名
desc 属性描述符
javacript 有三种类型的属性:
1,命名数据属性:拥有一个确定的值的属性。这也是最常见的属性
2,命名访问器属性:通过getter和setter进行读取和赋值的属性
3,内部属性:由JavaScript引擎内部使用的属性,不能通过JavaScript代码直接访问到,不过可以通过一些方法间接的读取和设置。比如,每个对象都有一个内部属性[[Prototype]],你不能直接访问这个属性,但可以通过Object.getPrototypeOf()方法间接的读取到它的值。虽然内部属性通常用一个双吕括号包围的名称来表示,但实际上这并不是它们的名字,它们是一种抽象操作,是不可见的,根本没有上面两种属性有的那种字符串类型的属性
通过Object.defineProperty()为对象定义属性,有两种形式,且不能混合使用,分别为数据描述符,存取描述符,下面分别描述下两者的区别:
数据描述符 --特有的两个属性(value,writable)
let Person = {}
Object.defineProperty(Person, 'name', {
value: 'jack',
writable: true // 是否可以改变
})
存取描述符 --是由一对 getter、setter 函数功能来描述的属性
get:一个给属性提供getter的方法,如果没有getter则为undefined。该方法返回值被用作属性值。默认为undefined。
set:一个给属性提供setter的方法,如果没有setter则为undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认值为undefined。
let Person = {}
let temp = null
Object.defineProperty(Person, 'name', {
get: function () {
return temp
},
set: function (val) {
temp = val
}
})
数据描述符和存取描述均具有以下描述符
configrable 描述属性是否配置,以及可否删除
enumerable 描述属性是否会出现在for in 或者 Object.keys()的遍历中
configurable: false 时,不能删除当前属性,且不能重新配置当前属性的描述符(有一个小小的意外:可以把writable的状态由true改为false,但是无法由false改为true),但是在writable: true的情况下,可以改变value的值
configurable: true时,可以删除当前属性,可以配置当前属性所有描述符。
2,跨域问题的解决
3,数组去重:
var arr = [10, 20, 30, 40, 10, 20, 30, 40]
// 方法一: ES6 set
var arr1 = new Set(arr) //[10, 20, 30, 40] 此时,返回的是set这个类的实例 并不是数组
var arr2 = [...new Set(arr)]
var arr3 = Array.from(new Set(arr)) // Array.from()把类数组转化为数组 [10, 20, 30, 40]
console.log(arr, arr1, arr2, arr3) //arr2: [10, 20, 30, 40] 数组
扩展运算符...和Set的结合,让数组的map和filter方法也可以间接用于 Set 了。利用Set 可以很容易地实现并集(Union)、交集(Intersect)和差集(Difference):
let a = new Set([1,2,3])
let b = new Set([2,3,4])
// 合并
let all = new Set([...a, ...b])
console.log(all) // {1, 2, 3, 4}
// 交集
let same = new Set([...a].filter(x => b.has(x)))
console.log(same) // {2, 3}
// 差集
let diff = new Set([...a].filter(x => !b.has(x)))
console.log(diff) // {1}
方法二:拿当前项和后面的内容进行对比
let newArr = []
for (var i = 0; i < arr.length-1; i++) {
let idx = arr[i],
args = arr.slice(i+1)
if (args.indexOf(idx) > -1) {
newArr.push(idx)
}
}
console.log(arr, newArr) // [10, 20, 30, 40, 10, 20, 30, 40] [10, 20, 30, 40]
或
for (var i = 0; i < arr.length-1; i++) {
let idx = arr[i],
args = arr.slice(i+1)
if (args.indexOf(idx) > -1) {
arr[i] = null
}
}
let arr1 = arr.filter(i => i !== null)
console.log(arr1) // [10, 20, 30, 40]
indexOf可以改成includes
方法三: 对象键值对方法----拿数组中的每一项向容器中存储 如果已经存储过了 就把当前项干掉
let obj = {}
for (var i = 0; i < arr.length; i++) {
let idx = arr[i]
if (typeof obj[idx] !== 'undefined') {
arr[i] = arr[arr.length - 1]
arr.length--
i--
continue
}
obj[idx] = idx
}
console.log(arr) //[10, 20, 30, 40]
js检测对象中是否存在某个属性:
1,使用in关键字
var o={x:1}
"x" in o //true
2,使用对象的hasOwnProperty()方法
var o={x:1}
o.hasOwnProperty("x") //true
3,使用undefined判断
var o={x:1}
o.x!==undefined //true
4,数组排序
方法一:冒泡排序---思想就是两两比较 交换位置
function bubble (o) {
let temp = null
for (var i = 0; i < o.length - 1; i++) {
for (var j = 0; j < o.length - 1 - i; j++) {
if (o[j] > o[j + 1]) {
temp = o[j]
o[j] = o[j + 1]
o[j + 1] = temp
}
}
}
return o
}
let ary = [3,1,8,4,9,2,1];
ary = bubble(ary)
console.log(ary)
交换: 可以使用es6解构赋值
[o[j], o[j + 1]] = [o[j + 1], o[j]]
5,移动端适配 1px 的问题
首先说下造成1px的原因: 因为css的1px并不等于移动设备的1px, 这是因为不同的手机有不同的像素密度。在window对象中有一个devicePixelRation属性,他可以反应css中的像素和设备像素的像素比
解决:
方法一
WWDC对IOS的建议: 直接使用0.5px边框
其缺点: 仅支持IOS8+,不支持安卓
方法二:
使用边框图片border-image
.border-image-1px {
border: 1px solid transparent;
border-image: url: '../../01.png' 2 repeat;
}
优点: 可以设置单条,多条
缺点: 修改颜色麻烦,圆角需要特殊处理
方法三
使用box-shadow模拟边框
.box-shadow-1px {
box-shadow: inset 0 -1px 1px -1px #efefef;
}
优点: 使用简单,圆角也可以实现
缺点: 边框有阴影
方法四
伪类 + transform + 绝对定位
.scale-1px {
position: relative;
::after {
content: '';
width: 100%;
height: 1px;
background: #efefef;
position: absolute;
left: 0;
bottom: 0;
transform: scaleY(0.5)
}
}
6, 已知如下数组:var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
编写一个程序将数组扁平化去并除其中重复部分数据,最终得到一个升序且不重复的数组
var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10]
// 扁平化
let flatArr = arr.flat(4)
// 去重
let disArr = Array.from(new Set(flatArr))
// 排序
let result = disArr.sort(function(a, b) {
return a-b
})
console.log(result)
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
7,HTTP 和 HTTPS 区别
1, HTTPS使用443端口, HTTP使用80
2, HPPS需要申请证书
3, HTTP是超文本传输协议,是明文传输,HTTPS是经过SSL加密的协议,传输更安全
4, HPPS比HTTP慢,因为HTTPS除了TCP我握手的三个包,还要加上SSL握手的九个包
8,用CSS实现三角形
首先我们创建一个带边框的div:
div {
width: 100px;
height: 100px;
border-width: 100px;
border-style: solid;
border-color: red blueviolet gold greenyellow;
}
然后将内部DIV的宽高设置为0:
div {
width: 0px;
height: 0px;
border-width: 100px;
border-style: solid;
border-color: red blueviolet gold greenyellow;
}
将其他的三个边框给取消
div {
width: 0px;
height: 0px;
border-width: 100px;
border-style: solid;
border-color: transparent transparent transparent greenyellow;
}
01.png
02.png
03.png
9, px与rpx换算
px是微信小程序中css的尺寸单位,可以根据屏幕宽度进行自适配。
规定屏幕宽度为750px,譬如iphone6,屏幕宽度为375px,共有750个物理像素,则1rpx = 0.5px。
设备rpx换算px:屏幕宽度/750,px换算成rpx:750/屏幕宽度;
iPhone5 1rpx = 0.42px 1px = 2.34px
iPhone6 1rpx = 0.5px 1px = 2rpx
iPhone6s 1rpx = 0.552px 1px = 1.81rpx
10,跨域解决方案详解
跨域也就是非通源策略请求
三者都一样是同源,有其一不同就是跨域
- 协议
- 域名
- 端口号
方法一: JSONP 需要服务器支持 callback返回数据
基于script标签的开放策略
jquery中提供了JSONP的处理方式:
$.ajax({
url: 'https://www.baidu.com/home/msg/data/personalcontent?num=8&indextype=manht&_req_seqid=3524849935&asyn=1&t=1595229055903&sid=1443_31672_31253_32046_32231_32116_32092_32297_26350_32261',
method: 'get',
dataType: 'jsonp', // dataType
success: res => {
console.log(res)
}
})
JSONP只支持GET请求,不支持POST请求
script、link、img、iframe等标签不存在跨域请求的限制
方法二:CORS跨域资源共享 需要服务器支持
- 客户端发送ajax/fetch请求
- 服务器端设置相关的头信息(需要处理options试探性请求)
服务器端需要设置请求头里的允许什么请求源、请求方式等
CORS跨域弊端: 服务器设置请求头时候不能同时设置多个请求源 如果设置为* 就不能携带cookie
平时见到的options请求是在发送真正请求前先发送一个options试探性请求,服务器接收到options请求后直接返回成功
方法三: http proxy 这个一般要配合webpack-dev-server
proxy请求代理
proxy: {
'/': {
target: '请求地址',
changeOrigin: true
}
}
方法四: ngnix反向代理 不需要前端干啥
方法五:PHP端修改header
header(‘Access-Control-Allow-Origin:*’);//允许所有来源访问
header(‘Access-Control-Allow-Method:POST,GET’);//允许访问的方式
方法六:postMessage
方法七:websocket协议跨域
10, 弹性布局 flex
行内元素可以使用flex布局
display: flex || inline-flex
设置在容器上的属性有6种
- flex-direction 排列方向
- flex-wrap 定义换行情况
- flex-flow flex-direction和flex-wrap的简写,默认row nowrap
- justify-content 定义项目在主轴上的对齐方式
- align-item 定义在交叉轴上的对齐方式
- align-content 定义多根轴线的对齐方式
flex-direction: row(水平) | row-reverse | column(垂直) | column-reverse;
flex-wrap: nowrap | wrap | wrap-reverse;
wrap:换行,第一行在上方
wrap-reverse:换行,第一行在下方
flex-flow: <flex-direction> || <flex-wrap>;
justify-content: start | end | flex-start | flex-end | center | left | right | space-between | space-around | space-evenly | stretch | safe | unsafe | baseline | first baseline | last baseline;
flex-start(默认值):左对齐
flex-end:右对齐
space-between:两端对齐,项目之间间隔相等
space-around:每个项目两侧的间隔相等,即项目之间的间隔比项目与边框的间隔大一倍
align-items: flex-start | flex-end | center | baseline | stretch;
flex-start:起点对齐
flex-end:终点对齐;
baseline:项目的第一行文字的基线对齐
stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度
space-between:两端对齐,项目之间间隔相等:
image.png
space-around:每个项目两侧的间隔相等,即项目之间的间隔比项目与边框的间隔大一倍:
image.png
space-evenly: 均匀间隔:
image.png
flex-start:起点对齐:
image.png
flex-end:终点对齐:
image.png
baseline:项目的第一行文字的基线对齐:
image.png
stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度:
image.png
11,单点登录
单点登录: 一个登录入口可以进入所有的系统中、不用每个系统都搞一个登录
...
待完善
12,防抖和节流
防抖:对于短时间内连续触发的事件,防抖的含义是让某个时间限制内,事件处理函数只执行一次。
可以引入框架(underscore.js)
function doSomeThing () {}
_.debounce(doSomeThing, 1000)
防抖函数代码实现:
function debounce (func, wait) {
let timeout;
return function () {
clearTimeout(timeout)
timeout = setTimeout(func, wait)
}
}
节流:如果你持续触发事件,每隔一段时间,只执行一次事件
比如某个用户闲着无聊,按住滚动条不断的拖来拖去,只要不停止触发,防抖事件就会永远不输出内容,那么产品同学的期望是:即使用户不断拖动滚动条,也能在某个时间间隔之后给个反馈。
这时,就需要讨论解决方案:我们可以设计一种类似于控制阀门一样定期开放的函数,也就是让函数执行一次后,在某个时间内暂时失效,过了这段时间再重新激活
12,babel是什么,有什么作用?
babel是一个 ES6 转码器,可以将 ES6 代码转为 ES5 代码,以便兼容那些还没支持ES6的平台
13,举一些ES6对String字符串类型做的常用升级优化?
1、ES6新增了字符串模板,在拼接大段字符串时,用反斜杠(`)取代以往的字符串相加的形式,能保留所有空格和换行,使得字符串拼接看起来更加直观,更加优雅。
2、ES6在String原型上新增了includes()方法,用于取代传统的只能用indexOf查找包含字符的方法(indexOf返回-1表示没查到不如includes方法返回false更明确,语义更清晰), 此外还新增了startsWith(), endsWith(), padStart(),padEnd(),repeat()等方法,可方便的用于查找,补全字符串。
14,举一些ES6对Array数组类型做的常用升级优化
1、数组解构赋值
ES6可以直接以let [a,b,c] = [1,2,3]形式进行变量赋值,在声明较多变量时,不用再写很多let(var),且映射关系清晰,且支持赋默认值。
2、扩展运算符
ES6新增的扩展运算符(...)(重要),可以轻松的实现数组和松散序列的相互转化,可以取代arguments对象和apply方法,轻松获取未知参数个数情况下的参数集合。
扩展运算符还可以轻松方便的实现数组的复制和解构赋值(let a = [2,3,4]; let b = [...a])
3、ES6在Array原型上新增了find()方法
用于取代传统的只能用indexOf查找包含数组项目的方法,且修复了indexOf查找不到NaN的bug([NaN].indexOf(NaN) === -1).此外还新增了copyWithin(), includes(), fill(),flat()等方法,可方便的用于字符串的查找,补全,转换等。
15,举一些ES6对Object类型做的常用升级优化
1、对象属性变量式声明
ES6可以直接以变量形式声明对象属性或者方法,。比传统的键值对形式声明更加简洁,更加方便,语义更加清晰。
let [apple, orange] = ['red appe', 'yellow orange'];
let myFruits = {apple, orange}; // let myFruits = {apple: 'red appe', orange: 'yellow orange'}
尤其在对象解构赋值(见优化部分b.)或者模块输出变量时,这种写法的好处体现的最为明显:
let {keys, values, entries} = Object;
let MyOwnMethods = {keys, values, entries}; // let MyOwnMethods = {keys: keys, values: values, entries: entries}
可以看到属性变量式声明属性看起来更加简洁明了。方法也可以采用简洁写法:
let es5Fun = {
method: function(){}
};
let es6Fun = {
method(){}
}
2、对象的解构赋值
ES6对象也可以像数组解构赋值那样,进行变量的解构赋值:
let {apple, orange} = {apple: 'red appe', orange: 'yellow orange'};
3、对象的扩展运算符(...)
ES6对象的扩展运算符和数组扩展运算符用法本质上差别不大,毕竟数组也就是特殊的对象。对象的扩展运算符一个最常用也最好用的用处就在于可以轻松的取出一个目标对象内部全部或者部分的可遍历属性,从而进行对象的合并和分解。
let {apple, orange, ...otherFruits} = {apple: 'red apple', orange: 'yellow orange', grape: 'purple grape', peach: 'sweet peach'};
// otherFruits {grape: 'purple grape', peach: 'sweet peach'}
// 注意: 对象的扩展运算符用在解构赋值时,扩展运算符只能用在最有一个参数(otherFruits后面不能再跟其他参数)
let moreFruits = {watermelon: 'nice watermelon'};
let allFruits = {apple, orange, ...otherFruits, ...moreFruits};
4、ES6在Object原型上新增了is()方法
做两个目标对象的相等比较,用来完善'==='方法。'==='方法中NaN === NaN //false其实是不合理的,Object.is修复了这个小bug。(Object.is(NaN, NaN) // true)
5、ES6在Object原型上新增了assign()方法,用于对象新增属性或者多个对象合并
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
6、ES6在Object原型上还新增了Object.keys(),Object.values(),Object.entries()方法,用来获取对象的所有键、所有值和所有键值对数组。
16,举一些ES6对Function函数类型做的常用升级优化
1、优化部分:
a. 箭头函数(核心)。箭头函数是ES6核心的升级项之一,箭头函数里没有自己的this,这改变了以往JS函数中最让人难以理解的this运行机制。主要优化点:
Ⅰ. 箭头函数内的this指向的是函数定义时所在的对象,而不是函数执行时所在的对象。ES5函数里的this总是指向函数执行时所在的对象,这使得在很多情况下this的指向变得很难理解,尤其是非严格模式情况下,this有时候会指向全局对象,这甚至也可以归结为语言层面的bug之一。ES6的箭头函数优化了这一点,它的内部没有自己的this,这也就导致了this总是指向上一层的this,如果上一层还是箭头函数,则继续向上指,直到指向到有自己this的函数为止,并作为自己的this。
Ⅱ. 箭头函数不能用作构造函数,因为它没有自己的this,无法实例化。
Ⅲ. 也是因为箭头函数没有自己的this,所以箭头函数 内也不存在arguments对象。(可以用扩展运算符代替)
b. 函数默认赋值。ES6之前,函数的形参是无法给默认值得,只能在函数内部通过变通方法实现。ES6以更简洁更明确的方式进行函数默认赋值。
function es6Fuc (x, y = 'default') {
console.log(x, y);
}
es6Fuc(4) // 4, default
2、升级部分:
ES6新增了双冒号运算符,用来取代以往的bind,call,和apply。(浏览器暂不支持,Babel已经支持转码)
foo::bar;
// 等同于
bar.bind(foo);
foo::bar(...arguments);
// 等同于
bar.apply(foo, arguments);
17,Symbol是什么,有什么作用
所有Symbol()生成的值都是独一无二的,可以从根本上解决对象属性太多导致属性名冲突覆盖的问题。对象中Symbol()属性不能被for...in遍历,但是也不是私有属性。
18,Set是什么,有什么作用
Set是ES6引入的一种类似Array的新的数据结构,Set实例的成员类似于数组item成员,区别是Set实例的成员都是唯一,不重复的。这个特性可以轻松地实现数组去重。
19,Map是什么,有什么作用
Map是ES6引入的一种类似Object的新的数据结构,Map可以理解为是Object的超集,打破了以传统键值对形式定义对象,对象的key不再局限于字符串,也可以是Object。可以更加全面的描述对象的属性。
20,Proxy是什么,有什么作用
Proxy是ES6新增的一个构造函数,可以理解为JS语言的一个代理,用来改变JS默认的一些语言行为,包括拦截默认的get/set等底层方法,使得JS的使用自由度更高,可以最大限度的满足开发者的需求。比如通过拦截对象的get/set方法,可以轻松地定制自己想要的key或者value。下面的例子可以看到,随便定义一个myOwnObj的key,都可以变成自己想要的函数。
function createMyOwnObj() {
//想把所有的key都变成函数,或者Promise,或者anything
return new Proxy({}, {
get(target, propKey, receiver) {
return new Promise((resolve, reject) => {
setTimeout(() => {
let randomBoolean = Math.random() > 0.5;
let Message;
if (randomBoolean) {
Message = `你的${propKey}运气不错,成功了`;
resolve(Message);
} else {
Message = `你的${propKey}运气不行,失败了`;
reject(Message);
}
}, 1000);
});
}
});
}
let myOwnObj = createMyOwnObj();
myOwnObj.hahaha.then(result => {
console.log(result) //你的hahaha运气不错,成功了
}).catch(error => {
console.log(error) //你的hahaha运气不行,失败了
})
myOwnObj.wuwuwu.then(result => {
console.log(result) //你的wuwuwu运气不错,成功了
}).catch(error => {
console.log(error) //你的wuwuwu运气不行,失败了
})
20,Promise是什么,有什么作用
Promise是ES6引入的一个新的对象,他的主要作用是用来解决JS异步机制里,回调机制产生的“回调地狱”。它并不是什么突破性的API,只是封装了异步回调形式,使得异步回调可以写的更加优雅,可读性更高,而且可以链式调用。
21, for...in 和for...of有什么区别?
如果看到问题十六,那么就很好回答。问题十六提到了ES6统一了遍历标准,制定了可遍历对象,那么用什么方法去遍历呢?
答案就是用for...of。ES6规定,有所部署了载了Iterator接口的对象(可遍历对象)都可以通过for...of去遍历,而for..in仅仅可以遍历对象。
这也就意味着,数组也可以用for...of遍历,这极大地方便了数组的取值,且避免了很多程序用for..in去遍历数组的恶习。
上面提到的扩展运算符本质上也就是for..of循环的一种实现。
22,Generator函数是什么,有什么作用?
如果说JavaScript是ECMAScript标准的一种具体实现、Iterator遍历器是Iterator的具体实现,那么Generator函数可以说是Iterator接口的具体实现方式。
执行Generator函数会返回一个遍历器对象,每一次Generator函数里面的yield都相当一次遍历器对象的next()方法,并且可以通过next(value)方法传入自定义的value,来改变Generator函数的行为。
Generator函数可以通过配合Thunk 函数更轻松更优雅的实现异步编程和控制流管理。
23,async函数是什么,有什么作用?
async函数可以理解为内置自动执行器的Generator函数语法糖,它配合ES6的Promise近乎完美的实现了异步编程解决方案。
24, module、export、import是什么,有什么作用
module、export、import是ES6用来统一前端模块化方案的设计思路和实现方案。export、import的出现统一了前端模块化的实现方案,整合规范了浏览器/服务端的模块化方法,用来取代传统的AMD/CMD、requireJS、seaJS、commondJS等等一系列前端模块不同的实现方案,使前端模块化更加统一规范,JS也能更加能实现大型的应用程序开发。
import引入的模块是静态加载(编译阶段加载)而不是动态加载(运行时加载)。
import引入export导出的接口值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。
25, 如何判断一个对象是数组还是对象
1,typeof判断数据类型(判断数组跟对象都返回object)
console.log(typeof null); // "object"
console.log(typeof function () {
return 1;
}); // "function"
console.log(typeof '梦龙小站'); // "string"
console.log(typeof 1); // "number"
console.log(typeof a); // "undefined"
console.log(typeof undefined); // "undefined"
console.log(typeof []); // "object"
console.log(typeof NaN); // "number"
console.log(typeof {}); // "object"
2,instanceof判断对象的原型链是否是指向构造函数的prototype
var arr = [1,2,3,1];
console.log(arr instanceof Array)//true
3,对象的constructor属性
var arr = [1,2,3,1];
console.log(arr.constructor === Array)//true
4,Object.prototype.toString.call(arr)
利用对象的toString可以准确判断是什么类型,call()改变this指向,这里是借用Object的方法,然后有人可能会问为什么不直接用arr.toString而要借用Object的方法
console.log(Object.prototype.toString.call("jerry"));//[object String]
console.log(Object.prototype.toString.call(12));//[object Number]
console.log(Object.prototype.toString.call(true));//[object Boolean]
console.log(Object.prototype.toString.call(undefined));//[object Undefined]
console.log(Object.prototype.toString.call(null));//[object Null]
console.log(Object.prototype.toString.call({name: "jerry"}));//[object Object]
console.log(Object.prototype.toString.call(function(){}));//[object Function]
console.log(Object.prototype.toString.call([]));//[object Array]
console.log(Object.prototype.toString.call(new Date));//[object Date]
console.log(Object.prototype.toString.call(/\d/));//[object RegExp]
console.log(Object.prototype.toString.call(new Person));//[object Object]
5, es6的方法——Array.isArray()
Array.isArray([]) //true
26, null和undefined 是否相等
console.log(null==undefined)//true
console.log(null===undefined)//false
null: object类型,代表“空值”,代表一个空对象指针
undefined: undefined类型
null表示"没有对象",即该处不应该有值。典型用法是:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时或者return后面什么也没有,返回undefined。
网友评论