三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

做网站竞品分析网络规划设计师需要的基础

做网站竞品分析网络规划设计师需要的基础 做网站竞品分析,网络规划设计师需要的基础,网站建设的布局对网络推广的影响,伪静态 多个网站JavaScript 中的原型与继承Posted on 2026-07-16 00:07 lzhdim 阅读(0) 评论(0) 收藏 举报一、从对象说起, 一切皆对象在 JS 中, 几乎所有的东西都是对象, 或者说最终都会指向某个对象. 比如: let arr = [1, 2, 3…JavaScript 中的原型与继承Posted on 2026-07-16 00:07 lzhdim 阅读(0) 评论(0)收藏 举报 一、从对象说起, 一切皆对象在 JS 中, 几乎所有的东西都是对象, 或者说最终都会指向某个对象. 比如: letarr = [1,2,3];console.log(typeofarr);//"object"functionfoo() {}console.log(typeoffoo);//"function" (但本质上也是对象) 简单的对象创建: letperson = { name:'张三', age:25, sayHi:function() { console.log('你好,我是'+this.name); }};person.sayHi();// 你好, 我是张三 但这样有个问题——每次创建新对象都要写一遍所有属性和方法, 太麻烦了! 于是我们有了后面的构造函数.二、构造函数,对象的工厂 functionPerson(name, age) { this.name= name; this.age= age; this.sayHi=function() { console.log('你好, 我是'+this.name); };}letperson1 =newPerson('张三',25);letperson2 =newPerson('李四',30);person1.sayHi();// 你好, 我是张三person2.sayHi();// 你好, 我是李四 这里有几个关键点: 1. 函数名通常大写开头,这是约定俗成的构造函数命名方式 2. 使用new关键字调用 3. 函数内部使用this来指代新创建的对象 当你使用new调用函数时,背后发生了这些事: 1. 创建一个全新的空对象 2. 将这个空对象的__proto__指向构造函数的prototype属性 3. 将构造函数中的this绑定到这个新对象 4. 执行构造函数中的代码 5. 如果构造函数没有显式返回对象,则返回这个新对象 三、原型登场 上面的构造函数方式有个问题——每个实例都会创建自己的方法副本, 浪费内存,这时候,原型(prototype)就派上用场了! 什么是原型? 每个函数都有一个prototype属性, 它指向一个对象. 当使用这个函数作为构造函数创建实例时, 所有实例都会共享这个原型对象上的属性和方法. 改进版的 Person: functionPerson(name, age) { this.name= name; this.age= age;}// 将方法放在原型上Person.prototype.sayHi=function() { console.log('你好,我是'+this.name);};letperson1 =newPerson('张三',25);letperson2 =newPerson('李四',30);console.log(person1.sayHi=== person2.sayHi);// true - 现在方法是共享的了! 什么是原型链? 当我们访问一个对象的属性时, JavaScript 会: 1. 先在对象自身属性中查找 2. 如果没找到, 就去对象的__proto__(即构造函数的prototype) 中查找 3. 如果还没找到, 就继续往__proto__.__proto__中查找 4. 直到找到Object.prototype(最顶层的原型,它的__proto__是null) 这就是原型链,JavaScript的继承机制. functionPerson() {}Person.prototype.species='人类';letp =newPerson();console.log(p.species);//"人类" - 从原型上找到的console.log(p.__proto__===Person.prototype);// trueconsole.log(Person.prototype.__proto__===Object.prototype);// trueconsole.log(Object.prototype.__proto__);// null 如果对象自身有属性, 就不会去原型上找了: p.species='地球人';console.log(p.species);//"地球人" - 自身的属性console.log(Person.prototype.species);//"人类" - 原型上的没变deletep.species;console.log(p.species);//"人类" - 删除自身属性后又从原型上找到了 四、几种继承的方式 1)原型链继承: functionParent() { this.parentProp='父类属性';}Parent.prototype.parentMethod=function() { console.log('父类方法');};functionChild() { this.childProp='子类属性';}// 关键点: 子类的原型指向父类的实例Child.prototype=newParent();letchild =newChild();console.log(child.childProp);// "子类属性"console.log(child.parentProp);// "父类属性"-通过原型链找到的child.parentMethod();// "父类方法" 问题:所有子类实例共享同一个父类实例的属性(如果是引用类型就麻烦了)创建子类实例时无法向父类构造函数传参2)构造函数继承: functionParent(name) { this.name= name; this.colors= ['red','blue'];}functionChild(name, age) { Parent.call(this, name);//关键点:在子类构造函数中调用父类构造函数 this.age= age;}letchild1 =newChild('张三',25);child1.colors.push('green');letchild2 =newChild('李四',30);console.log(child2.colors);//["red", "blue"]-不受child1影响 优点: 1. 避免了引用类型属性被所有实例共享 2. 可以在子类中向父类传参 缺点:方法都在构造函数中定义,每次创建实例都会创建一遍方法不能继承父类原型上的方法3)组合继承: 结合原型链继承和构造函数继承的优点: functionParent(name) { this.name= name; this.colors= ['red','blue'];}Parent.prototype.sayName=function() { console.log(this.name);};functionChild(name, age) { Parent.call(this, name);//第二次调用Parent this.age= age;}Child.prototype=newParent();//第一次调用ParentChild.prototype.constructor=Child;//修复constructor指向Child.prototype.sayAge=function() { console.log(this.age);};letchild1 =newChild('张三',25);child1.colors.push('green');child1.sayName();//"张三"child1.sayAge();//25letchild2 =newChild('李四',30);console.log(child2.colors);//["red", "blue"] 4)寄生组合继承: functioninheritPrototype(child, parent) { letprototype =Object.create(parent.prototype);// 创建父类原型的副本 //Object.create 是创建以指定对象为原型的新对象的方法 prototype.constructor= child;// 修复constructor child.prototype= prototype;// 将副本作为子类的原型}functionParent(name) { this.name= name; this.colors= ['red','blue'];}Parent.prototype.sayName=function() { console.log(this.name);};functionChild(name, age) { Parent.call(this, name); this.age= age;}// 关键: 使用我们封装的inheritPrototype函数inheritPrototype(Child,Parent);Child.prototype.sayAge=function() { console.log(this.age);};letchild =newChild('张三',25);child.sayName();// "张三"child.sayAge();// 25 优点: 1. 只调用一次父类构造函数 2. 子类原型上不会有多余的父类属性 3. 原型链保持不变 五、ES6的class ES6 引入了class语法, 让面向对象编程更加直观: classParent{ constructor(name) { this.name= name; this.colors= ['red','blue']; } sayName() { console.log(this.name); }}classChildextendsParent{ constructor(name, age) { super(name);// 必须在使用this之前调用super this.age= age; } sayAge() { console.log(this.age); }}letchild =newChild('张三',25);child.sayName();// "张三"child.sayAge();// 25 class本质上仍然是基于原型的语法糖. 上面的代码大致相当于: functionParent(name) { this.name= name; this.colors= ['red','blue'];}Parent.prototype.sayName=function() { console.log(this.name);};functionChild(name, age) { Parent.call(this, name); this.age= age;}Child.prototype=Object.create(Parent.prototype);Child.prototype.constructor=Child;Child.prototype.sayAge=function() { console.log(this.age);}; class还提供了静态方法和属性的简洁写法: classMyClass{ staticstaticMethod() { console.log('我是静态方法'); } staticstaticProperty ='我是静态属性';}MyClass.staticMethod();//"我是静态方法"console.log(MyClass.staticProperty);//"我是静态属性" 六、其他相关内容 instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上. functionmyInstanceof(instance, constructor) { letproto =Object.getPrototypeOf(instance); while(proto) { if(proto === constructor.prototype) { returntrue; } proto =Object.getPrototypeOf(proto); } returnfalse;}console.log([]instanceofArray);// trueconsole.log(myInstanceof([],Array));// true 原型可以被修改, 这可能导致安全问题: // 不要这样做!Object.prototype.hack=function() { console.log('被黑了!');};letobj = {};obj.hack();// "被黑了!"Austin Liu 刘恒辉 Project Manager and Software Designer E-Mail:lzhdim@163.com Blog:https://lzhdim.cnblogs.com欢迎收藏和转载此博客中的博文,但是请注明出处,给笔者一个与大家交流的空间。谢谢大家。
← 返回列表