JS手撕(五) new、Object.create()、Object.assign()


JS手撕(五)    new、Object.create()、Object.assign()

new关键字

实现new关键字,首先得了解一下new关键字究竟干了什么。

new关键字主要干了四件事:

  1. 创建一个新对象

  2. 设置该对象的原型为构造函数的原型(保留原有原型链)

  3. 执行构造函数,this指向新对象

  4. 如果构造函数返回值是对象,返回该对象。否则,返回1创建的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function myNew(Func, ...args) {
// 1. 创建一个新对象
const obj = Object.create(null);

// 2. 设置该对象的原型为构造函数的原型(保留原有原型链)
Object.setPrototypeOf(obj, Func.prototype);

// 3. 执行构造函数,`this`指向新对象
const result = Func.apply(obj, args);

// 如果构造函数返回值是对象,返回该对象。否则,返回`1`创建的对象
return (typeof result === 'object' && result !== null)
? result
: obj;
}

因为Object.create()可以使用现有的对象来作为新建对象的原型,所以第12步是可以合在一起的。

即:

1
const obj = Object.create(Func.prototype);

测试:

1
2
3
4
5
6
7
8
9
function Person(name, age) {
this.name = name;
this.age = age;

// return { test: 'test' }
}

const person = myNew(Person, 'clz', 21);
console.log(person); // Person {name: 'clz', age: 21}

Object.create()

Object.create()方法用于创建一个新对象,使用现有的对象来作为新建对象的原型。

实现一个低配版的,不考虑第二个参数。

核心就是一种实现继承的方法。(道格拉斯·克罗克福德在一篇文章中介绍的一种实现继承的方法)

1
2
3
4
5
function object(o) {
function F() {}
F.prototype = o;
return new F();
}

完整代码:

1
2
3
4
5
6
7
8
9
10
11
function object(o) {
function F() { }
F.prototype = o;
return new F();
}


Object.myCreate = function (proto) {
const obj = object(proto);
return obj;
}

测试:

1
2
3
4
5
6
7
function Animal(type) {
this.type = type;
}

const pig = Object.myCreate(Animal);
pig.type = 'pig';
console.log(pig); // F {type: 'pig'}

还有一个问题:我们有时候会使用Object.create(null)创建一个没有原型的对象,但是现在是有问题的。

1
2
const obj = Object.myCreate(null);
console.log(obj);

所以还需要判断参数是null的时候,设置原型为null来实现能够创建一个没有原型的对象。

1
2
3
4
5
6
7
8
9
Object.myCreate = function (proto) {
const obj = object(proto);

if (proto === null) {
Object.setPrototypeOf(obj, null);
}

return obj;
}

Object.assign()

Object.assign()将所有可枚举并且是自身属性从一个或多个源对象复制到目标对象,返回修改后的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Object.myAssign = function (target, ...sources) {
sources.forEach(source => {
for (const key in source) {
// 可枚举

if (source.hasOwnProperty(key)) {
// 自身属性
target[key] = source[key];
}
}
})

return target;
}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const target = {
name: 'clz'
};

const source1 = {
name: '赤蓝紫'
};
const source2 = {
age: 21
};
const source3 = {
age: 999
};

const result = Object.myAssign(target, source1, source2, source3);
console.log(result); // {name: '赤蓝紫', age: 999}
console.log(target === result); // true

参考

GitHub - qianlongo/fe-handwriting: 手写各种js Promise、apply、call、bind、new、deepClone….

JavaScript之手撕new_战场小包的博客-CSDN博客


文章作者: 赤蓝紫
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 赤蓝紫 !
评论
  目录