# 九.前端手写

# 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.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

# 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
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

# 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

# 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

# 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

# 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

# 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

# 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

# 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
  • 创建 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
  • 获取 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
上次更新: 2022/6/29 上午12:09:44