JS高级学习路线——面向对象进阶
构造函数进阶
使用构造函数 创建对象
用于创建对象 其除了是一个函数之外,我们又称之为构造对象的函数 - 简称构造函数
function Product(name,description){ //属性 this.name=name; // 属性 this.description = description //方法 又称方法属性 万物皆属性 this.buy=function(){ alert('buy') } } //会拷贝一份 var p1 = new Product() var p2 = new Product()
//实例p1,p2的构造函数是谁 console.log(p1.constructor) console.log(p2.constructor)
如何判断某个实例是否是根据某个构造函数创建的
if(p1 instanceof Product){
alert('true')
}
存在的问题
每个实例的name,描述确实不一样,需要单独的空间存储,但是buy方法是所有实例都一样的
为了避免内存浪费,所以出现了原型帮助我们解决这个问题
原型对象 不管你实例化多少次,都只生成一次
四种创建方式
1.传参形式
2.默认值
3.动态添加形式
4.混合模式
函数声明和函数表达式的区别
搭积木开发 -- 代码可读性极高
//产品对象 /*类 -- 抽象对象*/ function Product(name,price) { /*属性 行为 可以为空或者给默认值*/ this.name=name this.price=0; /*我们的需求:自动计算打折后的价格*/ /*形象的理解:包装*/ Object.defineProperty(this, "price", { get: function () {return price*0.9;}, set: function (value) { /*大概普通产品的价格都在0--1万*/ if(value>10000) { alert('产品价格必须在0--1万之间'); }else{ price = value; } } }); } //定义对象的两种方式 Product.prototype={ getPrice:function() { return this.price }, addToCart:function(){ alert('将物品添加到购物车') } } Product.prototype.buy=function(){} Product.prototype.addToCart=function(){} /*获取元素*/ var btn = document.getElementById('btn') var name = document.getElementById('pname') window.onload=function() { /*实例化 -- 实例 -- 具体*/ //如何使用 //对象的使用必须先实例化,对象定义好之后,都是抽象的,必须实例化成具体 var iphone = new Product() /*给对象的赋值赋值,也可以新增属性*/ iphone.name='iphone7' iphone.price=6000 /*绑定元素*/ /*通过点语法访问对象中的属性或者方法*/ name.innerHTML=iphone.name price.innerHTML=iphone.price /*绑定事件*/ btn.onclick = function(){ iphone.addToCart() } }
对象属性进阶1 get set权限
产品对象
1.对象内如何使用对象的属性和方法:this
2.对象外如何使用:先实例化,后用点语法
类 -- 抽象对象
function Product(name,price) { /*属性 行为 可以为空或者给默认值*/ this.name=name this.price=0; this.description = ''; this.zhekou = '' this.sales = '' /*我们的需求:自动计算打折后的价格*/ /*形象的理解:包装*/ Object.defineProperty(this, "price", { get: function () {return price*0.9;}, set: function (value) { /*大概普通产品的价格都在0--1万*/ if(value>10000) { alert('产品价格必须在0--1万之间'); }else{ price = value; } } }); }
get set 日期 拓展性知识
Object.defineProperty(this, "produceDate", { get: function () { return dateFormat(produceDate,'yyyy-MM-dd'); }, set: function (value) { produceDate = value; } }); function dateFormat(date,format) { var o = { "M+" : date.getMonth()+1, //month "d+" : date.getDate(), //day "h+" : date.getHours(), //hour "m+" : date.getMinutes(), //minute "s+" : date.getSeconds(), //second "q+" : Math.floor((date.getMonth()+3)/3), //quarter "S" : date.getMilliseconds() //millisecond } if(/(y+)/.test(format)) format=format.replace(RegExp.$1, (date.getFullYear()+"").substr(4- RegExp.$1.length)); for(var k in o)if(new RegExp("("+ k +")").test(format)) format = format.replace(RegExp.$1, RegExp.$1.length==1? o[k] : ("00"+ o[k]).substr((""+ o[k]).length)); return format; }
权限的设置——可读
/*我们的需求:自动计算打折后的价格*/ Object.defineProperty(this, "price", { value:5000000, writable: t, });
对象属性进阶2 公有私有属性
对象构造函数
// 私有属性好处: 安全 就类似闭包中的函数一样 减少污染 function Person(name) { //私有属性,只能在对象构造函数内部使用 var className = "用户对象"; //公有属性,在对象实例化后调用 this.name = name; //私有方法 var privateFunction = function () { alert(this.name); } //公有方法 this.publicFunction = function () { alert(this.name); //公有属性 alert(className); //正确 直接通过变量名访问 alert(this.className); //undefined 错误 不能这样访问 } //公有属性 alert(className); //正确 直接通过变量名访问 alert(this.className); //undefined 错误 不能这样访问 }
什么是公有属性:
使用象的人可以访问到对象内部的某个属性
init函数的引入
Product.prototype={ /*初始化函数的引入*/ /*我们将开发某个功能的初始化的工作都放在一起函数里面,用户只需要只要这一个工具就可以了*/ init:function(){ this.bindDOM() this.bindEvents() }, bindDOM:function(){}, bindEvents:function(){} }
私有成员的引入
//产品对象 /*类 -- 抽象对象*/ function Product(name,price) { /*属性 行为 可以为空或者给默认值*/ this.name=name this.price=1000; this.description = ''; this.produceDate /*我们的需求:自动计算打折后的价格*/ Object.defineProperty(this, "price", { value:5000000, writable: false, }); var that = this;//改变this指向 function bindDOM(){ /*获取元素*/ var btn = document.getElementById('btn') var name = document.getElementById('pname') /*绑定元素*/ /*通过点语法访问对象中的属性或者方法*/ name.innerHTML=that.name price.innerHTML=that.price } function bindEvents(){ var btn = document.getElementById('btn') /*绑定事件*/ btn.onclick = function(){ that.addToCart() } } this.init = function(){ /*访问方式:不加this*/ bindDOM() bindEvents() } } //定义对象的两种方式 Product.prototype={ getPrice:function() { return this.price }, addToCart:function(){ alert('将物品添加到购物车') } }
config
var that = this; //定义一个变量 :这个变量可以被对象中所有的属性访问到。。。。 /*避免重复,减少内存*/ /*统一管理*/ this.config = { btnConfirm: document.getElementById('btn'), btnBuy: document.getElementById('btn'), sum : 1000, des : document.getElementById('pdes'), youhuijia : document.getElementById('pyouhui'), zhekou : document.getElementById('pzhekou') } function bindDOM(){ that.config.name.innerHTML=that.name }
对象实例进阶
数据类型的复习
//数值型
var num1 = 1;
//字符串型
var num2 ='2333fgfgfggggggggggggggggggggg';
//布尔型
var num3 =false;
//对象型
var num4 = document.getElementById('mydiv');
//未定义
var num5;
call
console.log(toString.call(123)) //[object Number] var num = 123; console.log(num.toString()) //toString() 方法可把一个逻辑值转换为字符串,并返回结果
数据类型检测进阶
数据类型判断 - typeof
console.log(typeof undefined)//'undefined' console.log(typeof null) // well-known bug console.log(typeof true) //'boolean' console.log(typeof 123) //'number' console.log(typeof "abc") //'string' console.log(typeof function() {}) //'function' var arr=[]; console.log(typeof {}) //'object' console.log(typeof arr)//'object' console.log(typeof unknownVariable) //'undefined' // 在使用 typeof 运算符时采用引用类型存储值会出现一个问题, // 无论引用的是什么类型的对象,它都返回 "object"
数据类型判断 - toString.call
通用但很繁琐的方法: prototype
console.log(toString.call(123)) //[object Number] console.log(toString.call('123')) //[object String] console.log(toString.call(undefined)) //[object Undefined] console.log(toString.call(true)) //[object Boolean] console.log(toString.call({})) //[object Object] console.log(toString.call([])) //[object Array] console.log(toString.call(function(){})) //[object Function] console.log(Object.prototype.toString.call(str) === '[object String]') //-------> true; console.log(Object.prototype.toString.call(num) === '[object Number]') //-------> true; console.log(Object.prototype.toString.call(arr) === '[object Array]') //-------> true; console.log(Object.prototype.toString.call(date) === '[object Date]') //-------> true; console.log(Object.prototype.toString.call(fn) === '[object Function]') //-------> true;
数据类型判断 - instanceof
// 判断已知对象类型的方法: instanceof
console.log(arr instanceof Array) //---------------> true
console.log(date instanceof Date) //---------------> true
console.log(fn instanceof Function) //------------> true
//alert(f instanceof function) //------------> false
//注意:instanceof 后面一定要是对象类型,并且大小写不能错,该方法适合一些条件选择或分支。
数据类型判断 - 根据对象的constructor判断: constructor
// 根据对象的constructor判断: constructor var arr=[]; console.log('数据类型判断 - constructor') console.log(arr.constructor === Array) //----------> true console.log(date.constructor === Date) //-----------> true console.log(fn.constructor === Function) //-------> true
数据类型判断 函数封装
判断变量是不是数值型
function isNumber0(val){ return typeof val === 'number'; } // 但有些情况就不行,比如: // 1 var a; // 2 alert(isNumber(parseInt(a))); // 但实际上变量a是NaN,它是不能用于数值运算的。 // 所以上面的函数可以修改为: function isNumber(val){ return typeof val === 'number' && isFinite(val); } // 顺便介绍一下JavaScript isFinite() 函数,isFinite() 函数用于检查其参数是否是无穷大, // 如果 number 是有限数字(或可转换为有限数字), // 那么返回 true。否则,如果 number 是 NaN(非数字),或者是正、负无穷大的数,则返回 false。
判断变量是不是布尔类型
function isBooleanType(val) { return typeof val ==="boolean"; }
判断变量是不是字符串类型
function isStringType(val) { return typeof val === "string"; }
判断变量是不是Undefined
function isUndefined(val) { return typeof val === "undefined"; } var a;//a是undefined var s = "strType"; alert("变量a是Undefined的判断结果是:"+isUndefined(a)); alert("变量s是Undefined的判断结果是:"+isUndefined(s));
判断变量是不是对象
function isObj(str){ if(str === null || typeof str === 'undefined'){ return false; } return typeof str === 'object'; } var a; var b = null; var c = "str"; var d = {}; var e = new Object(); alert("变量a是Object类型的判断结果是:"+isObj(a));//false alert("变量b是Object类型的判断结果是:"+isObj(b));//false alert("变量c是Object类型的判断结果是:"+isObj(c));//false alert("变量d是Object类型的判断结果是:"+isObj(d));//true alert("变量e是Object类型的判断结果是:"+isObj(e));//true
判断变量是不是null
function isNull(val){ return val === null; } /*测试变量*/ var a; var b = null; var c = "str"; //弹出运行结果 alert("变量a是null的判断结果是:"+isNull(a));//false alert("变量b是null类型的判断结果是:"+isNull(b));//true alert("变量c是null类型的判断结果是:"+isNull(c));//false
判断变量是不是数组
//数组类型不可用typeof来判断。因为当变量是数组类型是,typeof会返回object。 //方法1 function isArray1(arr) { return Object.prototype.toString.call(arr) === '[object Array]'; } //方法2 function isArray2(arr) { if(arr === null || typeof arr === 'undefined'){ return false; } return arr.constructor === Array; }
Jquery判断数据类型
// jQuery提供一系列工具方法,用来判断数据类型,以弥补JavaScript原生的typeof运算符的不足。 // 以下方法对参数进行判断,返回一个布尔值。 // jQuery.isArray():是否为数组。 // jQuery.isEmptyObject():是否为空对象(不含可枚举的属性)。 // jQuery.isFunction():是否为函数。 // jQuery.isNumeric():是否为数字。 // jQuery.isPlainObject():是否为使用“{}”或“new Object”生成的对象,而不是浏览器原生提供的对象。 // jQuery.isWindow():是否为window对象。 // jQuery.isXMLDoc():判断一个DOM节点是否处于XML文档之中。
原型对象的进阶
属性屏蔽理论
function Product() { //属性 this.name = '神仙'; // 属性 this.description = '' this.buy = function() { alert('构造函数对象') } } Product.prototype = { name: '魔鬼', buy: function() { alert('原型对象') } } var product = new Product() console.log(product.name) delete product.name product.name = '魔鬼2' console.log(product.name) /*原型属性屏蔽理论 -- 乌云蔽日*/ console.log(product.buy()) /*清除乌云*/ delete product.buy //console.log(product.name) console.log(product.buy()) /*被屏蔽之后如何获取 */ //console.log(Product.prototype.buy())
hasOwnProperty
//hasOwnProperty : 看是不是对象自身下面的属性 function Product(){ this.name='iphone' } Product.prototype={ age:100 } var iphone = new Product() console.log(iphone.hasOwnProperty('name')) //true console.log(iphone.hasOwnProperty('age')) //false,原型下面的属性
constructor
//constructor : 查看对象的构造函数 function Product(){ } var iphone = new Product(); alert( iphone.constructor ); //Product var arr = []; alert( arr.constructor == Array ); //true
面相对象术语
原型构造函数
原型对象
1.原型对象里面的属性 -- 简称原型属性
Product.prototype.age = 12;
2.原型方法
Product.prototype.add=function(){}
//实例化 抽象 具体 实例 --- new Product ---类名
//使用的使用 需要先实例化:
var product = new Product(); //实例对象 实例
//如何访问对象里面的方法属性 -- 点语法
console.log(product.name)
product.add();
构造函数对象的属性和原型对象的属性区别
原型对象属性 原型对象方法 语法规范
//构造函数对象的属性和原型对象的属性 //构造函数对象属性不共享 原型对象属性共享 var iphone =new Product('iphone') var android =new Product('android') //构造函数对象属性不共享 console.log(iphone.name) //iphone console.log(android.name) //android //原型对象属性被所有实例共享 console.log(iphone.date) //2015/10/0 console.log(android.date) //2015/10/0
字面量
//简单字面量 - 描述现实世界 var book ={name:'盗墓笔记',price:100} var product={name:'iphone4s',price:6000} console.log(product.name)
//复杂字面量 var book = { name : "盗墓笔记", "main title" : "悬疑类小说", //当属性名中间有空格,或者“-”时,要用引号 把 属性名括起来 author : { //对象的属性也可以是对象 name : "徐磊", nickname : "南派三叔", works:[{name:'盗墓笔记',data:'2010'},{name:'大漠苍狼',data:'2011'},{name:'怒江之战',data:'2012'}] } }; console.log(book.name) console.log(book['main title']) console.log(book.author.name)
继承
前面讲过js中的面向对象其实是两个对象,一般构造函数对象中放置属性,原型对象中放置所有实例共享的方法
构造函数创建的实例为什么能访问原型对象的方法属性 -- 继承
构造函数对象
function Person(name, sex) { this.name = name; this.sex = sex; }
// 定义Person的原型,原型中的属性可以被自定义对象引用
// 两个对象的本质关系:原型对象继承了构造函数对象,因而可以访问构造函数对象的一切方法,属性
Person.prototype = { getName: function() { return this.name; }, getSex: function() { return this.sex; } }