<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="Generator" content="EditPlus">
<meta name="Author" content="">
<meta name="Keywords" content="">
<meta name="Description" content="">
<title>Document</title>
</head>
<body>
<div id="cont">Hello World</div>
<script>
// 创建构造函数Person
function Person(name, age) {
this.name = name;
this.age = age;
}
// 通过new实例化构造函数Person
let p1 = new Person("lili", 23);
let p2 = new Person("jerry", 24);
console.log("p1--->", p1); // { name:"lili", 23}
console.log("p2--->", p2); // { name:"jerry", 24}
console.log("p1.constructor == person--->", p1.constructor == person); // true
console.log("p1 == Person.prototype--->", p1 == Person.prototype); // false n prototype属性没有办法从构造函数中继承,只能由构造函数本身访问
console.log("Person.prototype == Person--->", Person.prototype == Person); // false
console.log("p1.constructor == Person.prototype.constructor--->", p1.constructor == Person.prototype.constructor); // true
console.log("p1.__proto__ == Person.prototype--->", p1.__proto__ == Person.prototype); // true
console.log("Person.__proto__ == Function.prototype--->", Person.__proto__ == Function.prototype); // true
console.log("Person.prototype.__proto__ == Object.prototype--->", Person.prototype.__proto__ == Object.prototype); // true
// 构造器 constructor 原型 prototype
// 每个对象都有一个constructor属性,指向这个对象所在的构造函数
p1.constructor == Person;
p2.constructor == Person;
// Person.prototype是Person的原型“对象”,所以这个对象也有constructor属性,同样指向Person
Person.prototype.constructor == Person;
// 由此可见三者是等同关系,并且都等于Person: 构造函数的原型对象(prototype)的构造器(constructor)指向该构造函数
p1.constructor == p2.constructor;
p1.constructor == Person.prototype.constructor == Person;
// 原型链__proto__
// 每个对象都有一个 __proto__ 属性指向创建它的构造函数的原型
p1.__proto__ == Person.prototype;
p2.__proto__ == Person.prototype;
// Person本身是一个“构造函数”,那么创建它的构造函数就是一个Function
Person.__proto__ == Function.prototype;
// Person.prototype 是一个原型“对象”, 那么创建它的构造函数就是一个Object
Person.prototype.__proto__ == Object.prototype;
// 创建构造函数Dog
function Dog(name, size) {
this.name = name;
this.size = size;
this.eat = function() {
console.log("吃肉肉");
}
};
// 创建实例化对象 dog1
let dog1 = new Dog("apple", 22);
// js的构造函数和实例化对象之间,并不能够实现共享数据,节省内存空间的作用,所以我们就引入了原型这一个概念
// 给构造函数Dog添加原型方法
Dog.prototype.sell = function() {
console.log("滑雪");
};
// 使用原型的注意事项
// 原型属性和方法统一定义时,需要定义构造器constructor,即使构造函数的原型对象中的构造函数指向该构造函数,否则原型属性和方法定义失败
// 添加原型方法
Person.prototype.job = "程序员";
Person.prototype.address = "苏州";
Person.prototype.study = function() {
console.log("学习JavaScript");
}
// 可以这样定位吗? ----》不可以
Person.prototype = {
job : "程序员",
address : "苏州",
study : function() { console.log("学习JavaScript"); }
};
// 上面的原型对象定义出错,需要加上constructor手动修改构造器的指向
Person.prototype = {
constructor : Person,
job : "程序员",
address : "苏州",
study : function() { console.log("学习JavaScript"); }
};
// 换个构造函数名字 是一样的道理
var example = new Object();
example.constructor == Object;
example.__proto__ == Object.prototype;
Object.__proto__ == Function.prototype;
Object.prototype.__proto == Object.prototype;
// 当原型的__proto__属性等于该原型的时候,就说明指向到了最顶层的对像null
Object.prototype.__proto == null && Object.prototype == null;
// 1. Math和JSON是以对象存在的,所以
Math.__proto__ === Object.prototype;
JSON.__proto__ === Object.prototype;
// 2. Function.prototype是唯一一个typeof(Function.prototyoe) == "funciton"的原型,其他构造器的原型都是Object
typeof Function.prototype == "function";
// 3. 重写会导致constructor指向发生改变
function Person() {}
Person.prototype.name = "小名"
person1 = new Person();
person1.constructor.prototype.name = "小花";
console.log(Person.prototype,name, person1.constructor === Person); // 小花 true
person1 = { // 这里已经属于重写构造函数了
getName: function() {
console.log("获取姓名");
};
}
console.log(Person.prototype,name, person1.constructor === Person, person1.constructor === Object); // 小花 false true
// 测试题1
A.prototype.n = 1;
var b = new A();
A.prototype = {
n : 2,
m : 3,
}
var c = new A();
console.log(b.n, b.m, c.n, c.m); // 1 undefined 2 3
// 测试题2
var F = function() { }; // F 为构造函数
Object.prototype.a = function() {
console.log("a()");
}; // 等价于 F.prototype.__proto__ 将值不仅写入构造函数prototype原型对象中,也写入了实例对象__proto__ 对象中
Function.prototype.b = function() {
console.log("b()");
}; // 等价于F.__proto__ ,将值仅仅写入构造函数prototype原型对象中,不写入实例对象__proto__ 对象中
var f = new F();
// 解析:
f.constructor == F == F.prototype.constructor;
f.__proto__ == F.prototype;
Object.prototype == F.prototype.__proto__;
Function.prototype == F.__proto__;
f.a() // a()
f.b() // 报错 f.b is not a function
F.a() // a()
F.b() // b()
// 测试题3
var f = new Foo("L");
f.lastName = function() {
console.log(this.name);
};
f.lastName(); // "L" 自身属性
f.alertName(); // "Lkikllua" 原型属性
// 以上函数中,f共有3个属性,f自身的属性有2个(name属性和lastName属性),还有一个alertName是原型属性
f.firstName(); // 这里f自身属性中没有firstName属性,它的原型Foo函数中也没有这个属性,所以要再往上一次Foo的原型上去找这格属性,这种有多层原型的函数就是原型链,直到null为止结束原型链
var item;
for(item in f) {
// 高级浏览器已经在for in中屏蔽了来自原型的属性,但是这里建议加上这个判断,保证程序的健壮性
if( f.hasOwnProperty(item) ) {
console.loe(item); // 循环遍历f函数,如果f函数有它自身的属性item,则打印出item属性
}
}
// 测试4
// 原型链继承例子:
function Name() {
this.name = function() {
console.log("kkkkk");
}
};
function FirstName() {
this.firstName = function() {
consoel.log("llll");
}
};
Name.prototype = new FirstName();
var he = new Name();
console.log(he.name); // "kkkkk"
console.log(he.firstName); // "llll"
// 原型链继承例子2:
function Elem(id) {
this.elem = document.getElementById(id);
};
Elem.prototype.html = function(val) {
var elem = this.elem;
if(val) {
elem.innerHTML = val;
return this // 链式操作
}else {
return elem.innerHTML;
}
};
Elem.prototype.on = function(type, fn) {
var elem = this.elem;
elem.addEventListener(type, fn); // addEventListener() 方法由于向指定元素添加事件
};
var div1 = new Elem("div1");
// console.log(div1.html());
div1.html(`<p>hello kkkkk</p >`).on("click", function() {
alert("clicked");
}).html(`<p>javascript</p >`);
/**
创建构造函数Person
function Person() {
this.name = name;
this.age = age;
}
// 通过new实例化构造函数Person
let p1 = new Person("lili",23);
总结:
1.prototype 属性没有办法从构造函数中继承,只能由构造函数本身来访问
2.实例对象中都有__proto__属性,而构造函数中都有prototype属性, 构造函数.prototyo == 实例对象.__proto__ 【 Person.prototype == p1.__proto__ 】
3.构造函数的原型对象(prototype)的构造器(constructor)指向该构造函数 构造函数.prototype.constructor == 实例对象.constructor 【 p1.constructor == Person.prototype.constructor == Person 】
4.Person本身是一个构造函数,那么创建它的构造函数就是一个Function 【Person.__proto__ == Function.prototype 】
5.Person.prototype 是一个原型“对象”, 那么创建它的构造函数就是一个Object 【 Person.prototype.__proto__ == Object.prototype 】
6.原型法添加方法的好处是:所有对象都共享,节约内存,通过构造函数添加成员方法会存在浪费内存
7.JS中给同一个构造函数的实例对象,添加共有属性和方法,需要使用prototype这一属性,也就是原型对象来实现
8.实例化完成后,所以实例均会与原型对象形成多对一的隐性关联关系。所有实例会共享原型对象的方法和属性,当然也包括constructor。当原型对象被添加一个属性或者方法后,均会被所有实例共享,即可以通过任意一个实例进行访问。如果原型对象的属性和方法与实例的属性和方法名称一致,则实例自身的属性和方法优先级高于原型对象上的。
9.原型属性和方法统一定义时,需要定义构造器constructor,即使构造函数的原型对象中的构造器指向该构造函数,否则原型属性和方法定义失败。
10.当原型的__proto__属性等于该原型的时候,就说明指向到了最顶层的对像null。
11.Function.prototype是唯一一个typeof(Function.prototyoe) == "funciton"的原型,其他构造器的原型都是Object。
12.原型链
1) 构造函数,原型和实例的关系
① 构造函数都有一个属性prototype,这个属性是一个对象(Object的实例)
② 原型对象prototype里面有一个constructor属性,该属性指向原型对象所属的构造函数
③ 实例对象都有一个__proto__属性,该属性也指向构造函数的原型对象,他是一个非标准属性,不可以用于编程,它是用于浏览器自己使用的
2) prototype与__proto__的关系
① prototype是构造函数的属性
② __proto__ 是实例对象的属性
这两者都指向同一个对象
【总结】① 函数也是对象,对象不一定是函数
② 对象的本质: 无效的键值对集合;键值对当中的值可以是任意数据类型的值
③ 对象就是一个容器,这个容器当中放的就是(属性和方法)
3) 属性搜索
① 在访问对象的某个成员的时候,会先在对象中找是否存在
② 如果当前对象中没有就在构造函数的原型对象中找
③ 如果原型对象中没有找到就到原型对象的原型上找
④ 直到Object的原型对象的原型是null为止
*/
</script>
</body>
</html>
构造函数,原型,原型对象,构造器,原型链
最新推荐文章于 2024-09-21 09:29:16 发布