# 九.前端手写

# 1.实现 let

(function () {
  for (var i = 0; i < 5; i++) {
    console.log(i);
  }
})()
1
2
3
4
5

# 2.const

参数 说明
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
上次更新: 2024/7/13 上午9:32:29