# 九.前端手写
# 1.实现 let
babel 在 let 定义的变量前加了道下划线,避免在块级作用域外访问到该变量,除了了对变量名的转换,我们也可以通过只执行函数来模拟块级作用域
;(function () {
for (var i = 0; i < 5; i++) {
console.log(i)
}
})()
console.log(i)
1
2
3
4
5
6
2
3
4
5
6
# 2.const
实现 const 的关键在于 Object.defineProperty()这个 API,这个 API 用于在一个对象上增加或修改属性,通过配置属性描述符,可以精确的控制属性的行为。Object.defienProperty()接受三个参数:
Object.defineProperty(obj, prop, desc)
1
参数 | 说明 |
---|---|
obj | 其定义属性的对象 |
prop | 要定义或修改的属性的名称 |
descriptor | 将被定义或修改的属性描述符 |
属性描述符 | 说明 | 默认值 |
---|---|---|
value | 该属性对应的值,可以是任何有效的 JavaScript 值(数值、对象、函数等)。 | undefined |
get | 一个给属性提供 getter 的方法,如果没有 getter 则为 undefined | undefined |
set | 一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。当属性值修改时,触发执行该方法 | undefined |
writable | 当且仅当该属性的 writable 为 true 时,value 才能被赋值运算符改变,默认为 false | false |
enumerable | enumerable 定义了对象的属性是否可以在 for...in 循环和 Object.keys()中被枚举 | false |
Configurable | configurable 特性表示对象的属性是否可以被删除,以及除 value 和 writable 特性外的其他特性是否可以被修改 | false |
对于 const 不可修改的特性,我们通过设置 writable 属性来实现
function _const(key,value){
const desc={
value,
writable:false
}
Object.defineProperty(window,key,desc)
}
_const('obj',{a,1})
obj.b = 2
obj = {}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 3.手写 call
# 4.手写 apply
# 5.手写 bind
- 一句话概况
- 1.bind()返回一个新函数,并不会立即执行
- 2.bind 的第一个参数将作为他运行时的 this,之后的一系列参数将会在传递的实参前传入作为他的参数
- 3.bind 返回函数作为构造函数,就是可以 new 的,bind 时指定的 this 值就会消失,但传入的参数依然生效
Function.prototype.bind = function () {
var self = this
var context = [].shift.call(arguments)
var args = [].slice.call(arguments)
return function () {
return self.apply(contxt, [].concat.call(args, [].slice.call(arguments)))
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Function.prototype._bind = function () {
var self = this
var context = [].shift.call(arguments)
var args = arguments
return function () {
self.call(context, ...args, ...arguments)
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 6.手写防抖
function debounce(fn, wait) {
var timer
return function () {
var context = this
var args = arguments
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(context, args)
}, wait)
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 7.手写节流
function throttle(fn, wait) {
var timer
return function () {
var context = this
var args = arguments
if (!timer) {
timer = setTimeout(() => {
timer = null
fn.apply(context, args)
}, wait)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 8.手写 clone
可以对 javascirpt 中的 5 种主要的数据类型(包含 number,string,object,array,boolean)进行复制
Object.prototype.clone = function () {
//对象的深拷贝 获取对应的构造函数 [] 或者{}
var newObject = this.constructor === Array ? [] : {}
//遍历对象的
for (let a in this) {
newObject[a] = typeof this[a] === "object" ? this[a].clone() : this[a]
}
return newObject
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 9.手写 promise
class Promise {
constructor(executor) {
this.status = "pending"
this.value = undefined
this.reason = undefined
this.onResolvedCallbacks = []
this.onRejectedCallbacks = []
let resolve = (value) => {
if (this.status === "pending") {
this.status = "resolved"
this.value = value
this.onResolvedCallbacks.forEach((fn) => fn())
}
}
let reject = (reason) => {
if (this.status === "pending") {
this.status = "rejected"
this.reason = reason
this.onRejectedCallbacks.forEach((fn) => fn())
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFullFilled, onRejected) {
if (this.status == "resolved") {
onFullFilled(this.value)
}
if (this.status === "rejected") {
onRejected(this.reason)
}
if (this.status === "pending") {
this.onResolvedCallbacks.push(() => {
onFullFilled(this.value)
})
this.onRejectedCallbacks.push(() => {
onRejected(this.reason)
})
}
}
}
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("hello world")
}, 100)
})
p.then(
(data) => {
console.log(data)
},
(error) => {
console.log(error)
}
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# 10.发布订阅
var event = {
clientListen: [],
trigger: function () {
for (var i = 0; i < this.clientListen.length; i++) {
var fn = this.clientListen[i]
fn.apply(this, arguments)
}
},
listen: function (fn) {
this.clientListen.push(fn)
},
}
event.listen(function (time) {
console.log("正式上班时间为:" + time)
})
event.trigger("2018/7")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 11.双向数据绑定
<body>
<div id="app">
<input type="text" id="txt" />
<p id="show"></p>
</div>
</body>
<script type="text/javascript">
var obj = {}
Object.defineProperty(obj, "txt", {
get: function () {
return obj
},
set: function (newValue) {
document.getElementById("txt").value = newValue
document.getElementById("show").innerHTML = newValue
},
})
document.addEventListener("keyup", function (e) {
obj.txt = e.target.value
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 12.js 的 new 操作符做了什么
1、新建一个对象
2、将新建对象的原型(__proto__
)指向构造函数的 prototype
3、将构造函数中的 this 指向新建对象
如果不要父类属性和方法,在函数的 prototype 上去 new 这个父类。
function A() {}
var a = new A()
//实现
var o = new Object()
o.__proto__ = A.prototype
A.call(o)
1
2
3
4
5
6
2
3
4
5
6
# 13.获取和设置 cookie
- 创建 cookie
function setCookie(name, value, expires, path, domain, secure) {
var cookieText = encodeURIComponent(name) + "=" + encodeURIComponent(value)
if (expires instanceof Date) {
cookieText += "; expires=" + expires
}
if (path) {
cookieText += "; expires=" + expires
}
if (domain) {
cookieText += "; domain=" + domain
}
if (secure) {
cookieText += "; secure"
}
document.cookie = cookieText
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- 获取 cookie
function getCookie(name) {
var cookieName = encodeURIComponent(name) + "="
var cookieStart = document.cookie.indexOf(cookieName)
var cookieValue = null
if (cookieStart > -1) {
var cookieEnd = document.cookie.indexOf(";", cookieStart)
if (cookieEnd == -1) {
cookieEnd = document.cookie.length
}
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
← 八.前端算法