一、原型
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);//64Gconsole.log(hp2.ram);//6Gconsole.log(hp1.screen);//18:9console.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();//2plus();plus();//4var plus1=test()plus1()//2plus1()plus1()plus1()//5
window,将属性和方法挂到全局对象window上,实现全局访问。
实现和return一样的闭包效果
function abc() {window.a = 3;}abc();console.log(a); // 3function 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()//2add1()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 = colorthis.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())//6console.log(compute.minus())//-4
