前端复盘1——原型链
-
没有原型的对象也是存在的
let hd = Object.create(null, { name: { value: 111 } });
-
对象方法和原型方法的使用优先级。
即使给_proto_给原型上添加相同方法。依然会先优先使用自己自身的方法。
-
引入prototye
注意:prototype是函数才有的属性,而__proto__是每个对象都有的属性
function User () { }; User.prototype.show = function () { // 1.作为构造函数 console.log('User.prototype.show'); } let userObj = new User(); console.log(userObj.__proto__.show === User.prototype.show); // true User.__proto__.hide = function () { // 2. 作为普通对象 console.log('User.__proto__.hide'); }; console.dir(User);
-
原型关系
上面User的prototype和__proto__的原型指得是Object的prototype
Object.prototype.ObjFunc = function () { console.log('这里是Object才有的方法'); } console.log(Object.prototype === User.__proto__.__proto__, Object.prototype === User.prototype.__proto__) // true
而Object.prototype.__proto__指的是null,因为Object.prototype已经到顶了。
-
自定义对象的原型设置
let son = { name: '儿子' } let father = { name: '父亲', getName () { console.log('名字:',this.name); } } // 原型设置, 和Object.create()类似。与之相匹配的是getPrototypeOf() Object.setPrototypeOf(son, father); son.getName();
-
prototye中constructor的引用
function User (name) { this.name = name; }; // 在原型上添加一个show方法 User.prototype.show = function () { console.log('User.prototype.show:', this.name); } // 但是,如果将上面的改写成下面的,后面new的时候是会报错的,因此要加上constructor User.prototype = { // constructor: User, show () { console.log('User.prototype.show:', this.name); } } let lisi = new User.prototype.constructor('lisi'); lisi.show();
-
给我一个对象还你一个世界
function User (name) { this.name = name; }; User.prototype.show = function () { console.log('User.prototype.show:', this.name); } function createNewObj (obj, arg) { let prototype = Object.getPrototypeOf(obj).constructor; // 注意:obj.__proto__不是一个标准的方法 return new prototype(arg); } let lisi = new User('李四'); let newObj = createNewObj(lisi, '王五'); // 关键代码,传递对象过去获取到新的对象 newObj.show(); // User.prototype.show: 王五
-
原型链检测instanceof
注意:
instanceof
运算符用于检测构造函数的prototype
属性是否出现在某个实例对象的原型链上。 -
Object.isPrototypeOf() 原型检测
-
in与hasOwnProperty
in会沿着原型链一直往上对象的属性,而hasOwnProperty只会在当前对象找对应属性。
-
使用apply或者call来借用其他原型上的方法
<body> <button class="hasCls"></button> <button class="hasCls"></button> <button></button> </body> <script> let buttons = document.querySelectorAll('button'); let hasClsButton = ([] || Array.prototype).filter.call(buttons, item => { return item.hasAttribute('class'); }); console.log(buttons, hasClsButton); </script>
-
合理的构造函数方法声明
function User (name) { this.name = name; this.show = function () { console.log(this.name); } }; // 没有必要花费更多的内存,把show方法定义到每个实例上 // 可以把show()方法定义在原型链上. // 如果方法多的话,可以定义到 User.prototype = {}里面 User.prototype.show = function () { console.log(this.name); } let zhangsan = new User('张三'); let lisi = new User('李四'); console.log(zhangsan, lisi);
13.__proto__原来是属性访问器
let test = {};
test.__proto__ = {
show () {
console.log('方法设置在原型对象上');
}
}
console.log(test.show());
test.__proto__ = '覆盖__proto__'; // 没有成功覆盖。原因是__proto__的set对其做了限制. 可以使用以下方法实现:
let test = Object.create(null);
test.__proto__ = '覆盖__proto__';
console.log(test.__proto__);
-
改变构造函数原来不是继承
有什么办法让Admin和Member继承User的role()方法,第一种实现方式是让Admin和Member的直接原型指向User。
function User () {}; let user = new User(); User.prototype.role = function () { console.log('这里是User的role方法'); } User.prototype.name = function () { console.log('这里是User的name方法'); } function Admin () {}; Admin.prototype = User.prototype; Admin.prototype.role = function () { console.log('这里是Admin的role方法'); } let admin = new Admin(); console.log(user.role()); // user的role方法被覆盖。输出:这里是Admin的role方法
上面这一种实现方式是有问题的,role方法会被覆盖。应该变换成下面这种实现方式。
function User () {}; User.prototype.role = function () { console.log('这里是User的role方法'); } User.prototype.name = function () { console.log('这里是User的name方法'); } function Admin () {}; Admin.prototype.__proto__ = User.prototype; Admin.prototype.role = function () { console.log('这里是Admin的role方法'); } let admin = new Admin(); // 既可以实现继承,又可以在自身原型上修改role()方法 console.log(admin.role(), admin.name()); // 这里是Admin的role方法; 这里是User的name方法

- 原型链继承
function User () {};
function Admin () {};
let admin = new Admin(); // 因为admin实例是在下面role方法定义之前new出来的,所以是没有role方法的
// Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
// Admin.prototype = Object.create(User.prototype);
// 上面那样写,最后是会报错的,下面才是正解
Admin.prototype.__proto__ = User.prototype;
// 这时候即使给Admin的原型上挂上role方法,admin对象也是取不到的,因为它相当于在User.prototype上新增role方法
Admin.prototype.role = function() {
console.log('role');
};
let admin1 = new Admin();
admin.role(); // 会报错,因为没有role方法
- 禁止contructor被遍历
下面这种情况,如果只是简单的Object.create,他是没有构造函数的。因此需要手动给contructor赋值。赋值方式有两种,一种是Admin.prototype.constructor = User;
,不过,构造函数就是可枚举的了。因此使用Object.defineProperties
将其变成不可枚举的。
function User () {};
function Admin () {};
let admin = new Admin(); // 因为admin实例是在下面role方法定义之前new出来的,所以是没有role方法的
// Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
Admin.prototype = Object.create(User.prototype);
// 但是这时候,是没有constructor的,需要手动赋值
// 但是这种赋值方式会有问题,将其变成可枚举的了
// Admin.prototype.constructor = User;
Object.defineProperties(Admin.prototype, {
'constructor': {
value: User,
enumerable: false
}
});
let admin1 = new Admin();
// 如果按照Admin.prototype.constructor = User;来写的话,会打印出constructor,将其变成可枚举的。
// 因此应该使用Object.defineProperties的形式
for (let item in admin1) {
console.log(item);
}
-
面向对象的多态
function User () {}; User.prototype.showMsg = function () { return console.log(this.msg()); } function Admin () {}; Admin.prototype = Object.create(User.prototype); Admin.prototype.msg = function () { return '这里是Admin的msg方法'; } function Members () {}; Members.prototype = Object.create(User.prototype); Members.prototype.msg = function () { return '这里是Members的msg方法'; } for (let item of [new Admin(), new Members()]) { item.showMsg(); }
-
使用对象工厂派生对象并实现继承
function User (name, age) { this.name = name; this.age = age; }; User.prototype.showMsg = function () { console.log(`名字:${this.name},年龄:${this.age}`); } function Admin (name, age) { let user = Object.create(User.prototype); user.showInfo = function () { console.log('这里是Admin方法里的showInfo方法'); }; User.call(user, name, age); return user; }; let admin = Admin('余晖', '21岁'); admin.showMsg(); admin.showInfo();
19 . super
super关键字用于访问和调用一个对象的父对象上的函数。
const person = {
name:'jack'
}
const man = {
sayName(){
return super.name;
}
}
Object.setPrototypeOf( man, person );
let n = man.sayName();
console.log( n ) //jack