开始
答案是肯定的,那为什么不是[1,2,3]呢?
本文首发于公众号「前端keep」,欢迎关注。
知识
首先看看官网上:
parseInt() 函数解析一个字符串参数,通过基数解析,返回一个整数或者NAN
parseInt() 的两个参数分别是string和radix
string就是要解析的字符串,radix就是基数
注意:
- 基数不在2-36之间,则返回值就是NAN
map 遍历数组,将数组中的每一个元素调用定义的回调函数,返回包含结果的数组
map()的第一个参数是回调函数,回调函数的三个参数分别是currentValue/index/arr
currentValue是当前值,index当前值的索引,arr当前元素属于的数组对象
解析
那么回到这道题中,['1','2','3'].map(parseInt)就可以等于
['1','2','3'].map(function('1',0)),
['1','2','3'].map(function('2',1)),
['1','2','3'].map(function('3',2))
接着
parseInt('1',0),
parseInt('2',1),
parseInt('3',2)
那么,第一个字符串‘1’基于基数0也就是10进制返回值是1
第二个的基数是1小于2,返回值为NAN
第三个中3是没有2进制的,返回值为NAN
延伸
function part(fn) {
return (...rest) => {
return fn.call(this, rest[0])
}
}
let a = ['1', '2', '3']
a.map(part(parseInt))
// [1, 2, 3]
为什么加个函数就返回没问题了呢
解析
function part(fn) {
return (...rest) => {
// console.log('rest', rest)
// rest (3) ["1", 0, Array(3)]
// rest (3) ["2", 1, Array(3)]
// rest (3) ["3", 2, Array(3)]
// console.log('rest[0]', rest[0])
// rest 1
// rest 2
// rest 3
// console.log(fn)
// parseInt() { [native code] }
// console.log('fn.call(this, rest[0])', fn.call(this, rest[0]))
//fn.call(this, rest[0]) 1
//fn.call(this, rest[0]) 2
//fn.call(this, rest[0]) 3
return fn.call(this, rest[0])
}
}
let a = ['1', '2', '3']
a.map(part(parseInt))
// [1, 2, 3]
- 先
...rest获取全部参数,即rest - 再获取每个参数中的索引为0的值,即rest[0]
- fn就是
parseInt()函数 - 接着fn用
call继承rest[0],执行函数就简化为parserInt('1'),parserInt('2'),parserInt('3') - 最后返回的值就是[1,2,3]
参考文献
为什么["1","2","3"].map(parseInt) 返回[1,NaN,NaN]?
防抖
防抖(debounce) 所谓防抖,就是指触发事件后在n秒内函数只能执行一次,如果在n秒内又触发了事件,则会重新计算函数执行时间。 防抖函数分为非立即执行版和立即执行版。
- 非立即执行:触发事件后函数不会立即执行,而是在n秒后执行,如果在n秒内又触发了事件,则会重新计算函数执行时间。
function debounce(func, wait) {
let timeout
return function () {
let context = this
let args = arguments
if (timeout) clearTimeout(timeout)
timeout = setTimeout(() => {
func.apply(context, args)
}, wait)
}
}
背景:产生事件时,首先执行立即执行函数setTimeout。 当鼠标移动时,会产生setTimeout,每移动一次就timeout增加一次, 当timeout有值时,就销毁定时器。如果停止移动,就不触发定时器, 那么timeout没有值,那么就执行加一操作。
获取this和参数,为了让debounce函数最终返回的函数this指向不变以及依旧能接受参数。
完整版:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
margin: 0;
padding: 0;
}
#con {
height: 100%;
width: 100%;
position: absolute;
line-height: 600px;
text-align: center;
color: #ff0000;
background-color: #ffff00;
font-size: 100px;
}
</style>
</head>
<body>
<div id="con">
</div>
<script>
let num = 1
let con = document.getElementById('con')
function count() {
con.innerHTML = num++
}
function debounce(func, wait) {
let timeout
return function () {
let context = this
let args = arguments
if (timeout) clearTimeout(timeout)
timeout = setTimeout(() => {
func.apply(context, args)
}, wait)
}
}
con.onmousemove = debounce(count, 1000)
</script>
</body>
</html>
- 立即执行:触发事件后函数会立即执行,然后n秒后不触发事件才能继续执行函数。
function debounce(func, wait) {
let timeout
return function () {
let context = this
let args = arguments
if (timeout) clearTimeout(timeout)
console.log('timeout',timeout)
let callNow = !timeout
timeout = setTimeout(() => {
timeout = null
}, wait)
if (callNow) func.apply(context, args)
}
}
当鼠标移动触发事件,进入debounce方法中。当执行setTimeout方法时,timeout为null,等一秒后再执行。在回到context/args赋值,如果此时timeout为null则不清除定时器。 并且callNow为ture,callNow为ture,那么执行加一操作。
完整版本:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
margin: 0;
padding: 0;
}
#con {
height: 100%;
width: 100%;
position: absolute;
line-height: 600px;
text-align: center;
color: #ff0000;
background-color: #ffff00;
font-size: 100px;
}
</style>
</head>
<body>
<div id="con">
</div>
<script>
let num = 1
let con = document.getElementById('con')
function count() {
con.innerHTML = num++
}
function debounce(func, wait) {
let timeout
return function () {
let context = this
let args = arguments
if (timeout) clearTimeout(timeout)
let callNow = !timeout
timeout = setTimeout(() => {
timeout = null
}, wait)
if (callNow) func.apply(context, args)
}
}
con.onmousemove = debounce(count, 1000)
</script>
</body>
</html>
双剑合璧
需要立即执行,则加上第三个参数,否则不加。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
margin: 0;
padding: 0;
}
#con {
height: 100%;
width: 100%;
position: absolute;
line-height: 600px;
text-align: center;
color: #ff0000;
background-color: #ffff00;
font-size: 100px;
}
</style>
</head>
<body>
<div id="con">
</div>
<script>
let num = 1
let con = document.getElementById('con')
function count() {
con.innerHTML = num++
}
function debounce(func, wait, immediate) {
let timeout
return function () {
let context = this
let args = arguments
if (timeout) clearTimeout(timeout)
if (immediate) {
let callNow = !timeout
timeout = setTimeout(() => {
timeout = null
}, wait)
if (callNow) func.apply(context, args)
} else {
timeout = setTimeout(() => {
func.apply(context, args)
}, wait)
}
}
}
con.onmousemove = debounce(count, 1000)
</script>
</body>
</html>
应用场景
- 窗口大小变化,调整样式
window.addEventListener('resize', debounce(handleResize, 200));
- 搜索框,输入后1000毫秒搜索
debounce(fetchSelectData, 1000);
- 表单验证,输入1000毫秒后验证
debounce(validator, 1000);
节流
连续触发事件,但是在n秒中只执行一次。节流会稀释函数的执行频率。
对于节流,一般有两种方式可以实现,分别是时间戳版和定时器版。 时间戳版:
function throttle(func, wait) {
var previous = 0
return function () {
let now = Date.now()
let context = this
let args = arguments
if (now - previous > wait) {
func.apply(context, args)
previous = now
}
}
}
在持续触发事件过程中,函数会立即执行,并且每1秒执行一次。
当时间每过去n秒后,执行加一事件。 完整版
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
margin: 0;
padding: 0;
}
#con {
height: 100%;
width: 100%;
position: absolute;
line-height: 600px;
text-align: center;
color: #ff0000;
background-color: #ffff00;
font-size: 100px;
}
</style>
</head>
<body>
<div id="con">
</div>
<script>
let num = 1
let con = document.getElementById('con')
function count() {
con.innerHTML = num++
}
function throttle(func, wait) {
var previous = 0
return function () {
let now = Date.now()
let context = this
let args = arguments
if (now - previous > wait) {
func.apply(context, args)
previous = now
}
}
}
con.onmousemove = throttle(count, 1000)
</script>
</body>
</html>
定时器版:
function throttle(func, wait) {
let timeout
return function () {
let context = this
let args = arguments
if (!timeout) {
timeout = setTimeout(() => {
timeout = null
func.apply(context, args)
}, wait)
}
}
}
持续触发事件时,每当n秒后执行一次,timeout设为空。当为空又开始执行。
在持续触发事件的过程中,函数不会立即执行,并且每 1s 执行一次,在停止触发事件后,函数还会再执行一次。 我们应该可以很容易的发现,其实时间戳版和定时器版的节流函数的区别就是,时间戳版的函数触发是在时间段内开始的时候,而定时器版的函数触发是在时间段内结束的时候。
完整版:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
margin: 0;
padding: 0;
}
#con {
height: 100%;
width: 100%;
position: absolute;
line-height: 600px;
text-align: center;
color: #ff0000;
background-color: #ffff00;
font-size: 100px;
}
</style>
</head>
<body>
<div id="con">
</div>
<script>
let num = 1
let con = document.getElementById('con')
function count() {
con.innerHTML = num++
}
function throttle(func, wait) {
let timeout
return function () {
let context = this
let args = arguments
if (!timeout) {
timeout = setTimeout(() => {
timeout = null
func.apply(context, args)
}, wait)
}
}
}
con.onmousemove = throttle(count, 1000)
</script>
</body>
</html>
双剑合璧版:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
margin: 0;
padding: 0;
}
#con {
height: 100%;
width: 100%;
position: absolute;
line-height: 600px;
text-align: center;
color: #ff0000;
background-color: #ffff00;
font-size: 100px;
}
</style>
</head>
<body>
<div id="con">
</div>
<script>
let num = 1
let con = document.getElementById('con')
function count() {
con.innerHTML = num++
}
function throttle(func, wait, type) {
if (type === 1) {
console.log('css')
// 时间戳版:
let previous = 0
return function () {
let now = Date.now()
let context = this
let args = arguments
if (now - previous > wait) {
previous = now
func.apply(context, args)
}
}
} else if (type === 2) {
// 定时器版:
let timeout
return function () {
let context = this
let args = arguments
if (!timeout) {
timeout = setTimeout(() => {
timeout = null
func.apply(context, args)
}, wait)
}
}
}
}
con.onmousemove = throttle(count, 1000, 2)
</script>
</body>
</html>
集合 Set
ES6 新增的一种新的数据结构,类似于数组,但成员是唯一且无序的。 Set 本身是一种构造函数,用来生成 Set 数据结构。
new Set([iterable]);
Set 对象存储原始值或是对象引用的唯一值。
向 Set 加入值的时候,不会发生类型转换,所以 1 和‘1’是两个不同的值。Set 用‘Same-value-zero equality’算法来判断两个值是否不同,它类似于精确相等运算符(===),主要的区别是 NAN 等于自身,而精确相等运算符认为 NaN 不等于自身。
- Set 实例属性
- constructor:构造函数
- size:元素数量
-
Set 实例方法
-
操作方法 - add(value):相当 array 里的 push,新增 - delete(vallue):删除集合中 value - has(value):判断集合是否存在 value - clear():清空集合
-
遍历方法(遍历顺序为插入顺序) - keys():返回一个包含集合中所有键的迭代器 - values():返回一个包含集合中所有值的迭代器 - entries():返回一个包含 Set 对象中所有元素的键值对迭代器 - forEach(callback,this):用于对集合成员执行回调操作,如果提供了参数,回调中的 this 就是这个参数,没有返回值
Set 可默认遍历,默认迭代器生成函数是 values() 方法
所以, Set 可以使用 map、filter 方法
因此,Set 很容易实现交集(Intersect)、并集(Union)、差集(Difference)
差集还是有问题的
-
WeakSet
WeakSet 对象允许将弱引用对象储存在一个集合中 与 Set 的区别:
-
前者只能存储对象引用,不能存放值,而 Set 对象都可以
-
前者对象中存储的对象值都是被弱引用的,即垃圾回收机制不考虑其对该对象的应用,如果没有其他的变量或属性引用这个对象值,则这个对象将会被垃圾回收掉(不考虑改对象还存在于 WeakSet 中)。WeakSet 对象里有多少哥成员元素,取决于垃圾回收机制有没有运行,运行前后成员个数可能不一致,遍历结束后,有的成员可能取不到了(被垃圾回收),其实是无法被遍历的,也没法拿到它的所有元素
-
属性
- constructor:构造函数,任何一个具有 Iterable 接口的对象,都可以作参数
-
add(value):在 WeakSet 对象中添加一个元素 value
-
has(value):判断 WeakSet 对象中是否包含 value
-
delete(value):删除元素 value
-
clear():清空所有元素
字典(Map)
集合和字典的区别:
- 共同点:集合和字典可以存储不重复的值
- 异点:集合是[value,value]的形式储存元素,字典是[key,value]的形式储存
任何具有 Iterator 接口且每个成员都是一个双元素的数组的数据结构都可以当作Map构造函数的参数
如果读取一个未知的键,则返回 undefined。
注意,只有对同一个对象的引用,Map 结构才将其视为同一个键。这一点要非常小心。
上面代码的 set 和 get 方法,表面是针对同一个键,但实际上这是两个值,内存地址是不一样的,因此 get 方法无法读取该键,返回 undefined。
由上可知,Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。这就解决了同名属性碰撞(clash)的问题,我们扩展别人的库的时候,如果使用对象作为键名,就不用担心自己的属性与原作者的属性同名。
如果 Map 的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map 将其视为一个键,比如 0 和-0 就是一个键,布尔值 true 和字符串 true 则是两个不同的键。另外,undefined 和 null 也是两个不同的键。虽然 NaN 不严格相等于自身,但 Map 将其视为同一个键。
Map 的属性及方法
- 属性:
- constructor:构造函数
- size:返回字典中所包含的元素个数
-
操作方法:
- set(key, value):向字典中添加新元素
- get(key):通过键查找特定的数值并返回
- has(key):判断字典中是否存在键 key
- delete(key):通过键 key 从字典中移除对应的数据
- clear():将这个字典中的所有元素删除
-
遍历方法
- Keys():将字典中包含的所有键名以迭代器形式返回
- values():将字典中包含的所有数值以迭代器形式返回
- entries():返回所有成员的迭代器
- forEach():遍历字典的所有成员
Map 结构的默认遍历器接口(Symbol.iterator 属性),就是 entries 方法。
Map 结构转为数组结构,比较快速的方法是使用扩展运算符(...)。
与其他数据结构的相互转换
-
Map 转 Array
-
Array 转 Map
-
Map 转 Object
因为 Object 的键名都为字符串,而 Map 的键名为对象,所以转换的时候会把非字符串键名转为字符串键名。
-
Object 转 Map
-
Map 转 JSON
-
JSON 转 Map
WeakMap
是一组键值对的集合,其中的键是弱引用对象,而值可以是任意的。 注意,WeakMap 弱引用的只是键名,而不是键值。键值依然是正常引用。 WeakMap 中,每个键对自己所引用对象的引用都是弱引用,在没有其他引用和该键引用同一对象,这个对象将会被垃圾回收(相应的 key 则变成无效的),所以,WeakMap 的 key 是不可枚举的。
- 属性:
- constructor:构造函数
- 方法:
- has(key):判断是否有 key 关联对象
- get(key):返回 key 关联对象(没有则则返回 undefined)
- set(key):设置一组 key 关联对象
- delete(key):移除 key 的关联对象
总结:
- Set
- 无序且不重复的
- [value,value],键值和键名重复
- 可以遍历,方法有:add、delete、has、clear
- WeakSet
- 成员都是对象
- 成员都是弱引用,可以被垃圾回收机制回收,可以用来保存 DOM 节点,不容易造成内存泄漏
- 不能遍历,方法有:add、delete、has、clear
- Map
- 本质上是键值对的集合,字典
- 可以遍历,方法:set、delete、has、get、clear
- 可以跟各种数据格式转换
- WeakMap
- 只接受对象作为键名(null 除外),不接受其他类型的值作为键名
- 键名是弱引用,键值可以是任意的,键名所指向的对象可以被垃圾回收,此时键名是无效的
- 不能遍历,方法有:get、set、has、delete
字符串、数字、布尔、数组、对象、null、undefined
typeof, instanceof, isArray()?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<input id="show" style="width:300px;"/>
<script>
function getTime(){
var nowDate = new Date();
var year = nowDate.getFullYear();
var month = (nowDate.getMonth() + 1) > 10 ? nowDate.getMonth() + 1 : '0' + (nowDate.getMonth() + 1);
var day = nowDate.getDate() > 10 ? nowDate.getDate() : '0' + nowDate.getDate();
var hour = nowDate.getHours() > 10 ? nowDate.getHours() : (nowDate.getHours() == 0 ? 24 : '0' + nowDate.getHours());
var minutes = nowDate.getMinutes() > 10 ? nowDate.getMinutes() : '0' + nowDate.getMinutes();
var seconds = nowDate.getSeconds() > 10 ? nowDate.getSeconds() : '0' + nowDate.getSeconds();
var str= year +"-" + month + "-" + day + " " + hour + ":" + minutes + ":" + seconds;
document.getElementById("show").value = str;
}
window.setInterval("getTime()", 1000);
</script>
</body>
</html>
显示:object.style.display="block";
隐藏:object.style.display="none";
html的元素的事件就只有组件自带的的那么几个,
如onclick,onmousedown等等都是调用脚本执行
方法:
1. 在组件上直接激发事件
2. 在页面加载的时候就调用脚本激发组件的某个事件
3. 在后台利用后台代码强行执行组件的事件。
或:
4. 为HTML元素的事件属性赋值
5. 在JS中使用el.on*** = function() {…}
6. 使用DOM2的添加事件的方法 addEventListener或attachEvent
\n alert("text\ntext");
alert("再打个招呼。这里演示了" + "\n" + "如何在消息框中添加换行。")
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
var str = "abcdefgaddda";
var obj = {};
// 每个字符出现次数
for (let i = 0; i < str.length; i++) {
var key = str[i];
typeof obj[key] === 'undefined' ? obj[key] = 1 : obj[key]++
}
var max = -1;
var max_key = key;
// 排序
for (let key in obj) {
if (max < obj[key]) {
max = obj[key];
max_key = key;
}
}
document.write("字符:" + max_key + ",出现次数最多为:" + max + "次")
</script>
</body>
</html>
var reg = /^[a-zA-Z][a-zA-Z_0-9]{4,19}$/
console.log(reg.test("11a__a1a__a1a__a1a__"))
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
function parseQueryString(url) {
var result = {};
var arr = url.split("?");
if (arr.length <= 1) {
return result;
} else {
arr = arr[1].split("&");
arr.forEach(item => {
let a = item.split('=')
result[a[0]] = a[1]
})
return result;
}
}
var url = "http://witmax.cn/index.php?key0=0&key1=1&key2=2";
var ps = parseQueryString(url);
console.log(ps)
</script>
</body>
</html>
在页面中有如下html:
<div id="field">
<input type="text" value="User Name"/>
</div><span class="red"></span>
要求用闭包方式写一个JS从文本框中取出值并在标签span中显示出来。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="firld">
<input type="text" value="qiufeihong"/>
</div>
<span class="red"></span>
<script>
var result = (function () {
var value = document.getElementById("firld").children[0].value;
var all = document.getElementsByTagName("span");
for (let i = 0; i < all.length; i++) {
all[i].innerHTML = value;
}
})();
</script>
</body>
</html>
前提知识
- window.onscroll 为当前页面的页面滚动事件添加事件处理函数.
- window.onresize 用来获取或设置当前窗口的resize事件的事件处理函数
- window.onload 用于在网页加载完毕后立刻执行的操作,即当 HTML 文档加载完毕后,立刻执行某个方法。
- document.documentElement.scrollTop 获取滚动条位置
- document.documentElement.clientWidth 获取浏览器窗口文档显示区域的宽度,不包括滚动条。
- document.documentElement.clientHeight 获取浏览器窗口文档显示区域的高度,不包括滚动条。
- document.documentElement.offsetWidth 获取DOM文档的根节点html元素对象的宽度,即offsetWidth=width+padding+border,不包括margin。
- document.documentElement.offsetHeight 获取DOM文档的根节点html元素对象的高度,即offsetHeight=height+padding+border,不包括margin。
解析
- 当前页面的页面滚动、更改当前页面的大小和加载完成时执行下面方法
- 获取div,获取滚动条位置
- 浏览器窗口的宽度减去div的宽度为div的left属性的值
- 浏览器窗口的高度减去div的高度为div的top属性的值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.tit {
position: absolute;
width: 100px;
height: 100px;
background: red;
}
</style>
</head>
<body>
<div id="box" class="tit"></div>
<script>
window.onscroll = window.onresize = window.onload = () => {
var getDiv = document.getElementById('box');
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
getDiv.style.left = document.documentElement.clientWidth - getDiv.offsetWidth + 'px';
getDiv.style.top = document.documentElement.clientHeight - getDiv.offsetHeight + scrollTop + 'px';
}
</script>
</body>
</html>
课外知识
- document.documentElement.scrollWidth 获取html元素对象内容的实际宽度,即html元素对象的滚动宽度。
- document.documentElement.scrollHeight 获取html元素对象内容的实际高度,即html元素对象的滚动高度。
- document.documentElement.clientLeft 获取html元素对象的左边框的宽度。
- document.documentElement.clientTop 获取html元素对象的上边框的宽度。
- document.doucmentElement.offsetLeft 获取html元素对象相对于整个页面文档的位置,也就是html元素的margin。
- document.documentElement.offsetTop 获取html元素对象相对于整个页面文档的位置,也就是html元素的margin。
- document.documentElement.scrollLeft 设置或获取页面文档向右滚动过的像素数。
- document.documentElement.scrollTop 设置或获取页面文档向下滚动过的像素数。
先前知识
- document.body返回当前文档中的元素或者元素.
- nodeType 属性返回以数字值返回指定节点的节点类型。 如果节点是元素节点,则 nodeType 属性将返回 1。 如果节点是属性节点,则 nodeType 属性将返回 2。 如果节点是文本节点,则 nodeType 属性将返回 3。
- onmouseover 事件会在鼠标指针移动到指定的对象上时发生。
解析
- 获取body中的节点
- 如果是元素节点,鼠标移动到上面添加边框,移出来恢复
- 递归所有节点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.tit {
display: block;
width: 100px;
height: 100px;
background: yellow;
}
</style>
</head>
<body>
<div id="box" class="tit">div</div>
<p class="tit">p</p>
<a class="tit">a</a>
<script>
function mouseBorder(t) {
var c = t.childNodes
for (let i = 0; i < c.length; i++) {
var d = c[i];
if (d.nodeType == 1) {
d.onmouseover = function () {
this.style.border = '1px solid red'
}
d.onmouseout = function () {
this.style.border = ''
}
mouseBorder(d);
}
}
}
mouseBorder(document.body);
</script>
</body>
</html>
String,Number,Boolean
Window:
方法:setInterval,setTimeout,clearInterval,clearTimeout,alert,confirm,open
属性:name,parent,screenLeft,screenTop,self,top,status
Document
方法:createElement,execCommand,getElementById,getElementsByName,getElementByTagName,write,writeln
属性:cookie,doctype,domain,documentElement,readyState,URL,
解析
- 为空且不为object类型返回自身
- 根据原始值的类型创建同样类型的值
- 遍历原始值,将原始值中的对象和属性拷贝到新值,并返回
不反对用Ext.ux.clone,但是最好还是递归
function cloneObject(o) {
// 1. 是否是object,是否为空
if (!o || 'object' !== typeof o) {
return o;
}
// 2. 判断其是数组还是对象,并创建新的对象或数组
var c = 'function' === typeof o.pop ? [] : {};
// 3. 遍历对象或数组
for (let p in o) {
let v = o[p];
v && 'object' === typeof v ? c[p] = cloneObject(v) : c[p] = v
}
return c;
}
a = {
'name': 'qiufeihong'
}
b = cloneObject(a)
a.name = 'youyuxi'
console.log('a', a)
console.log('b', b)
Ele.className = “***”; //***在css中定义,形式如下:.*** {…}
A.prototype.B = C;
A是某个构造函数的名字
B是这个构造函数的属性
C是想要定义的属性的值
Ajax是多种技术组合起来的一种浏览器和服务器交互技术,
基本思想是允许一个互联网浏览器向一个远程页面/服务做异步的http调用,
并且用收到的数据来更新一个当前web页面而不必刷新整个页面。
该技术能够改进客户端的体验。包含的技术:
XHTML:对应W3C的XHTML规范,目前是XHTML1.0。
CSS:对应W3C的CSS规范,目前是CSS2.0
DOM:这里的DOM主要是指HTML DOM,XML DOM包括在下面的XML中
JavaScript:对应于ECMA的ECMAScript规范
XML:对应W3C的XML DOM、XSLT、XPath等等规范
XMLHttpRequest:对应WhatWG的Web Applications1.0规范(http://whatwg.org/specs/web-apps/current-work/)
AJAX交互模型
同步:脚本会停留并等待服务器发送回复然后再继续
异步:脚本允许页面继续其进程并处理可能的回复
跨域问题简单的理解就是因为JS同源策略的限制,a.com域名下的JS无法操作b.com或c.a.com下的对象,具体场景如下:
PS:(1)如果是端口或者协议造成的跨域问题前端是无能为力的
(2) 在跨域问题上,域仅仅通过URL的首部来识别而不会尝试判断相同的IP地址对应的域或者两个域是否对应一个IP
前端对于跨域的解决办法:
(1) document.domain+iframe
(2) 动态创建script标签
默认情况javascript是同步加载的,也就是javascript的加载时阻塞的,后面的元素要等待javascript加载完毕后才能进行再加载,对于一些意义不是很大的javascript,如果放在页头会导致加载很慢的话,是会严重影响用户体验的。
(1) defer,只支持IE
defer属性的定义和用法(我摘自w3school网站)
defer 属性规定是否对脚本执行进行延迟,直到页面加载为止。
有的 javascript 脚本 document.write 方法来创建当前的文档内容,其他脚本就不一定是了。
如果您的脚本不会改变文档的内容,可将 defer 属性加入到
(2) async:
async的定义和用法(是HTML5的属性)
async 属性规定一旦脚本可用,则会异步执行。
(3) 创建script,插入到DOM中,加载完毕后callBack,见代码:
复制代码 代码如下:
function loadScript(url, callback){
var script = document.createElement_x("script")
script.type = "text/javascript";
if (script.readyState){ //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" ||
script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
};
} else { //Others: Firefox, Safari, Chrome, and Opera
script.onload = function(){
callback();
};
}
script.src = url;
document.body.appendChild(script);
}
注释:有多种执行外部脚本的方法: •async 属性仅适用于外部脚本(只有在使用 src 属性时)。 •如果 async="async":脚本相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本将被执行) •如果不使用 async 且 defer="defer":脚本将在页面完成解析时执行 •如果既不使用 async 也不使用 defer:在浏览器继续解析页面之前,立即读取并执行脚本
有关链接:异步加载js的几种方式
Navigator 对象
navigator.appName 保存浏览器类型
navigator.appVersion 存有浏览器的版本信息
navigator.userAgent 用户代理
本文首发于公众号「前端keep」,欢迎关注。
最后,希望大家一定要点赞三连。
关注我的博客:blog地址