JavaScript学习03-原型链
详解链接:https://www.jianshu.com/p/dee9f8b14771
原型链
//原型链 const obj = new Object(); const obj2 = { }; //每个对象都有一个—__proto__属性 obj2.__proto__.name = 'guo'; console.log(obj2.name); function Fun() { } //每个function都有一个prototype属性 //当我们创建一个函数对象时,它的__proto__和所属类构造函数本身的prototype指向同一个对象 Fun.prototype.name = 'guoyunhao'; const f = new Fun(); console.log(f.__proto__ === Fun.prototype); //先找本身有没有name属性,如果找不到,会按顺序往上在原型链上找 //obj.__proto__.__proto__.name 直到Object.prototype为止 console.log(f.name); Object.prototype.name = "根类名字"; var o1 = new Object(); var o2 = {}; console.log(o1.name); console.log(o2.name); var o3 = { name: '自己的名字' }; o3.__proto__.name = "o3proto的名字"; console.log(o3.name); //delete删除对象的属性,不能删除对象本身 delete o3.name; console.log(o3.name); //因为__proto__已被废弃,要使用如下方法设置prototype var o3P = { age: 22 }; Object.setPrototypeOf(o3, o3P); console.log(o3.age);
通过原型链创建类
//new User(); //通过原型链创建所谓的类
function User() { //在调用new User()时候,因为new关键字使其内部机制执行如下 //如果不加new,它会像普通函数一样执行 /* var thisobj = {}; thisboj.__proto__ = User.prototype; return thisobj; */ //私有属性 var name = 'guo'; //特权方法 因为能访问私有属性,所以叫特权方法 this.print_name = function() { console.log(name); }; } //原型属性 User.prototype.fn = function() { console.log('fn'); }; User.prototype.type = '类的类型'; var u = new User(); u.print_name(); //u.__proto__.fn u.fn(); //静态属性 User.version = 1.0; User.staticFunc = function() {}; //调用静态方法和属性 var version = User.version; var staticFunc = User.staticFunc;
继承
//继承 function People(name = 'default') { this.name = name; this.changeName = function(name) { this.name = name; }; } People.prototype.fnP = function() { console.log("people fnP"); }; People.staticFunc = function() { console.log('static People func'); } function User(name) {} User.prototype.fnU = function() {}; //原型链实现继承 User.prototype.__proto__ = People.prototype; //User.prototype = new People(); 这样不行,原因在下面截图处
var u = new User(); //Object.setPrototypeOf(u, new People()); //u.changeName('guo'); u.fnP(); //call apply实现继承 function Guo(name) { //特权属性的继承 People.call(this, name); this.height = 187; } //这里是整个函数对象的__proto__指向了People函数对象,所以可以继承静态方法 Guo.__proto__ = People; //而这里Guo.prototype是Guo的原型对象,是Guo构造函数创建的一个普通对象,相当于实例才能用People中的方法 //Guo.prototype = People; var g = new Guo("guoyunhao"); //g.__proto__ = People; g.changeName("eric"); console.log(g.name); //g.staticFunc(); Guo.staticFunc();
var obj = {}; console.log(obj.name); Object.prototype.name = 'guo'; console.log(obj.name); console.log(obj.__proto__ === Object.prototype); //构造函数 function User() { } //有了原型链这一机制,创建无数个User实例对象,只需要一份changeAge方法,节省内存空间 User.prototype.age = 23; User.prototype.changeAge = function(age) { //这里的this是User.prototype this.age = age; } var u = new User(); var u2 = new User(); u.age = 16; u.changeAge(17); console.log(u.age); console.log(u2.age); //不节省内存的方式 //这样写的话每次new出来一个User2对象都要执行函数内部的所有属性和方法 function User2() { this.age = 23; this.changeAge = function(age) { this.age = age; }; } function People(name = 'default') { this.name = name; // this.changeName = function(name) { // this.name = name; // }; } People.prototype.changeName = function(name) { this.name = name; }; function Guo(name, age) { //继承特权属性 People.call(this, name); this.age = age; } Guo.prototype.__proto__ = People.prototype; g = new Guo('guodage', 23); g.changeName('guoyunhao'); console.log(g.name);
深入理解
//每个对象都有 __proto__ 属性,但只有函数对象才有 prototype 属性 //凡是通过new Funtion()产生的对象都是函数对象 function f1() {}; var obj = new f1(); console.log(typeof f1, typeof obj); //原型对象就是一个普通对象,除了Function.prototype,它是函数对象,因为它是new Function()创建出来的,但它没有prototype属性 console.log(Function.prototype.__proto__ === Object.prototype); console.log(Object.prototype.__proto__); console.log(typeof f1.prototype); console.log(f1.prototype.constructor === f1); console.log(obj.constructor === f1); //普通对象没有prototype属性 console.log(f1.prototype.prototype); //原型对象(Person.prototype)是 构造函数(Person)的一个实例。
实现继承的错误用法与错误原因
