面试中常被考到的手撕代码:
Function.prototype.call2 = function(context) {
if (typeof this !== "function") {
throw new TypeError("Error");
}
// 默认上下文是window
context = context || window;
// 保存默认的fn
const { fn } = context;
// 将函数本身作为对象context的属性调用,自动绑定this
context.fn = this;
const args = [...arguments].slice(1);
const result = context.fn(...args);
// 恢复默认的fn
context.fn = fn;
return result;
};
Function.prototype.apply2 = function(context) {
if (typeof this !== "function") {
throw new TypeError("Error");
}
context = context || window;
const { fn } = context;
context.fn = this;
let result;
if (Array.isArray(arguments[1])) {
// 通过...运算符将数组转换为用逗号分隔的参数序列
result = context.fn(...arguments[1]);
} else {
result = context.fn();
}
context.fn = fn;
return result;
};
Function.prototype.bind2 = function(context) {
if (typeof this !== "function") {
throw new TypeError("Error");
}
const that = this;
// 保留之前的参数,为了下面的参数拼接
const args = [...arguments].slice(1);
return function F() {
// 如果被new创建实例,不会被改变上下文!
if (this instanceof F) {
return new that(...args, ...arguments);
}
// args.concat(...arguments): 拼接之前和现在的参数
// 注意:arguments是个类Array的Object, 用解构运算符..., 直接拿值拼接
return that.apply(context, args.concat(...arguments));
};
};
function instanceof2(left, right) {
let prototype = right.prototype;
// 沿着left的原型链, 看看是否有何prototype相等的节点
left = left.__proto__;
while (1) {
if (left === null || left === undefined) {
return false;
}
if (left === prototype) {
return true;
}
left = left.__proto__;
}
}
function cloneArr(src, target) {
for (let item of src) {
if (Array.isArray(item)) {
target.push(cloneArr(item, []));
} else if (typeof item === "object") {
target.push(deepClone(item, {}));
} else {
target.push(item);
}
}
return target;
}
function deepClone(src, target) {
const keys = Reflect.ownKeys(src);
let value = null;
for (let key of keys) {
value = src[key];
if (Array.isArray(value)) {
target[key] = cloneArr(value, []);
} else if (typeof value === "object") {
// 如果是对象而且不是数组, 那么递归调用深拷贝
target[key] = deepClone(value, {});
} else {
target[key] = value;
}
}
return target;
}
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Documenttitle>
<script>
const obj = {
value: ""
};
function onKeyUp(event) {
obj.value = event.target.value;
}
// 对 obj.value 进行拦截
Object.defineProperty(obj, "value", {
get: function() {
return value;
},
set: function(newValue) {
value = newValue;
document.querySelector("#value").innerHTML = newValue; // 更新视图层
document.querySelector("input").value = newValue; // 数据模型改变
}
});
script>
head>
<body>
<p>值是:<span id="value">span>p>
<input type="text" onkeyup="onKeyUp(event)" />
body>
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
<script>
const obj = {}
const newObj = new Proxy(obj, {
get: function(target, key, receiver) {
return Reflect.get(target, key, receiver)
},
set: function(target, key, value, receiver) {
if(key === 'value') {
document.querySelector('#value').innerHTML = value
document.querySelector('input').value = value
}
return Reflect.set(target, key, value, receiver)
}
})
function onKeyUp(event) {
newObj.value = event.target.value
}
script>
head>
<body>
<p>
值是:<span id="value">span>
p>
<input type="text" onkeyup="onKeyUp(event)">
body>
html>