【js(5)原型与原型链】
原型与原型链
- 一、构造函数
- 二、原型、原型链的理解
- 1.原型
- 2.prototype
- 3.`__proto__`
- 4.原型链
- 三、原型修改、重写
- 四、原型链指向
- 五、如何获得对象非原型链上的属性?
一、构造函数
- 构造函数就像一个“造东西的机器”(模板),实例就是它造出来的“产品”
var Parent = function(){}//Parent为普通的函数var instance = new Parent()
//通过new调用了之后,Parent就为构造函数
//创建了一个Parent构造函数的实例 instance
二、原型、原型链的理解
- [[ProtoType]]的双括号是Ecma-262规范的用来表示特性的一种方法。这里表示原型这种
特性
。- 理论上不能通过代码访问,但是目前大部分浏览器都可以通过
__proto__
把原型暴露出来,可以通过该属性访问原型。(暴力方法不推荐)
1.原型
- 原型是 JavaScript 实现
对象之间共享属性和方法
的一种机制,也是 JavaScript实现继承
的核心机制- js通过构造函数新建对象,每个构造函数内部都有一个prototype属性,属性值是一个对象,这个对象包含了可以由该构造函数的所有实例共享的属性和方法。
例如:
function Person(name) {this.name = name;
}Person.prototype.sayHello = function() {console.log("Hello, my name is " + this.name);
};let p1 = new Person("Tom");
let p2 = new Person("Jerry");p1.sayHello(); // Hello, my name is Tom
p2.sayHello(); // Hello, my name is Jerry
- 当使用构造函数新建一个对象后,在这个对象内部包含一个指针,指向构造函数prototype属性对应的值,在ES5中
这个指针被称为对象的原型
2.prototype
函数特有
的属性- 作用:让某一个
构造函数实例化的所有对象
可以找到公共的属性和方法
3.__proto__
对象特有
的属性,他表示当前对象的原型对象是谁__proto__
就是一个“链接”,它让一个对象可以访问它的原型对象,用来查找它自己没有的属性和方法- 每个对象都有
__proto__
属性,无论是实例对象还是构造函数(本身就是一个对象)本身都有这个属性obj.__proto__
是浏览器提供的一个属性,用来查看对象的原型- 它不是标准属性,建议使用
Object.getPrototypeOf()
来获取对象的原型
var Parent = function(){}//Parent为普通的函数
Parent.prototype.name = "所有Parent的实例都可以读取到我"
let p1 = new Parent();
let p2 = new Parent();p1.name;
p2.name;console.log(p1.__proto__ === Parent.prototype); // true
console.log(Parent.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
4.原型链
- 对象通过原型链来访问原型对象身上的属性和方法
- 原型本身也是一个对象,他也有自己的原型,形成一个链式结构,这种链式结构就被称为原型链
- 接上段代码:
p1对象上有没有name属性
p1.__proto__
(Parent.prototype)上有没有name属性
Object.prototype有没有name属性
(Parent.protptype对象是通过Object对象实例化得来的)
null(Object.prototype.__proto__ === null,原型链的终点)
总结:
JavaScript 中的对象会通过__proto__
链式查找属性和方法。如果自己没有,就去原型对象找;原型对象没有,就去它的原型对象找,直到找到 null 为止,这就是原型链。
三、原型修改、重写
重写原型后
,它并不会自动获得constructor属性
,因为constructor属性是在你定义一个构造函数时,js引擎自动加到构造函数的prototype对象上的。
function Person(name) {this.name = name
}
// 修改原型
Person.prototype.getName = function() {}
var p = new Person('hello')
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // true
// 重写原型
Person.prototype = {getName: function() {}
}
var p = new Person('hello')
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // false
要想获得constructor属性,就必须指回来
Person.prototype = {getName: function() {}
}
var p = new Person('hello')
p.constructor = Person
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // true
四、原型链指向
p.__proto__ // Person.prototype
Person.prototype.__proto__ // Object.prototype
p.__proto__.__proto__ //Object.prototype
p.__proto__.constructor.prototype.__proto__ // Object.prototype
Person.prototype.constructor.prototype.__proto__ // Object.prototype
p1.__proto__.constructor // Person
Person.prototype.constructor // Person
五、如何获得对象非原型链上的属性?
hasOwnProperty()
方法来判断属性是否属于原型链的属性
function iterate(obj){var res=[];for(var key in obj){if(obj.hasOwnProperty(key))res.push(key+': '+obj[key]);}return res;
}