【JavaScript】手撕前端面试题:手写new操作符 手写Object

文章介绍了如何在JavaScript中通过`Object.setPrototypeOf`设置对象原型,使用`Function.prototype.apply`应用函数到对象,以及实现`Object.freeze`和手动实现`_objectFreeze`函数,重点讲解了原型链、不可枚举属性和`Symbol`的处理。
摘要由CSDN通过智能技术生成
// 补全代码
// 1. 创建一个空的简单 `JavaScript` 对象(即 `{}`);
// 2. 为步骤 1 新创建的对象添加属性 `\_\_proto\_\_`,将该属性链接至构造函数的原型对象(设置它的原型为构造函数的原型对象);
// 3. 将步骤 1 新创建的对象作为 `this` 的上下文;
// 4. 如果该函数没有返回对象,则返回 `this`。
const obj1 = {}; // 1
const Fn = arguments[0]; // 获取函数参数
Object.setPrototypeOf(obj1, Fn.prototype); // 2 
const obj2 = Fn.apply(obj1, [].slice.call(arguments, 1)) // 3 
return obj2 instanceof Object ? obj2 : obj1; // 4

}


`[].slice.call(arguments, 1)`的作用是获得一个`arguments`的拷贝数组,且该数组不含`arguments`的第一个元素。



> 
> 我们知道数组的`slice`方法能够截取原数组的部分内容(返回一个新数组,不会修改原数组),但参数数组`arguments`是一个伪数组并不具有`slice`这个方法,所以这里使用`call`将`[].slice`的`this`指定到`arguments`。
> 
> 
> 


测试一下:



function Fn(age) {
this.name = ‘Ailjx’
this.age = age
}
console.log(‘new’, new Fn(18));
console.log(‘_new’, _new(Fn, 18));


![在这里插入图片描述](https://img-blog.csdnimg.cn/3fa0383efa89492282682267562afee9.png)


## 2、手写Object.freeze


### 要求


补全`JavaScript`代码,要求实现`Object.freeze`函数的功能且该新函数命名为"`_objectFreeze`"




---


**[Object.freeze()](https://bbs.csdn.net/topics/618545628)函数介绍如下:**


`Object.freeze()` 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,**冻结一个对象后该对象的原型也不能被修改**。`freeze()` 返回和传入的参数相同的对象。


参数:


* `obj`  
 要被冻结的对象。


返回值:


* 被冻结的对象。


### 手撕代码


**需要注意的是:**


1. 注意**不可枚举**的属性也要重新冻结。
2. 注意 `Symbol` 类型作为 `key` 值的情况,也要冻结。
3. 注意只冻结对象自有的属性(使用 `for ... in` 会把原型链上的可枚举属性遍历出来)。
4. 注意不可扩展性(不能添加新属性,使用 `Object.preventExtensions()搭配configurable: false` 或 `Object.seal()` 实现,同时也相当于把原型链冻结)。



const _objectFreeze = object => {
// 补全代码
if (typeof object !== ‘object’ || object === null) {
throw new TypeError(the ${object} is not a object)
}

// Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括 Symbol 值作为名称的属性)组成的数组。
const keys = Object.getOwnPropertyNames(object);

// Object.getOwnPropertySymbols() 方法返回一个给定对象自身的所有 Symbol 属性的数组。
const symbols = Object.getOwnPropertySymbols(object);

[...keys, ...symbols].forEach(key => {
    // Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
    Object.defineProperty(object, key, {
        // 当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
        // configurable: false, // 如果下面使用的是Object.preventExtensions(object)而不是Object.seal(),则需要设置configurable: false
        
		// 当 writable 属性设置为 false 时,该属性被称为“不可写的”。它不能被重新赋值
        writable: false,
    })
})

// Object.seal()方法封闭一个对象,
// 阻止添加新属性并将所有现有属性标记为不可配置。
// 当前属性的值只要原来是可写的就可以改变。
// 不会影响从原型链上继承的属性。但 \_\_proto\_\_ ( 已弃用 ) 属性的值也会不能修改。
// Object.seal的效果相当于: 在Object.defineProperty时将configurable设置成false,同时对对象调用Object.preventExtensions。
Object.seal(object)

// Object.preventExtensions()方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。
// 该方法使得目标对象的 [[prototype]] 不可变;任何重新赋值 [[prototype]] 操作都会抛出 TypeError 。这种行为只针对内部的 [[prototype]] 属性,目标对象的其它属性将保持可变。
// Object.preventExtensions(object) 

return object

}


**知识点:**


* [Object.getOwnPropertyNames()](https://bbs.csdn.net/topics/618545628) 方法返回一个由指定对象的**所有自身属性**的属性名(**包括不可枚举属性**但**不包括 Symbol 值作为名称的属性**)组成的数组。
* [Object.getOwnPropertySymbols()](https://bbs.csdn.net/topics/618545628) 方法返回一个给定对象自身的所有 `Symbol` 属性的数组。
* [Object.defineProperty()](https://bbs.csdn.net/topics/618545628) 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
* [Object.seal()](https://bbs.csdn.net/topics/618545628) 方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。效果相当于: 在`Object.defineProperty`时将`configurable`设置成`false`,同时对对象调用`Object.preventExtensions`。
* [Object.preventExtensions()](https://bbs.csdn.net/topics/618545628) 方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。 
 
> 
> 
> 	+ `Object.preventExtensions`只防止添加属性,即不可扩展。
> 	+ `Object.seal`除了不可扩展,也不可配置。
> 	+ `Object.freeze`就像`freeze`的意思是被冻结,除了不可扩展,不可配置,也不可重写。
>


## 结语



> 
> 这篇文章的所有内容都出自于[牛客网的JS篇题库](https://bbs.csdn.net/topics/618545628):  
>  ![在这里插入图片描述](https://img-blog.csdnimg.cn/f93d4cc3a84e4dfeb2377956bb738e69.png)
> 
> 
> 


牛客网的`JS`题库非常贴合实际的,在写的过程查漏补缺能收获了很多,强烈将[牛客网](https://bbs.csdn.net/topics/618545628)推荐给大家!


如果本篇文章对你有所帮助,还请客官一件四连!❤️



> 
>  [**基础不牢,地动山摇!** 快来和博主一起来牛客网刷题**巩固基础知识**吧!](https://bbs.csdn.net/topics/618545628)
> 
> 
> 








![img](https://img-blog.csdnimg.cn/img_convert/30aa03a4db011298e9bc5ef8e45dbe4f.png)
![img](https://img-blog.csdnimg.cn/img_convert/aa9ff588e849a6d2dabf065622776c12.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

正的技术提升。**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值