AGx*_*162 5 javascript inheritance object prototypal-inheritance
这是一个相当普遍的问题,来自学习阶段的新手,我需要澄清一些问题.
我目前正在学习对象,此时我正在学习继承.在本课程的这一点上,我已经学习了几种创建对象的方法,但使用this关键字的对象似乎具有最多的功能:
function Person(){
this.eyes = 2;
this.ears = 2;
this.arms = 2;
this.hands = 2;
this.feet = 2;
this.legs = 2;
this.species = "Homo sapien";
}
Run Code Online (Sandbox Code Playgroud)
我理解我可能会使用它,但后来有一个以这种方式创建的对象:
var person = new Object();
person.eyes = 2;
person.ears = 2;
person.arms = 2;
person.hands = 2;
person.feet = 2;
person.legs = 2;
person.species = "Homo sapien";
Run Code Online (Sandbox Code Playgroud)
因为我似乎能够用前者做后者,后者无法做到,所以我想知道为什么我不会一直使用前一种方法.任何人都可以帮我解决这个问题吗?我不需要详细的答案(尽管我会感激).这只是一个我想摆脱困境的问题,所以我不想详述.
T.J*_*der 11
前言:如果你不确定我的意思是下面的"原型"这个词,请跳到分频器下方进行解释,然后回到这里到答案的顶部.:-)
假设您在第一个示例中然后Person通过new以下方式致电:
var person = new Person();
Run Code Online (Sandbox Code Playgroud)
...然后,它person与你使用第二个例子得到的那个之间的唯一区别与继承有关:创建的一个new Person被赋予对象Person.prototype作为其底层原型.
我想知道为什么我不会一直使用前一种方法有任何理由
如果您不需要使用原型,那么使用构造函数可能会不必要地复杂化.请注意,您的第二个表单可以更简洁地写出:
var person = {
eyes: 2,
ears: 2,
arms: 2,
hands: 2,
feet: 2,
legs: 2,
species: "Homo sapien"
};
Run Code Online (Sandbox Code Playgroud)
这称为对象初始值设定项:它使用您看到的属性创建一个新对象.从来没有必要使用x = new Object(); 如果你想要一个新的空白对象,只需使用x = {};.
当一个对象是一次性的时,直接创建它通常是创建它的最简单方法.
构造函数的关键优势在于它们是基本相似的对象的工厂:具有相同的初始属性集,具有相同的底层原型等.并且该函数可以接受参数并使用它们来装备它创建的对象以适当的方式,也许对构造参数等进行一些验证.这就是:它们集中了初始化逻辑.
构造函数不是具有函数工厂的唯一方法.你也可以这样做:
function buildPerson() {
return {
eyes: 2,
ears: 2,
arms: 2,
hands: 2,
feet: 2,
legs: 2,
species: "Homo sapien"
};
}
var person = buildPerson();
Run Code Online (Sandbox Code Playgroud)
如果你想让那个人拥有原型(ES5浏览器和更高版本):
var personPrototype = {
// ...properties for the person prototype...
};
function buildPerson() {
var obj = Object.create(personPrototype);
obj.eyes = 2;
obj.ears = 2;
obj.arms = 2;
obj.hands = 2;
obj.feet = 2;
obj.legs = 2;
obj.species = "Homo sapien";
return obj;
}
var person = buildPerson();
Run Code Online (Sandbox Code Playgroud)
(还有另一种更详细的方法来定义这些属性.)
JavaScript非常灵活.:-)
JavaScript使用原型继承,这是一种奇特的方式,说对象A可以被对象B"支持",这样如果你向A询问它没有的属性,JavaScript引擎将查看该属性是否存在在B.一个快速的实际例子:
var proto = {
name: "proto's name"
};
var obj = Object.create(proto); // Creates an object backed by the given prototype
Run Code Online (Sandbox Code Playgroud)
不要担心Object.create,现在你需要知道的是它创建了一个新对象,并根据你传入它的对象分配它的底层原型.所以obj得到了支持proto.
obj没有name财产,但如果我们这样做:
console.log(obj.name);
Run Code Online (Sandbox Code Playgroud)
......我们看到了"proto's name".那是因为当JavaScript引擎试图从中获取name价值时obj,它发现它obj没有name属性,所以它看起来obj是原型,proto.在那里找到它,它使用了来自的价值proto.
只有在获得值时才会发生这种情况(除了我们现在可以忽略的一些高级情况).当设置属性的值,它被设置你设置它的对象.所以:
var proto = {
name: "proto's name"
};
var obj = Object.create(proto); // `obj` is backed by `proto`
console.log(obj.name); // "proto's name"
obj.name = "obj's name";
console.log(obj.name); // "obj's name"
Run Code Online (Sandbox Code Playgroud)
原型的目的是重用,因此对象可以成为其他几个对象的原型也就不足为奇了:
var proto = {
name: "proto's name"
};
var a = Object.create(proto); // `a` is backed by `proto`
var b = Object.create(proto); // `b` is also backed by `proto`
console.log(a.name); // "proto's name"
console.log(b.name); // "proto's name"
a.name = "a's name";
console.log(a.name); // "a's name"
console.log(b.name); // "proto's name"
Run Code Online (Sandbox Code Playgroud)
原型对象是普通对象; 我们可以改变它们:
var proto = {
name: "proto's name"
};
var obj = Object.create(proto);
console.log(obj.name); // "proto's name"
proto.name = "updated";
console.log(obj.name); // "updated"
Run Code Online (Sandbox Code Playgroud)
由于obj没有自己的name属性,每次我们访问它时,JavaScript引擎都会查看它的原型.
该new运营商自动原型分配给它创建的对象:它使用该函数的对象prototype属性上有.所以:
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function() {
console.log("My name is " + this.name);
};
var p = new Person("Fred"); // Creates an object backed by Person.prototype,
// then calls Person with this referring to the
// object
p.sayName(); // "My name is Fred";
Run Code Online (Sandbox Code Playgroud)
最后:由于原型对象是普通对象,因此它们也可以有原型:
var rootProto = {
name: "root proto's name"
};
var middleProto = Object.create(rootProto);
middleProto.middleProp = "middle property";
var obj = Object.create(middleProto);
console.log(obj.name); // "root proto's name"
console.log(obj.middleProp); // "middle property"
Run Code Online (Sandbox Code Playgroud)
对于name,JavaScript引擎查看obj,没有看到name属性,所以看middleProto.它也没有看到name那里的财产,所以它看起来rootProto.它找到它,所以它使用它.
困惑点:很多人对构造函数的属性被调用这一事实感到困惑,prototype并认为它是函数的原型.事实并非如此.它只是函数对象的常规属性(函数是对象,可以具有属性).在只有它的特殊方式是,new使用它,当你通过调用该函数new.非功能对象没有prototype属性,它们的原型不是普通属性,它是内部的东西.您可以通过将对象传递到Object.getPrototypeOf以下内容来获取对象的原型:
var proto = {/*...*/};
var obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true
Run Code Online (Sandbox Code Playgroud)