javascript中几种实例化方式的对比
实例化的几种方式
许多前端程序员对于js中的类其实都是比较懵逼的,因为业务开发中几乎不需要用到,但是当你读一些库的源码时,又是绕不过去的。
新旧语法,各种奇奇怪怪的关于类的方法一大堆,看看相关帖子,越看越是摸不着头绪。
下面把几种常见方式放在一起,做个比较。
// 最经典的实例化方式,大家都知道
function Foo(name) {
this.name = name
return 1 //不使用new调用时的返回值
}
Foo.prototype.bar = 'bar' //构造函数的原型链增加属性
let foo = new Foo('xx') // {name: 'xx'} 如果用new,返回值不走return
console.log(foo);
console.log(foo.name); //xx 实例属性
console.log(foo.bar); //bar 原型属性
console.log(foo.constructor) // Foo
console.log(Foo('xx')) // 1 不用new调用,则返回return的值
new操作符到底干了些什么,请看下面的方式
// new的过程分解
// new到底是如何让一个函数执行完返回一个实例对象的
function Foo(name) {
this.name = name;
return this;
}
Foo.prototype.bar = 'bar' //构造函数的原型链增加属性
let obj = {}; // 声明一个实例
// 也可以用Object.setPrototypeOf,MDN上不推荐这种方式,__proto__也不是个通用属性,只在浏览器环境有
obj.__proto__ = Foo.prototype; //构造函数原型链指向实例的__proto__
let foo = Foo.call(obj, 'xx'); //执行构造函数,并修改this指向
console.log(foo);
console.log(foo.name); //xx 实例属性
console.log(foo.bar); //bar 原型属性
console.log(foo.constructor) // Foo
下面是用Object.create方式
// Object.create方式1
// Object.create的第一个参数就是实例的原型对象
const proto = {bar: 'bar'}
let foo = Object.create(proto)
foo.name = 'xx'
console.log(foo);
console.log(foo.name); //xx 实例属性
console.log(foo.bar); //bar 原型属性
console.log(foo.constructor) // Object
// Object.create方式2
// 传递Object.create的第二个参数,必须是个属性描述符
const proto = {bar: 'bar'}
let foo = Object.create(proto, {
name: {
writable:true,
configurable:true,
enumerable: true,
value: "xx"
},
})
console.log(foo);
console.log(foo.name); //xx 实例属性
console.log(foo.bar); //bar 原型属性
console.log(foo.constructor) // Object
还有最简单的方式
let foo = { name: 'xx' }
// 与上面等效
let foo = Object({ name: 'xx' })
// 与上面等效
let foo = new Object({ name: 'xx' })
console.log(foo.name); //xx 实例属性 没有原型属性
console.log(foo.constructor) // Object
当然还有es6的class语法,比较简单,没有那么多奇奇怪怪的东西,可以自己找资料学习。
实际上他们都是由构造函数生成的,可以认为前两种是自定义构造函数生成的,后面的是由Object构造函数直接生成的。
几种方式放在一起对比一下,就会对此知识点有一个更清晰的认识。
欢迎来我的b站空间逛逛
https://space.bilibili.com/395672451