一、原型
prototype
原型prototype是function对象的一个属性,它也是一个对象。function是一个对象。
prototype是定义构造函数构造出的每个对象的公共祖先。
函数就有prototype默认属性,不用实例化就有prototype属性
function Handphone() { }
console.log(Handphone.prototype);
Handphone.prototype是一个对象,可以通过Handphone.prototype.xx来声明、保存数据
那就可以先拿Handphone.prototype.xx来保存数据试试,看看什么效果
结果实例化对象hp1、hp2也有在prototype中添加的属性
这个现象说明,这个prototype属性是定义构造函数构造出的每个对象的公共祖先,构造出来的对象存有prototype的地址,所有被该构造函数构造出的对象都可以继承原型上的属性和方法
function Handphone(color,brand){
this.color=color;
this.brand=brand;
this.screen='18:9';
this.system='Android';
}
Handphone.prototype.rom='64G';
Handphone.prototype.ram='6G';
Handphone.prototype.screen='16:9';
var hp1=new Handphone('red','小米');
var hp2=new Handphone('black','华为');
console.log(hp1.rom);//64G
console.log(hp2.ram);//6G
console.log(hp1.screen);//18:9
console.log(hp2.screen);//18:9
通过实例化对象的增删改查来修改prototype是不行的,修改祖先是不行的
function Test(){}
Test.prototype.name='prototype';
var test=new Test();
console.log(test.name);
test.num=1;
console.log(Test.prototype,test);
console.log(test);
delete test.name;
console.log(Test.prototype,test);
test.name='proto';
console.log(test.prototype,test);
通过prototype增加构造函数的属性、方法,prototype对象也是一个对象,可以通过对象字面量来添加、修改
function Handphone(color, brand, system) {
this.color = color;
this.brand = brand;
this.system = system;
}
Handphone.prototype = {
rom: '64G',
ram: '6G',
screen: '18:9',
system: 'Android',
call: function () {
console.log('I am calling somebody');
}
}
var hp1 = new Handphone('black', 'iPhone', 'IOS');
console.log(hp1);
constructor
prototype对象中也有属性,prototype对象有什么属性?constructor
原型prototype的一个属性constructor对象,指向该构造函数。
所有该构造函数构造出的对象都可以继承原型上的属性和方法。
constructor可以被更改。
function Handphone(color, brand, system) {
this.color = color;
this.brand = brand;
this.system = system;
}
function Telephone() {}
// 可以更改对象的构造函数
Handphone.prototype = {
constructor: Telephone
}
二、原型链
当构造函数car里什么语句都没有时,this对象中也有默认的属性proto,并不是空的,proto是系统内置、自带的属性
proto属于实例化对象,this中携带proto属性,存着构造函数的prototype地址,没有new实例化对象,不存在this,也就不存在proto对象,但依然有prototype对象
当有this.name=’Mazda’时,this变量中存有name的值,不去proto中找
当没有时,向proto中找
proto内置键名,默认不让修改,但可以修改
proto其实是个键名(键值对),通过键值对找到prototype对象,是存储prototype对象的空间,就是装prototype的容器
构造函数通过new实例化对象,生成proto属性,该属性是一个对象,指向该构造函数的原型。
实例化对象通过proto属性可以访问到该构造函数原型上的属性和方法,形成原型链。
function Car() {
/* var this = {
name:'Mazda',
__proto__: Car.prototype={
name:'Benz'
}
}
return this;
*/
// this.name='Mazda';
}
Car.prototype.name = "Benz";
var car = new Car();
console.log(car);
console.log(car.name);
proto、prototype属性可以被修改。
实例化对象没有prototype属性,有proto属性,构造函数有prototype属性,但这两个是一个东西,都指向一个空间,是一样的地址
//由张三 改成李四
function Person() {}
Person.prototype.name = "张三";
var p1 = {
name: "李四",
};
var person = new Person();
console.log(person.name); // '张三'
person.__proto__ = p1;
console.log(person.name); // '李四'
console.log(person)
console.log(person.prototype)//undefined
// 实例化对象没有prototype属性,有__proto__属性,构造函数有prototype属性,但这两个是一个东西,都指向一个空间,是一样的地址
console.log(person.__proto__)//有值
function Car() { }
Car.prototype.name = 'Mazda';
var car = new Car();
Car.prototype.name= 'Benz';
console.log(car.name); // 'Benz'
// 构造函数的原型添加name属性,空间地址不变
Car.prototype.name = 'Benz';
function Car() { }
var car = new Car();
// 构造函数的原型指向新的对象,新的空间地址
Car.prototype = {
name: 'Mazda'
}
// 实例化出来的对象的__proto__属性指向的是未修改前的Car.ptototype对象
console.log(car.name); // 'Benz'
console.log(car);
新版edge截图,与chrome一样,不同的浏览器不一样,显示结果不一样
[[Prototype]]就是proto
火狐浏览器截图
function Car() {this.a='1'}
// 构造函数的原型添加name属性,空间地址不变
Car.prototype.name = "Mazda";
var car1 = new Car();
// Car.prototype.name = "Benz";
// 构造函数的原型指向新的对象,新的空间地址
Car.prototype={
name:'Benz'
}
console.log()
var car2=new Car()
console.log(car1.name); // 'Mazda'
console.log(car1);
console.log(car2)
三、闭包立即执行函数
return形成闭包,将函数内部的AO返回到全局。
function test() {
var a = 1;
function plus1() {
a++;
console.log(a);
}
return plus1;
}
var plus = test();
plus();
plus();
plus();
function test() {
var a = 1;
function plus1() {
a++;
console.log(a);
}
return plus1;
}
var plus = test();
plus();//2
plus();
plus();//4
var plus1=test()
plus1()//2
plus1()
plus1()
plus1()//5
window,将属性和方法挂到全局对象window上,实现全局访问。
实现和return一样的闭包效果
function abc() {
window.a = 3;
}
abc();
console.log(a); // 3
function test() {
var a = 1;
function add() {
a++;
console.log(a);
}
window.add1 = add;
}
test(); // 执行后,可以在全局环境下访问到add方法
add1();
add1();
add1();
function test(){
var a=1;
function add(){
a++;
console.log(a)
}
window.add1=add;
window.add2 = add
}
test()
add1()//2
add1()
add1()
add2()//5
IIFE,声明一个全局变量接收函数返回值,或者直接挂载到window对象上。
var add1 = (function () {
var a = 1;
function add() {
a++;
console.log(a);
}
return add;
})();
add1()
add1()
//-----------------------------------------------------------------------------------------
;(function () {
var a = 1;
function add() {
a++;
console.log(a);
}
window.add = add;
})();
add();
add();
add();
四、插件开发
因为es5没有块级作用域,防止变量污染,防止全局变量污染,只有window.Test变量是全局的
在前面写;可以,在后面写也可以,在前面写防止忘了
;(function () {
function Test() { }
Test.prototype = {}
window.Test = Test;
})();
var test = new Test();
都不写;可能也行,但最好写
Test是构造函数,可以生成多个对象
相当于全局有一个Test函数或类,可以直接用,必须实例化
; (function () {
function Handphone(color, brand, system) {
this.color = color
this.brand = brand;
this.system = system;
}
Handphone.prototype = {
rom: '64G',
ram: '6G',
screen: '18:9',
call: function () {
console.log('')
}
}
window.Handphone = Handphone;
})()
var handphone=new Handphone()
var handphone1=new Handphone()
五、作业
写一个插件,任意传两个数字,调用插件内部方法可进行加减乘除功能
;(function () {
function Compute(opt) {
this.x = opt.firstNum || 0;
this.y = opt.secondNum || 0;
}
Compute.prototype = {
plus: function () {
return this.x + this.y;
},
minus: function () {
return this.x - this.y;
},
mul: function () {
return this.x * this.y;
},
div: function () {
return this.x / this.y;
}
}
window.Compute = Compute;
})();
var compute = new Compute({
firstNum: 1,
secondNum: 2
});
console.log(compute.plus());
console.log(compute.minus());
console.log(compute.mul());
console.log(compute.div());
写函数思考
1函数功能、用处?传入两个数字,返回数字的运算结果
2参数传入什么?两个数字
3返回什么?根据调用方法返回东西
;(function() {
function Compute(opt) {
this.x = opt.x;
this.y = opt.y;
}
Compute.prototype={
add:function() {
return this.x+this.y;
},
minus(){
return this.x - this.y
}
}
window.Compute = Compute
})()
var compute=new Compute({x:1,y:5})
console.log(compute.add())//6
console.log(compute.minus())//-4