目录
3.改变this指向形成闭包环境 方法一(利用变量保存的方式)
面向对象、js及其他
1.prototype、对象、属性、和方法
prototype:属性使您有能力向对象添加属性和方法。
function Product(){
this.title="sss";
this.price="ddd";
this.detial="cssdc";
}
Product.prototype={
buy:function(){
console.log("已添加到订单!");
},
shouchang:function(title){
console.log(title+"已收藏成功!");
}
}
//也可以这样定义
// Product.prototype.getPrice = function() {
// return this.price
// };
// Product.prototype.addToCart = function() {
// };
window.onload=function(){
var product1=new Product();
product1.title="iPhone X";
product1.price="49999";
product1.detial="全屏、大内存、高清......";
//动态添加属性
product1.color='blue';
product1.buy();
title=document.querySelector(".contant>.title");
title.innerHTML=product1.title;
}
2.面向对象易错语法
1.构造函数 当return一个对象时
window.onload = function () {
//构造函数 当return一个对象时
var fun = function () {
this.name = 'Joy'
return {
name: 'Jack'
}
}
var obj = new fun();
console.log(obj);//{name:Jack}
console.log(obj.name);//Jack
//等价于
function fun() {
this.name = 'Joy'
return {
name: 'Jack'
}
}
var obj = new fun;
console.log(obj);//{name:Jack}
console.log(obj.name);//Jack
}
2.变量提升和几种函数的定义
window.onload = function () {
function test() {
// 变量提升(未定义先使用 会自动相当于 在前面定义了未赋值而已)
console.log(gkk);//undefined
var gkk = 'hello';
console.log(gkk);//hello
console.log(foo);//ƒ foo() { return 'Hello';}
console.log(goo);//undefined
//函数表达式,仅变量goo被提升到顶部,实现没有提升
var goo = function () {
return 'world';
}
//函数声明,变量foo及其实现被提升到顶部
function foo() {
return 'Hello';
}
bar = function () {
console.log('world');
}
return function bar() {
console.log('This is a test function!');
}
}
//test();
var testfun = test();
testfun();//This is a test function!
console.log(testfun);//function bar() { console.log('This is a test function!');}
bar();//world
}
总结:1.关于变量提升,注意区别var和let const的定义(前者有 后两者没有)
2.关于函数变量提升
函数声明,变量foo及其实现被提升到顶部
函数表达式,仅变量goo被提升到顶部,实现没有提升
可以通过foo()调用函数,但是goo()不行
3.关于test()呢内部函数
bar = function () {
console.log('world');
}
在test函数里面不可以调用(会出现bar未定义的报错),但是在函数外面可以通过 bar() 调用
而函数 foo() 可以在test里面被调用,但是不能在外部被调用
3.改变this指向形成闭包环境 方法一(利用变量保存的方式)
// 改变this指向形成闭包环境 方法一(利用变量保存的方式)
window.onload=function(){
var name='window';
var one,two,three;
one = this;
console.log('one:'+this);//one:[object Window]
var p={
name:'xia',
getname:function(){
two=this;
console.log('two:'+this);//two:[object Object]
var obj=this;
return function(){
three=this;
console.log('three:'+this);//[object Window]
return obj.name;
}
}
}
var getname=p.getname();
var _name=getname();
console.log('name:'+_name);
// console.log(getname());
if(two == three){
console.log('two == three');
}else{
console.log('two !== three');
}
if(three == one){
console.log('three = one');
}else{
console.log('three != one');
}
// two !== three
// three = one
}
4.改变this指向闭包环境 方法二(利用call的方式)
// 改变this指向形成闭包环境 方法二(利用call的方式)
window.onload=function(){
var name='window';
console.log('one:'+this);
var p={
name:'xia',
getname:function(){
console.log('two:'+this);
return function(){
console.log('three:'+this);
return this.name;
}
}
}
var getname=p.getname();
var _name=getname.call(p);
console.log(_name);
// console.log(getname());
}
总结:不形成闭包环境 如不用getname.call(p)而用getname() 那么return的 this.name就并不是p里面的name(this不指向p)
5.循环当中的闭包知识
// 循环当中的闭包知识
window.onload=function(){
console.log('当按照通常语法习惯写循环时-------------');
for(var i=1;i<=5;i++){
console.log('i='+i);
setTimeout(()=>{
console.log('one='+i);
},i*1000);
}
console.log('改进闭包后的循环-------------');
for(var i=1;i<=5;i++){
(function(i){
setTimeout(()=>{
console.log('two='+i);
},i*1000);
})(i);
}
}
// 总结:要实现正常的循环与setTimeout的结合使用,要注意闭包问题
3.get,set和权限
1.Object.defineProperty
Object.defineProperty(this, 'price', {
get: function () {
return this.oldprice * 0.6;
},
set: function (value) {
if (value > 2000) {
alert('价格超出范围!');
}
else {
this.price = value;
}
}
});
语法规范:
Object.defineProperty(this,'price',{
get: function(){
},
set: function(value){
}
})
2.Object.defineProperties
Object.defineProperties(this, {
'price':{
get: function () {
console.log(this.oldprice);
return this.oldprice*=0.6 ;
}
},
'oldprice':{
set: function (value) {
console.log('v2=' + value);
if (value > 7000) {
alert('价格超出范围!');
this.price=200;
} else {
this.price = value;
}
}
}
})
3.权限
Object.defineProperty(this, 'count',{
value:'6折',
writable:false
});
4.构造函数、原型对象、实例对象
构造函数,原型对象,实例对象三者之间的关系
每创建一个函数,该函数都会自动带有一个prototype属性。该属性是一个指针,指向一个对象,该对象称之为原型对象(后期我们可以使用这个原型对象帮助我们在js中实现继承)。
原型对象上默认有一个属性constructor,该属性也是一个指针,指向其相关联的构造函数。
通过调用构造函数产生的实例对象,都拥有一个内部属性,指向了原型对象。其实例对象能够访问原型对象上的所有属性和方法。
总结:三者的关系是,每个构造函数都有一个原型对象,原型对象上包含着一个指向构造函数的指针,而实例都包含着一个指向原型对象的内部指针。通俗的说,实例可以通过内部指针访问到原型对象,原型对象可以通过constructor找到构造函数。
原文链接:https://blog.csdn.net/weixin_38055381/article/details/82183215
// 构造函数
function Product(){
this.name='xia',
this.price='3000'
}
// 原型对象
Product.prototype={
name:'liu',
color:'blue',
buy:function(){
}
}
// 实例对象
var p1=new Product;
// 属性屏蔽理论
console.log(p1.name);//xia
// 方法一
// delete p1.name;
// console.log(p1.name);//liu
// 方法二
console.log(Product.prototype.name);
属性屏蔽理论:
当原型和构造函数里面有相同属性时,访问该属性时,显示的是构造函数内的属性
若想要访问原型中的被屏蔽的属性有两种方法
1.delete(清除构造函数里的相同属性,再访问)
2.通过属性搜索法则,使用prototype属性或者方法名称访问 (构造函数名称.prototype.属性名)
注意:一般情况下,在构造函数中添加属性,在原型中添加方法,尽量不要再原型中添加属性,公共的属性和常量值可以放到原型对象上去
原型对象本质:原型对象的属性和方法可以被所有实例共享
注:通过修改一处修改所有实例属性,适用于 引用属性
// 原型对象的本质:共享
function Product(){
this.price='3000',
this.color='blue'
}
Product.prototype={
info:{
name:'peter',
age:25
}
}
var p1=new Product;
var p2=new Product;
// 通过修改一处修改所有实例属性
p1.info.name='jack';
console.log(p1.info.name);//jack
console.log(p2.info.name);//jack
5.正则表达式
正则表达式的创建方法:字面量创建方式、实例创建方式
var reg = /pattern/flags
// 字面量创建方式
var reg = new RegExp(pattern,flags);
//实例创建方式
pattern:正则表达式
flags:标识(修饰符)
标识主要包括:
1. i 忽略大小写匹配
2. m 多行匹配,即在到达一行文本末尾时还会继续寻常下一行中是否与正则匹配的项
3. g 全局匹配 模式应用于所有字符串,而非在找到第一个匹配项时停止
元字符
代表特殊含义的元字符
\d : 0-9之间的任意一个数字\d只占一个位置
\w : 数字,字母 ,下划线 0-9 a-z A-Z _
\s : 空格或者空白等
\D : 除了\d
\W : 除了\w
\S : 除了\s
. : 除了\n之外的任意一个字符
\ : 转义字符
| : 或者
() : 分组
\n : 匹配换行符
\b : 匹配边界 字符串的开头和结尾 空格的两边都是边界 => 不占用字符串位数
^ : 限定开始位置 => 本身不占位置
$ : 限定结束位置 => 本身不占位置 [a-z] : 任意字母 []中的表示任意一个都可以 [^a-z] : 非字母 []中^代表除了
[abc] : abc三个字母中的任何一个 [^abc]除了这三个字母中的任何一个字符
代表次数的量词元字符
* : 0到多个
+ : 1到多个
? : 0次或1次 可有可无
{n} : 正好n次;
{n,} : n到多次
n,m} : n次到m次
replace用法示例
var str = '1223334444';
var reg = /\d{2}/g;
var res = str.match(reg);
console.log(res) //["12", "23", "33", "44", "44"]
var str =' 我是空格君 ';
var reg = /^\s+|\s+$/g; //匹配开头结尾空格
var res = str.replace(reg,'');
console.log('('+res+')') //(我是空格君)
replace高级用法示例($1、$2)
//正则表达式 固定日期格式 $1、$2(分别表示第一个,第二个括号内的内容)
function changeDay(str){
return str.replace(/^(\d{4})(\S*|\s*)(\d{2})(\S*|\s*)(\d{2})(\S*|\s*)$/,"$1-$3-$5")
}
var str1='20190809';
var str2='2013年08月06日'
console.log(changeDay(str1));
console.log(changeDay(str2));
常用正则表达式大全
匹配中文字符的正则表达式: [u4e00-u9fa5]
评注:匹配中文还真是个头疼的事,有了这个表达式就好办了
匹配双字节字符(包括汉字在内):[^x00-xff]
评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)
匹配空白行的正则表达式:ns*r
评注:可以用来删除空白行
匹配HTML标记的正则表达式:<(S*?)[^>]*>.*?|<.*? />
评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力
匹配首尾空白字符的正则表达式:^s*|s*$
评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式
匹配Email地址的正则表达式:、w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*
评注:表单验证时很实用
匹配网址URL的正则表达式:[a-zA-z]+://[^s]*
评注:网上流传的版本功能很有限,上面这个基本可以满足需求
匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
评注:表单验证时很实用
匹配国内电话号码:d{3}-d{8}|d{4}-d{7}
评注:匹配形式如 0511-4405222 或 021-87888822
匹配腾讯QQ号:[1-9][0-9]{4,}
评注:腾讯QQ号从10000开始
匹配中国邮政编码:[1-9]d{5}(?!d)
评注:中国邮政编码为6位数字
匹配身份证:d{15}|d{18}
评注:中国的身份证为15位或18位
匹配ip地址:d+.d+.d+.d+
评注:提取ip地址时有用
匹配特定数字:
^[1-9]d*$ //匹配正整数
^-[1-9]d*$ //匹配负整数
^-?[1-9]d*$ //匹配整数
^[1-9]d*|0$ //匹配非负整数(正整数 + 0)
^-[1-9]d*|0$ //匹配非正整数(负整数 + 0)
^[1-9]d*.d*|0.d*[1-9]d*$ //匹配正浮点数
^-([1-9]d*.d*|0.d*[1-9]d*)$ //匹配负浮点数
^-?([1-9]d*.d*|0.d*[1-9]d*|0?.0+|0)$ //匹配浮点数
^[1-9]d*.d*|0.d*[1-9]d*|0?.0+|0$ //匹配非负浮点数(正浮点数 + 0)
^(-([1-9]d*.d*|0.d*[1-9]d*))|0?.0+|0$ //匹配非正浮点数(负浮点数 + 0)
评注:处理大量数据时有用,具体应用时注意修正
匹配特定字符串:
^[A-Za-z]+$ //匹配由26个英文字母组成的字符串
^[A-Z]+$ //匹配由26个英文字母的大写组成的字符串
^[a-z]+$ //匹配由26个英文字母的小写组成的字符串
^[A-Za-z0-9]+$ //匹配由数字和26个英文字母组成的字符串
^w+$ //匹配由数字、26个英文字母或者下划线组成的字符串
只能输入数字:“^[0-9]*$”
只能输入n位的数字:“^d{n}$”
只能输入至少n位数字:“^d{n,}$”
只能输入m-n位的数字:“^d{m,n}$”
只能输入零和非零开头的数字:“^(0|[1-9][0-9]*)$”
只能输入有两位小数的正实数:“^[0-9]+(.[0-9]{2})?$”
只能输入有1-3位小数的正实数:“^[0-9]+(.[0-9]{1,3})?$”
只能输入非零的正整数:“^+?[1-9][0-9]*$”
只能输入非零的负整数:“^-[1-9][0-9]*$”
只能输入长度为3的字符:“^.{3}$”
只能输入由26个英文字母组成的字符串:“^[A-Za-z]+$”
只能输入由26个大写英文字母组成的字符串:“^[A-Z]+$”
只能输入由26个小写英文字母组成的字符串:“^[a-z]+$”
只能输入由数字和26个英文字母组成的字符串:“^[A-Za-z0-9]+$”
只能输入由数字、26个英文字母或者下划线组成的字符串:“^w+$”
验证用户密码:“^[a-zA-Z]w{5,17}$”正确格式为:以字母开头,长度在6-18之间,
只能包含字符、数字和下划线。
验证是否含有^%&'',;=?$"等字符:“[^%&'',;=?$x22]+”
只能输入汉字:“^[u4e00-u9fa5],{0,}$”
验证Email地址:“^w+[-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*$”
验证InternetURL:“^http://([w-]+.)+[w-]+(/[w-./?%&=]*)?$”
验证电话号码:“^((d{3,4})|d{3,4}-)?d{7,8}$”
正确格式为:“XXXX-XXXXXXX”,“XXXX-XXXXXXXX”,“XXX-XXXXXXX”,
“XXX-XXXXXXXX”,“XXXXXXX”,“XXXXXXXX”。
验证身份证号(15位或18位数字):“^d{15}|d{}18$”
验证一年的12个月:“^(0?[1-9]|1[0-2])$”正确格式为:“01”-“09”和“1”“12”
验证一个月的31天:“^((0?[1-9])|((1|2)[0-9])|30|31)$”
正确格式为:“01”“09”和“1”“31”。
匹配中文字符的正则表达式: [u4e00-u9fa5]
匹配双字节字符(包括汉字在内):[^x00-xff]
匹配空行的正则表达式:n[s| ]*r
匹配HTML标记的正则表达式:/<(.*)>.*|<(.*) />/
匹配首尾空格的正则表达式:(^s*)|(s*$)
匹配Email地址的正则表达式:w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*
匹配网址URL的正则表达式:http://([w-]+.)+[w-]+(/[w- ./?%&=]*)?*/
6.数据绑定
1.字符串拼接 ++++
略
2.formatString 正则表达式+replace
/* 数据绑定:
1.字符拼接 +++
2.foramteString 正则表达式+replace
3.模板
*/
function formateString(str,data){
return str.replace(/#\((\w+)\)/g,function(match,key){
return typeof data[key] === 'undefined' ? '' : data[key];
})
}
function $(id){
return document.getElementById(id);
}
window.onload=function(){
var user={name:'TFBOYS',time:'六周年演唱会'};
$('test').innerHTML=formateString('祝#(name)#(time)顺利举行!',user);
$('test').style='color:orange';
}
3.模板 template
用法一
<script>
var event = {
title: 'TFBOYS六周年演唱会',
person: 'TFBOYS',
time: '2019-08-10',
place: '深圳体育馆',
detail: '祝TFBOYS六周年演唱会顺利举行!'
}
/* data:要绑定的数据
divid:最终templa存放的位置
template:数据要绑定的template模块
总结:把data绑定到template里再放到divid里
*/
function bindTemplate(data, divid, template) {
var html = template(template, data);
document.getElementById(divid).innerHTML = html;
}
window.onload = function () {
bindTemplate(event, 'divbox', 'arttemplate')
// console.log(document.getElementById('arttemplate'));
}
</script>
<body>
<div id="divbox">
<!-- template模板 -->
<div id="arttemplate">
<h2>{{title}}</h2>
<div class="person">主要人物:{{ person }}</div>
<div class="time">时间:{{ time }}</div>
<div class="place">地点:{{ place }}</div>
<div class="detail">详情:{{ detail }}</div>
</div>
</div>
</body>
用法二:
//在字符串拼接中使用模块
window.onload = function () {
var film = { name: '美人鱼', lead: '周星驰', role: '邓超' }
var source = '<strong>{{name}}</strong>'
+ '<strong>{{lead}}</strong>'
+ '<strong>{{role}}</strong>';
var rendar = template.compile(source);
var html = rendar(film);
document.getElementById('content').innerHTML = html;
}
注意:要引入template.js文件才能使用template函数 文件内容如下:
/*!art-template - Template Engine | http://aui.github.com/artTemplate/*/
!function(){function a(a){return a.replace(t,"").replace(u,",").replace(v,"").replace(w,"").replace(x,"").split(y)}function b(a){return"'"+a.replace(/('|\\)/g,"\\$1").replace(/\r/g,"\\r").replace(/\n/g,"\\n")+"'"}function c(c,d){function e(a){return m+=a.split(/\n/).length-1,k&&(a=a.replace(/\s+/g," ").replace(/<!--[\w\W]*?-->/g,"")),a&&(a=s[1]+b(a)+s[2]+"\n"),a}function f(b){var c=m;if(j?b=j(b,d):g&&(b=b.replace(/\n/g,function(){return m++,"$line="+m+";"})),0===b.indexOf("=")){var e=l&&!/^=[=#]/.test(b);if(b=b.replace(/^=[=#]?|[\s;]*$/g,""),e){var f=b.replace(/\s*\([^\)]+\)/,"");n[f]||/^(include|print)$/.test(f)||(b="$escape("+b+")")}else b="$string("+b+")";b=s[1]+b+s[2]}return g&&(b="$line="+c+";"+b),r(a(b),function(a){if(a&&!p[a]){var b;b="print"===a?u:"include"===a?v:n[a]?"$utils."+a:o[a]?"$helpers."+a:"$data."+a,w+=a+"="+b+",",p[a]=!0}}),b+"\n"}var g=d.debug,h=d.openTag,i=d.closeTag,j=d.parser,k=d.compress,l=d.escape,m=1,p={$data:1,$filename:1,$utils:1,$helpers:1,$out:1,$line:1},q="".trim,s=q?["$out='';","$out+=",";","$out"]:["$out=[];","$out.push(",");","$out.join('')"],t=q?"$out+=text;return $out;":"$out.push(text);",u="function(){var text=''.concat.apply('',arguments);"+t+"}",v="function(filename,data){data=data||$data;var text=$utils.$include(filename,data,$filename);"+t+"}",w="'use strict';var $utils=this,$helpers=$utils.$helpers,"+(g?"$line=0,":""),x=s[0],y="return new String("+s[3]+");";r(c.split(h),function(a){a=a.split(i);var b=a[0],c=a[1];1===a.length?x+=e(b):(x+=f(b),c&&(x+=e(c)))});var z=w+x+y;g&&(z="try{"+z+"}catch(e){throw {filename:$filename,name:'Render Error',message:e.message,line:$line,source:"+b(c)+".split(/\\n/)[$line-1].replace(/^\\s+/,'')};}");try{var A=new Function("$data","$filename",z);return A.prototype=n,A}catch(B){throw B.temp="function anonymous($data,$filename) {"+z+"}",B}}var d=function(a,b){return"string"==typeof b?q(b,{filename:a}):g(a,b)};d.version="3.0.0",d.config=function(a,b){e[a]=b};var e=d.defaults={openTag:"<%",closeTag:"%>",escape:!0,cache:!0,compress:!1,parser:null},f=d.cache={};d.render=function(a,b){return q(a,b)};var g=d.renderFile=function(a,b){var c=d.get(a)||p({filename:a,name:"Render Error",message:"Template not found"});return b?c(b):c};d.get=function(a){var b;if(f[a])b=f[a];else if("object"==typeof document){var c=document.getElementById(a);if(c){var d=(c.value||c.innerHTML).replace(/^\s*|\s*$/g,"");b=q(d,{filename:a})}}return b};var h=function(a,b){return"string"!=typeof a&&(b=typeof a,"number"===b?a+="":a="function"===b?h(a.call(a)):""),a},i={"<":"<",">":">",'"':""","'":"'","&":"&"},j=function(a){return i[a]},k=function(a){return h(a).replace(/&(?![\w#]+;)|[<>"']/g,j)},l=Array.isArray||function(a){return"[object Array]"==={}.toString.call(a)},m=function(a,b){var c,d;if(l(a))for(c=0,d=a.length;d>c;c++)b.call(a,a[c],c,a);else for(c in a)b.call(a,a[c],c)},n=d.utils={$helpers:{},$include:g,$string:h,$escape:k,$each:m};d.helper=function(a,b){o[a]=b};var o=d.helpers=n.$helpers;d.onerror=function(a){var b="Template Error\n\n";for(var c in a)b+="<"+c+">\n"+a[c]+"\n\n";"object"==typeof console&&console.error(b)};var p=function(a){return d.onerror(a),function(){return"{Template Error}"}},q=d.compile=function(a,b){function d(c){try{return new i(c,h)+""}catch(d){return b.debug?p(d)():(b.debug=!0,q(a,b)(c))}}b=b||{};for(var g in e)void 0===b[g]&&(b[g]=e[g]);var h=b.filename;try{var i=c(a,b)}catch(j){return j.filename=h||"anonymous",j.name="Syntax Error",p(j)}return d.prototype=i.prototype,d.toString=function(){return i.toString()},h&&b.cache&&(f[h]=d),d},r=n.$each,s="break,case,catch,continue,debugger,default,delete,do,else,false,finally,for,function,if,in,instanceof,new,null,return,switch,this,throw,true,try,typeof,var,void,while,with,abstract,boolean,byte,char,class,const,double,enum,export,extends,final,float,goto,implements,import,int,interface,long,native,package,private,protected,public,short,static,super,synchronized,throws,transient,volatile,arguments,let,yield,undefined",t=/\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|\s*\.\s*[$\w\.]+/g,u=/[^\w$]+/g,v=new RegExp(["\\b"+s.replace(/,/g,"\\b|\\b")+"\\b"].join("|"),"g"),w=/^\d[^,]*|,\d[^,]*/g,x=/^,+|,+$/g,y=/^$|,+/;e.openTag="{{",e.closeTag="}}";var z=function(a,b){var c=b.split(":"),d=c.shift(),e=c.join(":")||"";return e&&(e=", "+e),"$helpers."+d+"("+a+e+")"};e.parser=function(a){a=a.replace(/^\s/,"");var b=a.split(" "),c=b.shift(),e=b.join(" ");switch(c){case"if":a="if("+e+"){";break;case"else":b="if"===b.shift()?" if("+b.join(" ")+")":"",a="}else"+b+"{";break;case"/if":a="}";break;case"each":var f=b[0]||"$data",g=b[1]||"as",h=b[2]||"$value",i=b[3]||"$index",j=h+","+i;"as"!==g&&(f="[]"),a="$each("+f+",function("+j+"){";break;case"/each":a="});";break;case"echo":a="print("+e+");";break;case"print":case"include":a=c+"("+b.join(",")+");";break;default:if(/^\s*\|\s*[\w\$]/.test(e)){var k=!0;0===a.indexOf("#")&&(a=a.substr(1),k=!1);for(var l=0,m=a.split("|"),n=m.length,o=m[l++];n>l;l++)o=z(o,m[l]);a=(k?"=":"=#")+o}else a=d.helpers[c]?"=#"+c+"("+b.join(",")+");":"="+a}return a},"function"==typeof define?define(function(){return d}):"undefined"!=typeof exports?module.exports=d:this.template=d}();
7.值类型与引用类型
其中:栈,存储值类型;堆,存储引用类型
7.对象
内置对象
String、Date、Math、Array、RegExp、Number、Object、Function、Null、Boolean、Error、Cookie、Session
BOM对象 浏览器对象模型
Window、Document、History、Location、Screen、Navigator
DOM对象 文档对象模型
自定义对象 多种方式创建对象
1.object
2.工厂模式创建对象
/* 工厂模式创建对象
好处:不用考虑实例问题,所有和创建一个对象的代码都统一交给‘工厂’来做
*/
function createPerson(name){
//原料
var obj=new Object();
//加工
obj.name=name;
obj.HP=100;
obj.MP=100;
obj.technologys=['普通攻击','横扫千军','地狱火','漫天飞雪'];
obj.attack = function(num){
alert(name+'发动技能['+obj.technologys[num]+'],对方能量-10')
};
obj.run = function(){
alert('溜了溜了!');
};
//出厂
return obj;
}
// 准备原料
var people=['剑侠客','飞天舞女','冷千面'];
// 往厂内添加原料
var person1=createPerson(people[1]);
// 使用产品
person1.attack(3);
person1.run();
工厂模式创建对象
好处:不用考虑实例问题,所有和创建一个对象的代码都统一交给‘工厂’来做
注:当我们new一个对象时(var car=new Car()):
1.第一步:在内存中开辟一块空间
2.第二步:创建一个新空对象
3.第三步:把this指向这个空对象
4.第四步:把空对象的 内部原型 指向 构造函数的原型对象 car.__proto__=Car.prototype
5.第五步:当构造函数执行完成后,如果有return的话,那么把当前空对象(此时这个对象不一定为空)返回
3.字面量创建对象
// json形式 字面量创建对象
var person={
name:'',
HP:100,
MP:100,
technologys:['普通攻击','横扫千军','地狱火','漫天飞雪'],
attack: function(num){
alert(person.name+'发动技能 ['+person.technologys[num]+'] ,对方能量-10')
},
run: function(){
alert('溜了溜了!');
}
}
person.name='飞天舞女';
person.attack(3);
// json对象转化为字符串 JSON.stringify()
var str=JSON.stringify(person);
console.log(str);
// 字符串转化为json对象 JSON.parse()
var string='{"name":"剑侠客","attack":"横扫千军"}';//注意string字符串一定要是外面外小双引号,大打单引号
var boy=JSON.parse(string);
console.log(boy);
console.log(boy.name);
4.拷贝
/* 函数作用 将一个json对象 所有属性拷贝给另一个对象
target:目标对象
source:原对象
*/
function extend(target,source){
// for(key in source){
// target[key]=source[key];
// }
target=source;
return target;
}
var boy={
name:'冷晗凌',
age:19,
sex:'男'
}
var girl={
name:'慕千雪',
age:18,
sex:'女'
}
var lenghanling=extend({},boy);
console.log(lenghanling.name);
console.log(lenghanling.age);
console.log(lenghanling.sex);
/* Mextend函数 将多个json拷贝给目标对象
target:目标对象
arry:原对象构成的 对象数组
*/
function Mextend(target,...arry){
// console.log(b[0]);
var len=arry.length;
var i=0;
if(len==0){
return {};
}
if(length==1){
i++;
target=arry[0];
}
for(;i<len;i++){
for(key in arry[i]){
target[key]=arry[i][key];
}
}
return target;
}
var technology = {tname:'亡灵复活',tlevel:10,tstrength:3000,tmagic:30};
var shenqi = {sname:'霜之哀伤',slevel:30,sstrength:3000}
var fuzi=Mextend({},technology,shenqi);
console.log(fuzi);
console.log(fuzi.tname);
console.log(fuzi.sname);
console.log(fuzi.__proto__);
console.log(fuzi.__proto__.hasOwnProperty);
8.查询字符串
网页跳转 window.location
window.location='detail.html?nameId='+that.num+'&imgId=99';
获取URL当中携带的数据
function getDataJson() {
var shuju = location.search.substring(1);//截取URL当中?后面的内容
var shujuArray = shuju.split(/&/g);//将数据根据&分段形成数组
var json = {};
for (var i = 0; i < shujuArray.length; i++) {
var num = shujuArray[i].indexOf('=');//获取=的位置序号
if (num == -1) continue;//如果没有发现则跳到下一次循环继续操作
var key = shujuArray[i].substring(0, num);//截取等号前的数据名称
var keydata = shujuArray[i].substring(num + 1);//截取等号后的数据值
json[key] = keydata;//以名/值对的形式将数据存储在json当中,形成json数据
}
return json;
}
9.__proto__
console.log('Array对象');
var arr1 = new Array();
console.log(arr1.__proto__ === Array.prototype);//true
console.log(Array.prototype.__proto__ === Function.prototype);//false
console.log(Array.prototype.__proto__ === null);//false
console.log(Array.__proto__ === Function.prototype);//true
console.log(Function.prototype.__proto__ === Object.prototype);//true
console.log(Object.prototype.__proto__ === null);//true
console.log('Object对象');
var Product = function () { }
var product = new Product();
console.log(product.__proto__ === Product.prototype);//true
console.log(Product.prototype.__proto__ === Object.prototype);//true
console.log(Product.__proto__ === Function.prototype);//true
console.log(Object.__proto__ === Function.prototype);//true
console.log(Function.prototype.__proto__ === Object.prototype);//true
console.log(Object.prototype.__proto__ === null);//true
总结:
1.通过function创建的自定义对象(Product)、内置对象(Array)、函数(Function)都指向(__proto__)Function.prototype
2.通过function创建的自定义对象(Product)、内置对象(Array、Object、等)、函数(Function)的原型对象(prototype)都指向(__proto__)Object.prototype
3.实例(product)都指向(__proto__)对应对象的原型对象(prototype),字面量创建的对象指向(__proto__)Object.prototype
4.注意:对比1,2两点,一个是原型对象一个是构造对象,带prototype都是原型对象,指向都带有__proto__
5.Object的原型对象(Object.prototype)指向 null
10.面向对象那个的三大特点
封装性:指私有方法和属性外部不能直接调用,要通过公有属性的方法先调用,外部再调用公有属性和方法,从而达到调用私有属性和方法的目的,实现了面向对象的封装性。或者解释为:我们可以将方法属性归类到一个对象当中,比如产品对象放置和产品有关的方法,属性,这就是封装性
继承性:父类与子类之间的继承关系
重载性: 一个方法,名称相同,通过参数个数不同或者参数的类型不同执行不同的功能
11.继承
ES5写法:
//父类 基类 属性和方法
var Person = function () {
this.name = 'TFBOYS-王源',
this.age = 18,
this.sex = '男'
}
Person.prototype = {
introudes: function () {
console.log('大家好,我是' + this.name);
},
showage:function(){
console.log('I am '+this.age+'years old');
}
}
//子类
var Student = function () {
//继承父类的属性
Person.call(this, arguments),
//添加自己的属性
this.ID = 1520173643,
this.birthday = '2000-11-08'
}
//继承父类的方法
Student.prototype = new Person();
//添加自己的方法
Student.prototype.study = function () {
console.log('my birthday is ' + this.birthday);
}
//方法重写
Student.prototype.showage=function(){
console.log('I am 19 years old');
}
var Engner = function () {
//继承父类的属性
Person.call(this, arguments),
//添加自己的属性
this.color='red'
}
//继承父类的方法
Engner.prototype = new Person();
Engner.prototype.showage=function(){
console.log('adsdsads');
}
var s1 = new Student();
s1.introudes();
console.log(s1.name);
console.log(s1.ID);
s1.study();
s1.showage();
var p1=new Person();
p1.showage();
var e1=new Engner();
e1.showage();
注意:对象继承属性用 Person.call(this, arguments),其中 arguments在有对象有传入参数的情况下可以改成传入的参数;
对象继承方法用 Student.prototype = new Person();或者 Student.prototype = Person.prototype,这两者的区别在于,前者可以使后面子类添加的方法子属于该子类,不会添加到父类当中,但是后者在该子类添加方法后,会使父类和其它子类均能使用该方法。
ES6写法:
class Father{
//constructor相当于一个构造器
constructor(name,age){
this.name=name;
this.age=age;
}
// 与子类同名方法
eat(){
console.log('Father is eating!');
}
//static使父类的方法不被子类继承(子类实例无法调用该方法。但是子类本身可以调用)
static run(){
console.log('Father is running!');
}
work(){
console.log('Father is working!');
}
}
//子类通过extends来继承父类
class Son extends Father{
constructor(name,sex){
//通过super来继承父类constructor内的属性
super(name);
this.sex=sex;
}
// 与父类同名方法
eat(){
console.log('Son is eating!');
}
sleep(){
console.log('Son is sleep!');
}
}
let f1=new Father('ISfather','34');
let s1=new Son('ISson','boy');
console.log(s1);//Son{name:'ISson',age:undefined,sex:'boy'}
// 当父类和之类有相同名字的方法时,优先调用子类的方法
s1.eat();//Son is eating!
//static的作用是
s1.run();//报错 子类实例无法调用父类static方法
Son.run();//Father is running! 子类本身可以调用父类static方法
s1.work();//Father is working! 非static父类方法子类实例可以调用
12.call和apply
call的用途举例:更改调用对象this指向
<body>
<input type="search" value="啦啦啦" id="myinput">
</body>
<script>
// call更改调用对象this指向
var value = '全局变量';
function fn() {
console.log(this.value);
}
function fn2() {
return function () {
console.log(this.value);
}
}
var myinput=document.getElementById('myinput');
var ff = fn2();
ff();
ff.call(myinput);
fn();
fn.call(myinput);
</script>
call的用途:利用call伪数组转化为真数组
function add(){
// 利用call伪数组转化为真数组 arguments是伪数组
var Arrayarguments=Array.prototype.slice.call(arguments);
Arrayarguments.push(10);
var sum=0;
for(var i=0;i<Arrayarguments.length;i++){
console.log(Arrayarguments[i]);
sum+=Arrayarguments[i];
}
return sum;
}
var sum=add(2,4,7,9,6,5);
console.log(sum);
call的供爷法则
// 对象1
var myclass = {
getname: function () {
console.log('this is class function!');
}
}
// 对象2
var student = {
getdetail: function () {
return { name: 'Lan', age: 18 };
}
}
//call的供爷法则
myclass.getname.call(student);
console.log(student.getdetail.call(myclass));
apply的用途:求一个数组当中的最大值
//求一个数组当中的最大值
// 方法一 ES6的...
var array1=[2,4,7,9,6,5];
console.log(Math.max(...array1));
// 方法二 常规遍历依次比较
// 方法三 apply 接受数组参数
var array2=[1,4,7,9,16,5];
var maxnum=Math.max.apply(null,array2);
console.log(maxnum);
// 注:如果是离散参数则可以用call
var maxnum1=Math.max.call(null,1,4,7,9,16,5);
console.log(maxnum1);
apply的用途:利用apply合并数组
//利用apply合并数组
var array1 = [2, 4, 6, 8, 9];
var array2 = [1, 3, 5, 7, 10];
Array.prototype.push.apply(array1, array2);
//合并后的数组array1
console.log(array1);