关于函数、原型、dom、this的深入理解
原型深入
dom获取元素
- 通过标签获取来的是HtmlCollection,通过标签获取来的都是HtmlCollection类的一个实例
- 所有的div都是HTMLDivElement这个类的一个实例>==>HTMLElement==>Element==>Node==>EventTarget==>Object
- getElementsByName是定义在document这个家族的方法。
var p = document.getElementsByName('p'); //通过name获取来的
var oDiv = document.getElementById('div1');
var op = oDiv.getElementsByTagName('p'); //通过tag获取来的
console.dir(p); //p是NodeList的一个实例
console.dir(op);//op是HtmlCollection这个类的一个实例
//console.dir({});
//console.dir([]);
console.dir(oDiv);
//所有的div都是HTMLDivElement这个类的一个实例==>HTMLElement==>Element==>Node==>EventTarget==>Object
var sP = document.getElementById('p'); //通过oDiv来查找getElementsByName的属性,并且让这个属性的值去执行,传入了一个'p'作为参数
console.dir(sP);
// document.getElementById('p') 这个getElementById属性是不是方法也是一个函数
函数的三种角色
函数有多种角色:
- 普通函数: 函数执行的时候就会产生一个私有的作用域,栈内存。 形参赋值 预解释 代码逐行执行 闭包 内存释放问题
- 构造函数(类): new 实例 实力!! 构造函数中的this是当前实例 return问题
- 那么函数它自己本身是谁的实例 任何一个函数都是Function这个类的一个实例,那么任何一个函数实例都可以调用(proto)定义在Function这个类原型上的所有属性和方法
Object.prototype.toString.call();
var obj = {}; // [object Object]
var f = new Array(); // ""
call方法深入
call这个方法是定义在Function.prototype的方法。那么我们定义任何一个函数我们都可以认为它是Function这个类的一个实例。那么就可以通过实例的
__proto__
属性找到所属类的原型。任何一个函数都可以调用call和apply等方法 eg:Object.prototype.toString.call()
; 强制改变this
关键字的
call作用:
函数实例找到call方法执行,call的执行过程中把调用call方法这个函数实例中的this都改变成call的第一个参数。接下来再把调用call方法的这个实例函数执行
function fn() { //是Function这个类一个实例
console.log(this); //obj
}
//fn(); // this==>window
var obj = {
fn: fn
}
//obj.fn();//this ==> obj
//fn.call(obj); // 1 找到call方法并且运行 2 在运行之前把调用call方法的fn这个函数中的this都修改成call的参数,也就是obj 3 执行fn
//假如在Function的原型上没有定义一个call,我们自己模拟呢??
Function.prototype.myCall = function (obj) {
//把这个函数体内的this都改成obj这个参数
//执行fn就是this执行
//console.log(this);
this(); //因为这个this只有在调用call方法的时候才知道具体是那个函数实例
}
//fn.call(obj); // 用obj去借用fn这个方法
//
function fn1() {/*console.log(1)*/
/* this();
console.log(this)*/
console.log(1)
}
function fn2() {
console.log(2)
}
fn1.call(fn2); //1 在执行的过程中把fn1中的this改成fn2然后fn1() ==> 1
/*
* 上面的fn1.call(fn2)是改变fn1中的this
* */
(function (){}).call/*function call()*/.call.call.call.call.call(fn2);
/*
* 上面的call是改变function.__proto__.call的call方法中的this
* *///fn2 这里的fn1只是用来读取值。通过fn1来读取Function.prototype的属性
//规律: 多个call就是相当于参数执行,而调用call的方法是用来读取call这个属性值的
//Function.prototype.call(fn1); //Function.prototype是一个匿名函数,但是这个函数什么也没做
// Function.prototype.call.call.call(fn1); //fn1 ==> fn2.call.call.call(fn1)
call和apply和bind的区别
call在执行的时候,call的第一个参数是用来改变this的,而从第二个参数开始都是传给调用call的函数的
严格模式: call执行的时候和非严格模式不同 没有参数:undefined null:null undefined:undefined,非严格模式都是window
在函数体内的arguments不随着参数变化而变化 arguments.callee arugmetns.caller 不能用
this问题:严格模式自执行函数中的this是undefined,如果没有执行主体this也是undefined。非严格模式下都是window
`/*'use strict';*/ //严格模式解析代码`
function sum(num1, num2) {
//console.log(num1 + num2);
//console.log(this);
}
//sum(100,200); //300 window
//sum.call(100,200); //从第二个参数开始是传个sum的,我们此时函数已经执行结束了
//sum.call(); //window
//sum.call(null); //window
//sum.call(undefined); //window
// !function (){console.log(this)}();
apply:它跟call的用法是一样一样的。就是传参数的方式不相同而已
call:是把从第二个参数开始一个一个传给调用call的函数主体
同样也是相当于把数组中的每一项分别传给调用apply这个方法的函数实例
function sum(num1, num2) {
console.log(num2 + num1);
console.log(this);
}
//sum.apply(null,[100,200]); //apply的用法,也是把数组参数中的每一项分别传给sum的
绑定 bind: 同样也是用来改变this关键字的
/* var temp = sum.bind(null, 100, 200); 预处理 中间量 假设 标识变量
temp();*/
var obj = {name : 'zx'}
var temp = sum.bind(obj); //仅仅是改变了this,但是并没有执行 temp已经是被改变了this的函数
temp(100,200); //当我们需要的时候才执行呢
JSON操作
JSON它是一个特殊的数据格式,是可以跨平台传输的数据
var obj = {name: 'zf'};
var jsonObj = {"name" : "tx"};
JSON常用方法:
JSON.stringify() 把json格式的对象转化为字符串的
JSON.parse(); 把json格式的字符串转化为json格式的对象,低版本ie不兼容
var str = JSON.stringify(jsonObj); //json格式的字符串
console.log(JSON.parse(str)); //
正则及实战应用
正则的作用
用来判断字符串是否符合规则 处理字符串
-
test
用来验证是否符合规则返回真和假 ==》 正则匹配 -
exec
用来把当前字符串中所有符合规则的字符串获取到。 用来实现正则的捕获的。 返回的是一个数组 ==》 正则捕获
正则的创建:var reg = /\d/;
实例创建:var reg = new RegExp('');
var reg = /\d/;
console.log(reg.test('1')); //
console.log(reg.exec('x')); //
console.log(reg.exec('1')); //
正则的元字符
/*
* 正则由元字符和修饰符组成
* 1 元字符: 具有一定意义的字符 eg:\d 代表0-9中间的一个数字
* 特殊意义的元字符:
* 1 \转义字符
* 2 ^用某个元字符开头
* 3 $ 用某个元字符结尾
* 量词符:
* 1 *
* 2 +
* 3 ?
* 4 {n}
* 5 {n,}
* 6 {n,m}
* 修饰符:
* 1 g global全局
* 2 i ignoreCase忽略大小写
* 3 m multyline多行
*
* */
var reg = /\\d/;
reg.test('\d')
编写简单的正则表达式
var reg1 = /^\d+(ab|cd|xyz)\d+$/;
var reg2 = /^\d+ab|cd|xyz\d+$/;
var str1 = '400ab500';
var str2 = '234ab';
var str3 = '1324abcd';
var str4 = 'cd8888ab';
var str5 = 'xyz999ab';
//验证邮箱
//你的网站的邮箱规则
/*
* 可以包括数字 字母 下划线 @ 域名 . com/net/cc/cn只能是正常的字母
* '.'这个元字符匹配太多需要转义
* 在[]里的单个的元字符不用转义,就表示这个字母表示的本身的意思
* */
var reg = /^[\w.]+@\w+(\.[a-z]+)?$/i
/*
* 问号的几种意义?
* 1 量词出现0-1次 出现在实际意义字符后边的时候是一个量词
* 2 贪婪 or 非贪婪 出现在量词后面的问号是修饰贪婪还是非贪婪,如果不加问号那么就是把能匹配多少都拿回来,如果加一个问号。那么是尽可能少的去匹配和捕获 /\d+?/
* 3 分组中的匹配不捕获也就是子正则中的匹配不捕获,那么就不会出现在exec捕获时候返回的数组中。?: 把问号和冒号放在括号的开始位置。表示不在把括号中的内容当成一个子正则。那么这个分组其实也已经取消了 /^\d(?:ab|cd|ef)\d$/
* 4 正向预查询和负向预查询 带条件的正则表达式 ?= ?!负向预查询
* eg: 一个字符串有连续多个数字,但是这些数字后边是字母。但是只把满足条件的数组取到,后面的字母忽略。只是一个以字幕结尾这是一个条件,但是不参与捕获 var str2 = 'adsf345qwe#' 这个不行
* var str3 = 'adfa8888aaaa'
* var reg = /\d{2,}(?=[a-z]+$)/ 切记$符号不要去修饰条件。正向预查询相当于加了一个条件。这个括号里根本就不参与捕获,只是这个正则成立的条件
*
* */
/*
* [^a-z] 除了a-z以外的任意字符 var reg = /[^a-z]/;
* \d 是0-9 \D 除了0-9之外的任意字符
* \w 是[a-zA-Z0-9_]
* \W 也是取非集
* \s 一切不可见的字符集
* \S 取反
* . 除了匹配回车之外的单字符
*
*
* 验证重复的字符串 var reg = /(\w)/; reg.exec()'';
* var reg = /(\w)\1+/
*
* */
/*
*
* 分组: 难点+重点
* 1 什么是分组
* 2 分组的引用
* var reg = /^(\d)(\d)\1$/
*
* 用其他方式获取分组捕获的内容
* var reg = /(\w)(\w)(\w)/
* var str = 'abcdefghijklmn'
* reg.test(str);
* 正则这个方法只要运行了就可以去访问RegExp.$1 - $9 当这个正则实例运行之后,如果此正则上有分组,则自动把捕获到的内容分别赋值给构造函数的$1-$9,如果不够是空字符串 如果是对象类型的找不到才是null 如果是值类型的找不到事空字符串
*
*
* 模式修正符
* g
* i
* m
* 匹配模式ip地址
* 192.168.1.1
* reg.exec(); 即使你加了g也没有多次都匹配回来
* str.match 这个吧所有能匹配来的都匹配来的
* 这里有一个reg.lastIndex在作怪
* str1 = 'qewrqewr8'
* str2 = '4adfaasd'
* 因为上一次匹配的时候的lastIndex是8.下次从8开始找了。但是要用同一个reg实例
* 正则是尽可能少的去匹配次数,但是却在每次尽可能多的去匹配
* 加上了全文修饰符g每次lastIndex都会变成0,如果是验证就不要加g了。因为仅仅是为了验证而已
*
* 重点replace
* var a = [];
* str.replace(/\d/g,function (){
* return a[arguments[0]]
* arguments[0] 当前匹配结果
* arguments[1] 当前匹配结果在字符串中的索引
* arguments[2] 整个字符串
* String.fromCharCode(64+arguments[0]/1)
* })
*
*
*
* 把字符串反转的固定技巧
* 'abc'.replace(/(\w)(\w)(\w)/,'$3$2$1')
*
*
* 把不限长度的字符串反转 abcdefg
* str.replace(/\w/g,function (){
* 找到第一个用最后一个替换掉
* 第一个索引位置用arguments[1]; //length-1
* str.length-1-arguments[0]
* return str.charAt(str.length-1-arguments[1])
*
* })
*
*
* replace实现字符串去重
* var str = '88888888889999999999999997777777777777'
*
*
*
*
* */
var ary = ['a','b','c','d','e'];
var str = '12345';
str = str.replace(/\d+/g,function (){
//console.log(arguments);
//console.log(]) ;
return ary[arguments[1]];
})
console.log(str);
var str = '888888888888999999999999997777777777';
str = str.replace(/(\d)\1+/g,function (a,b,c,d){
//如果正则里有了分组就不是3个参数了 是4个参数
//如果有分组,第一个参数是总正则匹配的记过,第二个参数是子正则匹配的结果
return b;
})
console.log(str)
项目实战-表格排序
- 88
- 89
- 78
- 92
- 85
- 97
var utils = {
listToArray : function (similarArray){
/*
* try catch js
* */
var a = [];
try{
a = Array.prototype.slice.call(similarArray);
}catch (e){
alert(); //ie7 和 8 弹出
var a = [];
for(var i=0; i