② 内嵌式注意: script 建议写在所有元素的后面!③ 外链式注意: script 建议写在所有元素的后面!1.2 j_js笔记">
赞
踩
<button οnclick="js代码"></button>
<script>
js代码...
</script>
注意: script 建议写在所有元素的后面!
<script src="js文件的地址"></script>
注意: script 建议写在所有元素的后面!
// 单行注释
/*
多行注释
*/
// 以弹框的形式输出
alert()
// 输出到控制台
console.log()
// 输出到页面
document.write()
数据: 程序中使用的都是数据。
直接量: 直接使用数据,就是直接量
变量: 给数据取个名字,就是变量。使用变量就是使用数据。
// 1. 定义变量使用 var 关键字, 使用变量的时候不需要加 var
var username = '啊你';
// 2. 可以先定义变量再赋值,也可以定义的同时去赋值
var age;
age = 200;
// 3. 可以同时声明多个变量
var num1 = 10, num2 = 20, num3 = 30;
// 4. 变量的值可以修改
强制遵循:
1. 变量名由数字、字母、下划线和 $ 组成,但是不能以数字开头。
2. 变量名不能关键字和保留字。
3. 变量名严格区分大小写。
建议遵循:
1. 变量名应该是有意义的单词
2. 如果变量名由多个单词组成,建议使用小驼峰命名法
3. 不要英文和拼音混合使用
原始类型:
1. number 数值
2. string 字符串
3. boolean 布尔值
4. null 空
5. undefined 未定义
对象类型:
.......
typeof('hello world')
typeof(msg);
// 十进制表示
100
// 八进制表示
0100
// 十六进制表示
0x100
// 常规的小数
10.23
0.5 //简写为 .5
// 科学计数法
12e23 // 12 * 10^23
注意: 浮点数的计算存在精度问题!0
NaN 也是 number 的一个值,一般其他类型转为 number 类型的时候,如果无法转为正常的数字,就会转为 NaN
NaN 两个特点:
1. NaN 与任何数据运算,结果都是 NaN
2. NaN 与任何数据都不相等,包括自己
如果超过范围,会表示为 Infinity(正无穷) 或者 -Infinity
isNaN()判断一个数字是否是NaN,或者其他类型的数据是否可以转换为NaN
isFinite()判断一个数字是否在有效范围内
使用单引号或者双引号作为字符串的定界符
如果字符串的定界符是双引号,字符串内容中就不要出现双引号了,
如果字符串的定界符是单引号,字符串内容中就不要出现单引号了,
\n 换行符
\'单引号转义
\"双引号转义
\uXXXX unicode 编码
表示一种状态 ,两个值ture 或false
null 表示的是空
如果定义了变量暂时不知道赋什么值,可以先赋值为null
undefined 表示的是未定义
定义了但是没有赋值,一般不需要主动定位为undefined
1. 字符串转为number
纯数字字符串转为对应的数字,空字符串(或者纯空格字符串)转为0,其他字符串转为NaN
2.布尔值转为number
true->1
false->0
3.null转为number 转为0
4.undefined转为number,转为NaN
1数值转为字符串
转为数字组成的字符串,NaN转为NaN
2.布尔值转为字符串
true->"true"
flase->"flase"
3.null->"null"
4.undefined->"undefined"
1. 数值转为布尔值
0 和 NaN 转为 false,其他的转为 true
2. 字符串转为布尔值
空字符串转为 false,其他的转为 true
3. null -> false
4. undefined -> false
Number()
parseInt() 截取字符串里面的数字
parseFloat() 截取字符串里面的数字
parseInt()、parseFloat() 与 Number() 转换规则的区别:
- parseInt()、parseFloat() 可以把以数字开头的字符串转为开头的数字(提取字符串中的数字)
- 空字符串、纯空格字符串和其他形式的字符串都是 NaN
- 布尔值、null、undefined 都会转为 NaN
parseInt 和 parseFloat 的区别:
- parseInt() 只提取字符串中数字里的整数部分
- parseFloat() 提取字符串中数字的整数部分加小数部分
String()
Boolean()
当某个数据处在某种运算环境下,而该数据不是该运算环境需要的类型,此时数据会进行自动类型转换,转为运算环境需要的类型。
数据会自动转为当前所处的运算环境需要的类型
用于运算符的符号就是运算符
与运算符一起参与运算的变量或者直接量,称之为操作数
一元运算符(一目运算符)
二元运算符(二目运算符)
三元运算符(三目运算符)
算术运算符
关系运算符
逻辑运算符
位运算符
赋值运算符
其他运算符
运算符 | 含义 | 操作数个数 | 操作数的类型要求 | 组成的表达式的值的类型 | 有无副作用 |
---|---|---|---|---|---|
+ | 数学加号 | 2 | number | number | 无 |
- | 数学减号 | 2 | number | number | 无 |
* | 数学乘号 | 2 | number | number | 无 |
/ | 数学除号 | 2 | number | number | 无 |
% | 取余 | 2 | number | number | 无 |
+ | 正号 | 1 | number | number | 无 |
- | 负号 | 1 | number | number | 无 |
++ | 递增 | 1 | number | number | 有 |
– | 递减 | 1 | number | number | 有 |
注意:
正号运算符通常可以用来把其他类型的数据转为 number。
++ 和 – 组成的表达式,运算符在操作数的前面或后买,表达式的值是不同的;副作用是相同的。
运算符在前的,把操作数运算之后的结果作为表达式的值
运算符在后的,把操作数没有运算之前的值作为表达式的值
运算符 | 含义 | 操作数个数 | 操作数要求的类型 | 表达式的值的类型 | 是否有副作用 |
---|---|---|---|---|---|
> | 大于 | 2 | number / string | boolean | 否 |
>= | 大于等于 | 2 | number / string | boolean | 否 |
< | 小于 | 2 | number / string | boolean | 否 |
<= | 小于等于 | 2 | number / string | boolean | 否 |
== | 相等 | 2 | number / string | boolean | 否 |
!= | 不相等 | 2 | number / string | boolean | 否 |
=== | 全等 | 2 | 没有要求 | boolean | 否 |
!== | 不全等 | 2 | 没有要求 | boolean | 否 |
1. 字符串比较
如果进行比大小或者相等的时候,两个操作数都是字符串,会按照字符串的规则进行比较。
比大小:字符串会一个字符一个字符按照对应的ascii码进行比较。
比相等:两个字符串完全一致就相等。
2. == 和 === 的区别:
相等(==): 会对操作数进行自动数据类型转换
全等(===):不会对操作数进行数据类型转换,如果两个操作数类型不同,直接返回 false (建议使用)
使用 == 进行判断运算,操作数中如果由 null,出现特殊情况:
- null 和 0 不等
- null 和 false 不等
- null 和 空字符串 不等
- null 和 undefined 相等
运算符 | 含义 | 操作数个数 | 操作数类型 | 表达式值的类型 | 是否有副作用 |
---|---|---|---|---|---|
&& | 逻辑与 | 2 | 无要求 | 其中一个操作数作为表达式的值 | 无 |
|| | 逻辑或 | 2 | 无要求 | 其中一个操作数作为表达式的值 | 无 |
逻辑与组成的表达式的值计算规则:
- 如果第一个操作数成立,取第二个操作数作为整个表达式的值。
- 如果第一个操作数不成立,取第一个操作数作为整个表达式的值。
逻辑或组成的表达式的值计算规则:
- 如果第一个操作数成立,取第一个操作数作为表达式的值。
- 如果第一个操作数不成立,取第二个操作数作为表达式的值。
运算符 | 含义 | 操作数的个数 | 操作数的数据类型 | 表达式的值的数据类型 | 是否有副作用 |
---|---|---|---|---|---|
= | 赋值 | 2 | 没有要求 | 变量的值作为表达式的值 | 有 |
+= | 赋值求和 | 2 | number | 变量的值作为表达式的值 | 有 |
-= | 赋值求差 | 2 | number | 变量的值作为表达式的值 | 有 |
*= | 赋值求积 | 2 | number | 变量的值作为表达式的值 | 有 |
/= | 赋值求商 | 2 | number | 变量的值作为表达式的值 | 有 |
%= | 赋值取余 | 2 | number | 变量的值作为表达式的值 | 有 |
+= | 赋值连接字符串 | 2 | string | 变量的值作为表达式的值 | 有 |
注意:
- 赋值运算符左边的操作数必须是个变量。
- 赋值运算符更看重的是副作用
运算符 | 含义 | 操作数的个数 | 操作数的数据类型 | 表达式的值的数据类型 | 是否有副作用 |
---|---|---|---|---|---|
+ | 字符串连接符 | 2 | string | string | 没有 |
typeof | 类型判断 | 1 | 没有要求 | string | 没有 |
, | 逗号运算符 | 2 | 没有要求 | 最后一组操作数作为表达式的值 | 没有 |
?: | 比较运算符 | 3 | 第一操作数要求布尔值 后两个操作数没有于要求 | 如果第一个操作数成立,操作数2作为表达式的值,否则操作数3作为表达式的值 | 没有 |
最高: 一元运算
中间: 算符运算符 > 关系运算符
三低: 逻辑运算符 > 三元运算符 > 赋值运算符
使用 () 提高优先级
if (条件表达式) {
语句;
语句;
}
if (条件表达式) {
语句;
语句;
} else {
语句;
语句;
}
if (条件表达式) {
语句;
} else if (条件表达式) {
语句;
} else if (条件表达式) {
语句;
} else if (条件表达式) {
语句;
} else {
语句;
}
switch (表达式) {
case 表达式可能的值:
语句;
语句;
break;
case 表达式可能的值: 语句; break;
case 表达式可能的值: 语句; break;
case 表达式可能的值: 语句; break;
case 表达式可能的值: 语句; break;
default: 语句;
}
break 的作用:
进入到 case 之后,执行语句,遇到 break 才停止,如果没有break会继续执行下面的 case,直到碰到 break。
if (条件表达式) {
if (条件表达式) {
}
} else {
switch (表达式) {
case ...
}
}
while (条件表达式) {
语句;
}
- 条件表达式不能永远成立,否则就会成为死循环。
- 随着循环次数的增加,条件表达式要越来越趋近于不成立。
do {
语句;
} while (条件表达式)
相对于 while,do … while 只有第一次没有判断就执行了循环里的语句,以后与 while 一样都是先判断才执行。
for (循环标记变量初始化; 条件表达式; 循环标记变量的变化) {
语句;
}
循环标记变量的变化 每次循环都会执行,且在大括号中的语句都执行完毕后才执行
[100, 200, 300, 400, 'hello', [1,2,3,4,5]];
[30];
Array(100,200,300,400);
Array('hello'); // 数组只有一个元素,值是 hello
Array(20); // 表示数组的长度是 20(元素的个数)
读写数组的元素,使用元素的索引,配合 [] 读写操作
arr[2]; // 读取数组中索引是 2 的元素
arr[3] = 100; // 给数组中索引是 3 的元素重新赋值
所有的数组都有属性,length, 通过length 可以获取数组的长度(元素的个数)
arr.length; // 读取数组的长度
// length 是可以修改的,修改 length 可能会造成数组元素被截取
for (var i = 0; i < arr.length; i ++) {
i; // 数组的元素的索引
arr[i]; // 数组的元素的值
}
for (var i in arr) {
i; // 数组的元素的索引
arr[i]; // 数组的元素的值
}
1. 指定数组的索引,添加元素;要求索引必须是数组的下一个索引
2. 让数组当前的长度作为数组的下一个索引 arr[arr.length] = '元素的值'
3. 在数组的后面追加元素 arr.push(元素); arr.push(元素1,元素2 ....);
4. 在数组的前面添加元素 arr.unshift(元素); arry.unshift(元素1,元素2 ....)
5. 在指定的位置插入新元素 arr.splice(新元素的位置, 0, 新元素);
arr.splice(新元素的位置, 0, 新元素1, 新元素2 ....);
1. 通过设置数组 length 的值实现删除数组元素的目的。 arr.length -= 2; // 删除后两个元素
2. 删除数组的最后一个元素。 arr.pop()
3. 删除数组的第一个元素。 arr.shift0
4. 删除指定位置指定数量的元素。 arr.splice(位置, 数量);
如果数组的元素还是个数组,这样的数组就是多维数组!
function函数名([参数]){
函数体
}
var 函数名=function([函数]){
函数体
}
函数名()才是函数的调用,只有调用被调用了,函数体才会执行
函数调用称之为“函数调用表达式”,表达式的值就是函数的返回值
函数名不加(),是在引用函数本身,本质上在使用一个变量
1.返回值作为函数调用表达式的值
2.在函数体内,return的右边写个表达式,该表达式就是函数的返回值
3.在函数体内,没有写return函数默认返回值则是undefined
4.如果return右边什么都不写,函数默认值是undefined
5.return可以终止函数的执行,return语句执行之后,函数体内后面的代码不会执行
什么样的函数需要写返回值?
如果函数是进行某种计算的,通常会把计算的结果作为函数的返回值
如果函数进行某个功能操作,没有计算结果,一般不需要返回值
系统定义的函数:
Number() 返回转成 number 了的数据
String() 返回转成 string 了的数据
Boolean() 返回转成 boolean 了的数据
parseInt() 有返回值
parseFloat() 有返回值
isNaN() 有返回值
isFinite() 有返回值
typeof() 有返回值
形参:在声明函数的时候,设置的参数就是形参;形参相当于没有赋值的变量(仅限函数内使用),参数命名规范同变量
实参:在调用函数时,给的值就是实参;实参作为形参的值
1.正常情况,实参数量=形参数量
2如果实参数量>形参数量,多余的实参没有任何作用
3.如果实参数量<形参数量,靠后的形参没有被赋值默认取undefined
JS函数中,可以给形参设置默认值,有默认值的参数称之为可选参数。
在函数调用的时候,可以不给有默认值的形参赋值,形参取默认值;如果调用的时候对有默认值的形参赋值了,就取调用时赋的值。
设置参数默认值,旧语法(ES5之前的)
function 函数名(a, b) {
// 如果 参数b 的值是 undefined,说明调用函数的时候没有给 b 赋值
if (b === undefiend) {
b = '默认值'
}
}
设置参数默认值,新版语法:
function 函数名(a, b='默认值') {
}
注意:
可选参数(有默认值的参数)一定要写在后面。
arguments 是一个类数组对象(伪数组)。
argument 能够得到调用该函数时所有的实参,每个参数都会作为 arguments 内部的元素
arguments 可以用于声明可变参数数量的函数。
1.作用域就是变量的可作用范围
2.函数可以产生作用域,函数内部定义的变量,只能在函数内可以使用
局部:在函数内声明的变量,作用域仅限于所在的函数是局部的。这样的变量称之为局部变量
全局:在函数外声明的变量,作用域是全局,任何地方都可以用。这样的变量称之为全局变量
注意
1.函数内参数本质是局部变量,作用域是所在函数
2.在函数内不使用var声明的变量是全局变量(不建议使用)
什么是作用域链?
函数的嵌套形成作用域链
在使用变量的时候,会沿着作用域链向上找
变量的查找过程:
1.先从本作用域查找该变量是否定义,如果定义过直接使用
2.如果本作用域没有定义要使用的变量,去上层作用域查找;从哪里找到从哪里停止如果到全局也没有则报错
注意: 作用域只与函数的声明的位置有关,与函数调用的位置无关
1. 程序在正式执行之前,会进行预解析;
2. 在预解析的时候,会进行变量的提升; 只提升变量的声明,变量的值不会提升。
3. 变量提升提升到本作用域的最前面。
如果在变量声明的代码之前,使用变量,得到 undefined
1. function 关键字方式声明的函数,除了声明提升值也提升。可以在函数声明代码之前调用函数。
2. 函数名与变量名如果冲突,优先提升函数名。
3. 表达式方式声明的函数与普通变量提升的规则是一致的。
没有名字的函数 用途1用于自调用函数2回调函数
函数声明完就立即调用
特点:自调用函数一般用于匿名函数也可以进行传参也可以是有名字的函数作为自调函数
用途:模块划分,避免全局变量污染
注意:连续两个自调用函数一前一后解决方案
1给第一个自调用函数后面加分号
2.给第二个自调用函数前面加叹号
三个条件:我定义的,我没有调用,函数被执行了
事件
定时器
ajax请求
生命周期钩子
一般来说,回调函数通常作为其他函数的参数
一个函数的内部如果又调用了自己,称作是函数的递归调用,这样的函数就是递归函数。
1)必须有一个明显的结束条件。
2)必须有一个趋近于结束条件的趋势。
1)函数递归调用很容易发生灾难(内存泄漏)而调用失败。
2)函数递归调用效率不高,能不用就不用。
后端的操作中有些场景必须要递归函数来完成,如:
1)删除文件夹以及里面的内容,需要递归删除(操作系统的原始接口只能删除文件和空文件夹)
2)复制文件夹以及里面的内容。
3)剪切文件夹以及里面的内容。
{
name: '安妮',
age: 19,
'user-grade': 100,
say: function(){
},
sleep: function(){
}
}
var obj = new Object(); // 声明空的对象
obj.name = '安妮';
obj.say = function(){
}
. 语法 obj.name; obj.say()
[] 语法 obj['name'] obj['say']();
1. 属性名不符合标识符命名规范。
2. 用变量来表示属性名。
1. 读取对象中不存在的属性,返回 undefined
2. 给对象属性设置值的时候,如果属性存在就修改值,如果属性不存在,添加该属性。
for(var i in obj){
console.log(i,obj[i]);
}
delete 对象.属性名 delete 对象[‘属性名’]
'属性名'in 对象;//返回值
true表示该属性存在
构造函数就是对对象的描述(js中相同数据类型的构造函数一样)
对象是构造函数的实例,构造函数就是对对象的描述
对象都有构造函数,一个对象对应一个构造函数构造函数对应多个对象
对象instanceof构造函数;//返回布尔值
注:原始类型(字符串,number,布尔)使用instanceof判断返回false
所有的对象都有constructor属性,返回对象的构造函数对原始类型的数据调用constructor属性时,原始类型切换为对象类型
function User(name, age, address) {
// 设置属性
this.name = name;
this.age = age;
this.address = address;
// 设置方法
this.login = function(){
console.log('我是 ' + this.name + ', 我今年' + this.age + '岁了,我来自' + this.address + ',啊,我登录了');
}
this.logout = function(){
this.login();
console.log('啊,我退出登录了!');
}
}
new 构造函数();
没实例化一次,就会产生一个新的对象
this 指向构造函数所生成的对象。
谁调用指向谁!
如果函数的前面没有
对象.
,就是 window 在调用该方法!
原型也是一个对象
所有的对象都有一个原型,对象可以从原型上继承属性和方法
对象.__proto__
对象的构造函数.prototype
对象是构造函数的实例,构造函数是对象的描述。
对象可以从原型上继承属性和方法
对象可以通过它的构造函数来获取原型
构造函数相同的对象,原型也相同。
// 自定义构造函数
function User(name, age, address) {
// 属性
this.name = name;
this.age = age;
this.address = address;
}
// 把方法添加到实例的原型上
User.prototype.login = function(){
console.log(this.name + ' 登录了');
}
User.prototype.logout = function() {
console.log(this.name + ' 退出登录了');
}
自定义构造函数的时候,通常通过 this 对象设置属性,方法添加到原型上; 得到实例之后,属性会存储在对象本身上,方法存储在原型对象上。
一般,相同类型的对象属性的值往往是不同的,但是方法的语句是一致的。
这么做可以减少内存存储空间。
对象.hasOwnProperty('属性名'); // 返回布尔值
/*
如果属性是在对象本身上的,返回true
如果属性不在对象本身上(不论在原型上还是原型上没有),返回 false
*/
Object.create(对象); // 返回一个新的对象, 参数会作为新对象的原型
Object.create(null); // 返回一个没有原型的对象,真正意义上的空对象
任何对象都有原型对象,原型还是一个对象,既然是一个对象就会有自己的原型,那原型的原型仍然还有原型,可以依次向上找原型,直到找到一个没有原型的对象。这样就形成了一条原型链。
原型链 描述的就是是对象查找属性或者方法的过程。
属性的查找会遵循如下过程:
1)对象在查找找属性的时候,先从自身去找看有没有这个属性,如果有,直接使用这个属性的值。
2)如果没有,会沿着原型链向上找,如果找到就使用这个属性的值且停止查找,如果没找到继续向上找直到原型链的终点。
3)如果找到原型链的终点还没有找到,就返回undefined(代表已经找到顶了)
Function.__proto__ === Function.prototype
;[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zl3tQe7Y-1604558343644)(C:\Users\Admin\Desktop\原型链和构造函数.png)]
原始类型就是值类型,也可以称为不可变类型。
对象类型就是引用类型,也可以称为可变类型。
**值类型: ** 变量名和数据都存储在栈区域内。
引用类型: 栈中存储的是变量名和地址,真正的数据在堆里。
**不可变类型:**原始类型(值类型),整个数据就是一个整体,无法修改其中的一部分。
**可变类型:**对象类型(引用类型),由很多属性组成,可以修改其中的属性,修改了对象的属性,对象还是原来的对象。
// 第一种 直接量方式
var b1 = true;
// 第二种 Boolean 函数
var b2 = Boolean(true);
// 第三种 Boolean 构造函数方式
var b3 = new Boolean(0);
console.log(b1, typeof b1); // true 'boolean'
console.log(b2, typeof b2); // true 'boolan'
console.log(b3, typeof b3); // false 'object' // 布尔值的对象形式
实例的属性:
实例的方法:
toFixed([n]) 保留指定位数的小数,按照四舍五入;不指定参数,取整
toString([n]) 转为字符串,可以转为几进制
构造函数本身的属性:
Number.MAX_VALUE JS中最大可表示的数字
Number.MIN_VALUE JS中最小可表示的数字
构造函数本身的方法:
实例的属性: length 字符串的长度(字符的个数) 实例的方法: indexOf(value [,fromIndex]) 返回value在字符串中第一次出现的索引位置;第二个可选参数指定从哪开始查找。 可以用来判断字符串中是否包含某个值。 lastIndexOf(value [,fromIndex]) 返回value在字符串中最后一次出现的索引位置;第二个可选参数指定从哪开始向前查找。 slice(start [,end]) 截取字符串,第一个参数开始截取的位置,第二个参数结束的索引,不指定第二个参数,截取到最后; 截取规则:顾头不顾尾 substring(start [,end]) 同 slice。 substr(start [,length]) 截取字符串,第一个参数是开始索引,第二个是截取长度;不指定第二个参数,截取到最后。 split([sep]) 把字符串分割为数组;可以指定分隔符。 toUpperCase() 把字符串转为大写 toLowerCase() 把字符串转为小写 构造函数本身的属性: 构造函数本身的方法: String.formCharcode(编码)指定返回Unicode编码对应的字符
(本身)方法 Math.abs()取绝对值
Math.sqrt()取平方根
Math.pow(n,m)幂运算N的M次方
Math.Max()取所有参数的最大值
Math.Min()取所有参数的最小值
Math.round()四舍五入取整
Math.floor()舍1取整
Math.ceil进一取整
Math.random()取随机数 返回0到1 的小数 (顾头不顾尾)
随机取0~16 Math.floor(Math.random()*15);
var today = new Date();
var birthday = new Date('December 17, 1995 03:24:00');
var birthday = new Date('1995-12-17T03:24:00');
var birthday = new Date(1995, 11, 17);
var birthday = new Date(1995, 11, 17, 3, 24, 0);
实例的方法: getFullYear()年 getMonth()月 返回的值时0~11 getDate()日 getDay()星期几 getHours()小时 getMinutes()分钟 getSeconds()秒 getMilliseconds()毫秒 getUTC...获取标准时区的日期和时间 set... 设置日期和时间 setUTC... 设置标准时区日期和时间 getTime() 返回时间戳 setTime() 根据时间戳设置日期时间 构造函数本身的方法: Date.now() 返回此时此刻的时间戳 ate.UTC(year,month[,date[,hrs[,min[,sec[,ms]]]]]) 返回指定日期的时间戳
注意:
给参数的时候,月份的数字范围 0~11, Date 构造函数 和 Date.UTC()
实例的属性: length 数组的长度 实例的方法: 修改器方法:(可以修改调用方法的对象) pop() 删除最后一个元素 push() 在最后面添加元素 shift() 删除第一个元素 unshift() 在最前面添加运算 splice() 添加、删除、替换元素 sort() 数组排序 reverse() 数组翻转 访问方法: (不会修改调用方法的对象本身,计算结果已返回值的形式得到) concat() 连接数组 slice(start [,end]) 截取数组,指定开始索引和结束索引,顾头不顾尾 join([sep]) 把数组合并成字符串,可以指定分隔符,不指定默认逗号。是字符串split方法的逆运算 ES5方法 forEach() 用于遍历数组 filter() 过滤数组;回调函数返回布尔值,filter返回过滤后的新数组 map() 返回回调函数的返回值组成的数组 every() 每一个都要满足条件; 只有所有回调函数返回true,every才返回true some() 只要有一个满足条件; 只要一个回调函数返回true,some就返回true reduce() 用于累计运算, 回调函数第一个参数接收上一个回调函数的返回值 reduceRight() 用于累计运算,从后向前运算, 回调函数第一个参数接收上一个回调函数的返回值 indexOf() 返回指定元素在数组中第一次出现的位置 lastIndexOf() 返回指定元素在数组中最后一次出现的位置
实例的属性
length 返回函数必须的参数的数量
实例的方法
call() 调用函数并设置函数内this的指向, 参数数量不固定(至少一个)
apply() 调用函数并设置函数内this的指向,参数数量两个
bind() 设置函数内this的指向,把修改了this指向的函数返回;参数形式同call
方法:
JSON.parse() 把 json 格式的字符串解析为数组或对象
JSON.stringify() 把对象或数组转为json格式的字符串
方法:
parseInt(str [,进制]) 从字符串中提取数字,可以指定数字的进制
parseFloat(str [,进制]) 从字符串中提取数字,可以指定数字的进制
属性: name 获取或设置窗口的名字 window.innerWidth 获取视口的宽度 window.innerHeight 获取视口的高度 history location navigator screen 方法: alert() 警告框 confirm() 确认框 返回布尔值 prompt() 输入框 返回输入的内容 window.open() 打开新窗口 window.close() 关闭窗口 window.print() 调用打印程序 scrollTo() 滚动到页面指定的位置 scrollBy() 滚动多少距离 setInterval() 开启定时器(多次定时) clearInterval() 清除定时器 setTimeout() 开启定时器(单次定时) clearTimeout() 清除单次定时器
属性:
length 当前窗口中历史记录的个数
方法:
back() 后退一步
forward() 前进一步
go(n) 前进/后退 n 步;n 是负数表示后退
属性:
href 完整的URL
protocol 协议部分
host 主机名+端口号
hostnmae 主机名
port 端口号
path 路径部分
search 查询字符串
hash 锚点部分
方法
reload() 重新加载
assign(url) 页面跳转,就业面会存在历史记录中
replace(url) 页面跳转;旧页面会在历史记录中抹除
属性:
userAgent 获取客户端信息
属性:
width 屏幕的宽度
height 屏幕的高度
**MDN 文档对象模型手册:**https://developer.mozilla.org/zh-CN/docs/Web/API/Document_Object_Model
document 文档对象节点
element 元素节点
attribute 属性节点
text 文本节点
comment 注释节点
nodeName 节点名 元素节点的nodeName返回标签名
nodeValue 节点值
nodeType 节点类型 document:9; element:1; attribute:2; text:3; comment:8
document.getElementById('id名');
// 返回元素对象
// 获取不到元素,返回 null
// 元素 id 名由重复的,只获取第一个
document.getElementsByTagName('标签名');
element.getElementsByTagName('标签名');
// 返回 HTMLCollection 对象,由元素对象组成的一个伪数组
// 获取不到元素,返回空的 HTMLCollection 对象
document.getElementsByClassName('类名');
element.getElementsByClassName('类名');
// 返回 HTMLCollection 对象,由元素对象组成的一个伪数组
// 获取不到元素,返回空的 HTMLCollection 对象
document.getElementsByName('name属性值');
// 返回 NodeList 对象,由元素对象组成的一个伪数组
// 获取不到元素,返回空的 NodeList 对象
document.querySelector('选择器');
element.querySelector('选择器');
// 返回的是元素对象,获取不到返回 null
document.querySelectorAll('选择器');
element.querySelectorAll('选择器');
// 返回 NodeList 对象, 获取不到返回空的 NodeList 对象
需要 IE8 以上浏览器,如果兼容性要求高,可有使用 getElementById() 和 getElementsByTagName()
document.all; // 获取 HTMLCollection 对象,由文档中所有元素组成的伪数组
document.all 作为语法糖,判断IE还是非IE
if (document.all) { document.write('我是 IE 浏览器!'); } else { document.write('我不是 IE 浏览器!'); }
- 1
- 2
- 3
- 4
- 5
childNodes 获取所有的子节点,返回 NodeList 对象
firstChild 获取第一个子节点
lastChild 获取最后一个子节点
parentNode 获取父节点
previousSibling 获取上一个兄弟节点
nextSibling 获取下一个兄弟节点
children 获取所有子元素,返回 HTMLCollection 对象
firstElementChild 获取第一个子元素
lastElementChild 获取最后一个子元素
parentElement 获取父元素
previousElementSibling 获取上一个兄弟元素
nextElementSibling 获取下一个兄弟元素
element.属性名; // 赋值或者读取都可以
- 可能会对代码中写的值进行处理,如 img 元素的 src 属性
- 如 checked、selected、disabled 这样的属性,是布尔值
element.dataset.属性名; // 赋值或者读取都可以
属性名指的是 - 后面的部分
element.getAttribute('属性名')
element.setAttribute('属性名', '值')
这种方式实际上是操作写在代码中标签上的属性,不会区分内置属性还是自定义属性
3 DOM 操作 - 操作元素的样式
element.style.属性名; // 读写操作都可以
作用在元素上的 css 属性映射到 element.style 对象中
CSS 属性名中有 - 的,转为小驼峰的形式
使用 element.style 方式读取某个 css 属性值的时候,css 属性必须是设置在 行内
使用 element.style 方法设置某个 css 属性的值,直接设置在行内
计算样式: 所有作用在元素上的 css 样式,不论在哪里设置的,称之为计算样式!
// IE9 以及以上 和 其他浏览器
getComputedStyle(元素对象) // 返回一个对象,包含所有作用在该元素上的css样式
// IE8 以及以下
元素对象.currentStyle.属性名
// 定义函数获取元素计算样式
function getStyle(ele, attr) {
if (window.getComputedStyle) {
// IE9+ 或 其他浏览器
return getComputedStyle(ele)[attr];
} else {
// IE8 -
return ele.currentStyle[attr];
}
}
element.className 可以设置或读取标签中的 class 属性
element.classList 是一个类名列表对象
方法:
add() 添加一个类名 (原先的类名还在)
remove() 删除指定的类名
toggle() 切换类名(没有类名添加,有类名删除)
需要 IE9 +
把元素内的 html 代码都作为内容:
innerHTML
outerHTML
只把文本作为元素的内容:
innerText
textContent
只有双标签元素才能有文本内容!
offsetWidth / offsetHeight 内容+内边距+边框
clientWidth / clientHeight 内容+内边距
scrollWidth / scrollHeight 内容溢出,考虑溢出内容的宽度;如果内容不溢出同 client 系列一致。
getBoundingClientRect() 返回对象,对象中有 width 和 height 属性,值同 offset 系列一致。
获取视口的尺寸:
window.innerWidth
window.innerHeight
document.documentElement.clientWidth
document.documentElement.clientHeight
// 二者区别
1. 如果窗口没有滚动条,二者获取的结果一致
2. 如果出现了滚动条, window 系列会加上滚动条的宽度/高度; documentElement 系列不计算滚动条
获取整个页面的高度:
document.body.scrollHeight
或者
document.documentElement.scrollHeight
document.createElement('tagName');
parentElement.appendChild(node); // 追加子节点
parentElement.insertBefore(newNode, oldNode); // 在指定位置添加子节点,newNode 会在 oldNode 的前面
parentElment.removeChild(node); // 参数是要删除的节点
parentElement.replaceChild(newNode, oldNode); // newNode 会把 oldNode 替换掉
cloneNode() 节点克隆,参数 默认是 false 表示浅克隆, 设置为 true 表示深克隆(推荐)
属性:
document.documentElement 快速获取 html 元素 只读
document.body 快速获取 body 元素 只读
document.head 快速获取 head 元素 只读
document.all 获取所有的元素组成的集合 只读
document.referrer 获取历史记录中上一个页眉 只读
document.lastModified 获取页面最后一次修改时间 只读
document.title 页面标题 可读可写
方法:
document.write()
1. documentFragment 对象也是一种节点, nodeType 值是 11
2. 不会作为 dom 结构一部分,不会在页面中渲染
3. 通常用来作为元素的临时容器
document.createDocumentFragment()
1. 优化,同时添加多个元素; 可以先把元素添加到 df 对象中,最后统一添加到 dom 结构中
2. 实现一组元素顺序反转
方法:
submit(); 调用该方法可以让表单提交
reset(); 调用该方法可以让表单重置
方法:
focus() 调用该方法可以获取焦点
blur() 调用该方法可以失去焦点
select() 可以选中里面的文字
属性:
options 所有 option 的集合
selectedIndex 当前选中的选项的索引
方法:
add() 添加选项,参数是要添加的option对象
remove() 删除选项,指定要删除选项的索引
blur()
focus()
创建 option 元素:
new Option('中间的文本内容', ‘value 值’);
属性:
rows 返回所有行元素的集合
cells 返回所有单元格元素的集合
方法:
insertRow() 向表格中添加一行,指定新行的索引,返回新添加的行元素
deleteRow() 从表格中删除一行,指定索引;
属性:
cells 返回该行中所有单元格元素的集合
rowIndex 返回当前行的索引
方法:
insertCell() 添加一个单元格,需要指定索引; 返回新的单元格元素
deleteCell() 删除一个单元格,需要指定索引;
属性:
cellIndex 返回单元格在行内的索引
<button onclick="代码..."></button>
// ① 获取元素对象
btn.onclick = function(){
}
btn.addEventListener('click', 回调函数);
可以给一个元素添加多个相同的事件
// 重新给元素绑定事件,覆盖前面
btn.onclick = null;
btn.removeEventListener('click', 回调函数名)
注意: 事件如果以后需要解除绑定,在添加事件的时候,回调函数就不要使用匿名函数。
事件的触发过程分为三个节点: 捕获阶段、目标阶段、冒泡阶段。
事件默认在冒泡阶段触发,addEventListenre 第三个参数设置为 true,事件会在捕获阶段触发。
目标元素指的是具体发生了事件的元素,不能再细分了。
当发生了事件之后,先从 window 开始,到 document 一层一层的向下寻找目标元素,这个过程称之为捕获阶段
找到目标元素,称之为目标阶段,目标阶段是捕获阶段的结束
找到目标元素之后开始冒泡,从目标元素开始一直到window,一层一层的冒泡,称之为冒泡阶段
this 指向绑定事件的元素
click 单击
dblclick 双击
contextmenu 右击
mousedown 鼠标按键按下
mouseup 鼠标按键抬起
mousemove 鼠标在元素上移动
mouseover 鼠标悬停在元素上
mouseout 鼠标离开元素
mouseenter 鼠标悬停在元素上,代替 mouseover (推荐)
mouseleave 鼠标离开元素,代替 mouseout (推荐)
keydown 键盘按键按下
keyup 键盘按键抬起
keypress 键盘按键按下,控制按键无法触发,只有可输入字符按键可以触发。
keydown 和 keyup 任何一个按键都可以触发,字母按键是无法区分大小写
keypress 只有可输入字符按键能触发,且能区分大小写
load 文档中所有的一切加载完毕
unload 文档关闭
beforeunload 文档关闭之前,用来实现窗口关闭的时候确认是否关闭
DOMContentLoaded 文档加载完毕,用来替换 load 事件的; 页面中所有的元素加载完毕就触发; 建议使用
window.onbeforeunload = function(){
return '您确定要关闭吗?';
}
文档事件通常绑定给 window
load 事件和 DOMContentLoaded 事件的区别:
① load 事件三种绑定方式都可以绑定;DOMContentLoaded 事件只能使用 addEventListener 绑定
② load 等到页面中所有的一切(包括外部的图片文件、视频文件等)加载完毕才触发; DOMContentLoaded 只要页面中的元素加载完毕就触发。
submit 表单提交的时候,绑定给 form 元素
reset 表单重置的时候,绑定给 form 元素
blur 失去焦点,绑定给表单控件元素
focus 获取焦点,绑定给表单控件元素
select 文本被选中,绑定给可输入元素
change 对于输入框元素,内容改变并且失去焦点才会触发; 对于复选框、单选按钮、下拉选项,只有修改就触发
load 图片文件加载完毕
error 图片加载错误
abort 图片加载中断(了解)
resize 视口大小发生变化触发事件,绑定给 window
scroll 元素中的内容发生滚动就可以触发事件; 监听整个页面内容滚动绑定给 window
获取页面内容滚动了多少:
document.documentElement.scrollTop || document.body.scrollTop;
事件的回调函数自动获取形参,可以得到event事件
clientX/clientY 获取鼠标在视口上的位置
pageX/pageY 获取鼠标在页面(根元素)上的位置
scrennX/screenY 获取鼠标在屏幕上的位置
offsetX/offsetY获取鼠标在目标元素上的位置
button 获取鼠标的按键 : 0:左键 1:滚轮键 2:右键
keyCode 获取按键的ascii值(数字)
which 同keycode
key 获取按键的值 (字符串)
type 获取事件的类型(事件的名字)
timestamp获取触发事件的时刻与打开页面的时刻相距的毫秒数
target 获取目标元素
stopPropagation()阻止冒泡
preventDefault()阻止浏览器默认行为
所有的元素右击默认出现系统菜单
超连接点击默认会跳转
提交按钮和重置按钮点击默认触发表单的提交和重置
表单与元素默认有提交行为和重置行为
在事件的回调函数内;
event.preventDefault()或者return false
事件委托:把某个元素的事件,委托到其他元素上(通常是祖先元素)
实现方式:
把事件添加到元素的祖先元素上,触发事件的时候,判断目标元素是否是我们要监听事件的元素,如果是就执行相关操作,否则什么都不干
//如果目标元素是li,执行相关操作
if(event.target.nodeName.toUpperCase()==='LI'){
//切换active类名
event.target.classListtoggle('active');
}
事件委托的优势:
①减少内存消耗;如果需要给很多元素添加某个事件,可以委托到他们共同的祖先元素上
②让动态的添加元素也有事件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sCRAaJbh-1604558343647)(G:/SH200910SH/02阶段_JavaScript/Day17/图例/01-元素对象原型链.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2lE1TfbZ-1604558343649)(G:/SH200910SH/02阶段_JavaScript/Day17/图例/02-事件对象原型链.png)]
1. null 和 undefined 区别?
undefined 表示变量没有赋值
null 变量有值,值是 null
2. 什么时候得到的是 undefined
① 定义变量,没有赋值
② 使用对象中不存在的属性
③ 函数中的形参没有对应的实参
④ 函数没有返回值
3. 什么时候得到是 null
① 定义变量或对象中的属性,暂时不知道赋什么值,可以先赋值为 null
② dom中,获取元素对象的时候,如果没有满足条件的元素,得到就是 null
1. 什么是垃圾对象(数据) 对象(数据)没有被引用,就是垃圾 2. 垃圾回收 清除掉垃圾对象,就是垃圾回收 JS/Java/Python/php 等自动垃圾回收 C/C++手动垃圾回收 3. 内存泄漏 如果内存中的垃圾对象没有被及时回收,就会常驻内存;长时间会造成内存存储空间不足,导致数据泄漏。 4. 垃圾回收的常见算法 引用计数 老版本IE 标记清除 新版本IE和其他浏览器 5. JS中变量的生命周期 全局变量,所有代码执行完毕,会被清除。 局部变量,函数调用结束,会被清除。
引用计数的原理:
每个对象都有一个标记来记录引用次数,初始值是0
一个对象如果被引用(被变量或者属性),引用标记 +1;每被引用一次,引用标记就 +1
如果取消对该对象的引用(变量或属性被销毁或者被该值),引用标记 -1
当对象的引用标记为 0 的时候,说明没有人引用该对象,该对象会被回收
优缺点:
-优点: 垃圾对象回收得比较及时
-缺点: 对象如果互相引用,会造成内存泄漏
原理:
系统定时执行标记清除操作;
每次执行标记清除操作的时候,分为两个阶段:
标记阶段:从跟对象通过属性向下查找,一层一层查找,能被指向的对象称之为可到达对象,可到达对象被添加一个标记,表示可以被引用。
清除阶段:遍历内存中所有的对象,没有标记的对象都会被清除。 清除结束后,会重置标记,为了下一次的标记清除。
优缺点:
-优点: 相对于引用计数,不会造成内存泄漏
-缺点: 需要深度递归,计算量大;定时进行标记清除,垃圾对象不会被立即回收。
1. 在执行全局代码之前,确定 window 为全局执行上下文
2. 全局执行上下文进行预处理操作
全局变量提升,全局变量添加为 window(全局执行上下文) 的属性,值是 undefined
全局函数提升,全局函数添加为 window(全局执行上下文) 的方法。
设置 this 的指向 window (全局执行上下文)
3. 正式执行全局代码
1. 当调用函数的时候,创建一个函数内的执行上下文对象
2. 执行上下文对象进行预处理
给形参赋值,形参添加为执行上下文对象的属性
给arguments 赋值,argument 添加为执行上下文对象的属性
局部变量提升,添加为执行上下文对象的属性,值是 undefined
局部的函数提升,添加为执行上下文对象的方法
设置 this 指向调用该函数的对象
3. 执行函数体内的语句
注意:
- 函数每调用一次,就会在函数内创建一个执行上下文对象。 函数如果被调用多次,每次产生的局部变量各自属于各自的执行上下文对象。
- JS 没有提供获取函数内执行上下文对象的方式,但是该执行上下文对象是确实存在。
JS 引擎在开始执行 js 脚本的时候,首先会创建一个执行栈,也叫调用栈,用来存储执行过程中产生的执行上下文对象。
栈 是一种经典的数据结构,特点是先进后出或者后进先出。
数据放入栈称之为进栈或者压栈(创建数据); 数据从栈中移除称之为出栈(销毁数据)。
JS 引擎先执行 执行栈里栈顶的上下文。
JS执行过程:
1. 在执行脚本之前先创建一个执行栈。
2. 首先创建全局执行上下文对象,并压栈;
3. 当调用函数的时候,会创建函数的执行上下文对象,并压栈。
4. 函数调用结束,函数的执行上下文对象出栈。
5. 最后执行栈只剩下全局执行上下文对象,最后才出栈。
区别:
1. 作用域是用来描述变量的特性的;变量会作为执行上下文对象的属性。
2. 变量的作用域在声明函数的时候就确定了,静态的; 在函数调用的时候会创建执行上下文对象,是动态的。
联系:
执行上下文对象也有作用域,全局执行上下文对象有全局作用域,函数内的执行上下文对象有局部作用域
某个函数中可以使用其他函数作用域内的变量
在函数B的外部调用函数A,但是函数A中可以使用函数B作用域内的变量,就产生闭包
1. 声明函数B,在函数B的内部再声明一函数A; 函数B嵌套着函数A
2. 函数A要使用函数B作用域内的变量
3. 在函数B中把函数A返回
或者
把函数A作为一个回调函数被使用(通常作为事件或定时器的回调函数)
// 1. 声明函数B,在函数B的内部再声明一函数A; 函数B嵌套着函数A function B(){ var x = 100; var y = 200; function A(){ // 2. 函数A要使用函数B作用域内的变量 console.log(x + y); } // 3. 在函数B中把函数A返回 return A; } var f = B(); f(); // 在函数B的外部调用函数f,可以使用函数B作用域内的x和y
1. 调用函数B,返回值值赋值给了 f,调用了 f。
2. 执行 f 函数体内的语句, f 指向的是函数 A,函数体内使用了变量 x 和 变量 y
3. 本作用域下并没有声明变量 x 和 y,根据作用域链的规则,读取上层作用域中的变量 x 和 y(函数 B 的作用域内)
作用域只与函数声明的位置有关系!与函数调用位置无关!
1. 函数函数B,函数B调用结束之后,检查局部变量 x、y 和 A 是否还被引用,如果没有被引用,就销毁
2. A 被返回,赋值给了 f,而 A 的内部又引用了 x 和 y,所以虽然函数B调用结束了,但是变量x、y和函数A都没有被销毁
3. 等到变量 f 被销毁,变量x、y和函数A才会失去引用被清除
闭包延长了局部变量的生命周期!
缺点:
导致局部变量常驻内存,有内存泄漏的风险
解决方式:
1. 能不闭包就不闭包
2. 不要多次引用
3. 必要时可以手动解除引用关系,赋值为 null
利用闭包实现JS模块
1. 把实现某个功能所有的代码封装成一个模块
2. 把代码全部写入一个自调用函数,不对外暴露
3. 模块还需要对外暴露一个方法(全局变量)
4. 对外暴露的方式:
① 返回,使用一个全局变量接收
② 把要暴露的方法赋值给 window 的属性
new Object()
{}
function factory(name,age){
//对属性值进行处理
return {
name:name,
age:age
}
}
function Foo(){
}
new Foo()
function Foo(name,age){
this.name=name;
this.age=age;
}
Foo.portotype.say=function(){
}
//定义父类
class Animal{
public weight;
public height;
}
//定义子类
class Dog extends Animal{
public chishi;
}
//定义子类
class Cat extends Animal{
public chilaoshu;
}
d=new Dog();
c= new Cat();
1.构造函数A的实例的原型指向构造函数B的一个实例,可以说A继承了B
2.如果一个对象想要作为其他对象的原型,建议给该对象设置constructor属性,指向以他为原型的对象的构造函数
//父类 function Animal(weight,height){ this.weight =weight; this.height=height; } Animal.prototype.eat =function(){} //子类 function Person(name,weight,height){ this.name=name; //调用父类,把父类设置的属性添加到子类实例 Animal.call(this,weight,height); } //设置Person实例的原型是Animal的一个实例 Person.prototype=new Animal(); //设置Person实例的原型上的constructor属性指向Person Person.prototype.constructor=Person; Person.prototype.say=function(){}
内的执行上下文对象有局部作用域
## 4. 闭包
### 4.1 什么是闭包?
某个函数中可以使用其他函数作用域内的变量
在函数B的外部调用函数A,但是函数A中可以使用函数B作用域内的变量,就产生闭包
### 4.2 如何产生闭包
```js // 1. 声明函数B,在函数B的内部再声明一函数A; 函数B嵌套着函数A function B(){ var x = 100; var y = 200; function A(){ // 2. 函数A要使用函数B作用域内的变量 console.log(x + y); } // 3. 在函数B中把函数A返回 return A; } var f = B(); f(); // 在函数B的外部调用函数f,可以使用函数B作用域内的x和y
1. 调用函数B,返回值值赋值给了 f,调用了 f。
2. 执行 f 函数体内的语句, f 指向的是函数 A,函数体内使用了变量 x 和 变量 y
3. 本作用域下并没有声明变量 x 和 y,根据作用域链的规则,读取上层作用域中的变量 x 和 y(函数 B 的作用域内)
作用域只与函数声明的位置有关系!与函数调用位置无关!
1. 函数函数B,函数B调用结束之后,检查局部变量 x、y 和 A 是否还被引用,如果没有被引用,就销毁
2. A 被返回,赋值给了 f,而 A 的内部又引用了 x 和 y,所以虽然函数B调用结束了,但是变量x、y和函数A都没有被销毁
3. 等到变量 f 被销毁,变量x、y和函数A才会失去引用被清除
闭包延长了局部变量的生命周期!
缺点:
导致局部变量常驻内存,有内存泄漏的风险
解决方式:
1. 能不闭包就不闭包
2. 不要多次引用
3. 必要时可以手动解除引用关系,赋值为 null
利用闭包实现JS模块
1. 把实现某个功能所有的代码封装成一个模块
2. 把代码全部写入一个自调用函数,不对外暴露
3. 模块还需要对外暴露一个方法(全局变量)
4. 对外暴露的方式:
① 返回,使用一个全局变量接收
② 把要暴露的方法赋值给 window 的属性
new Object()
{}
function factory(name,age){
//对属性值进行处理
return {
name:name,
age:age
}
}
function Foo(){
}
new Foo()
function Foo(name,age){
this.name=name;
this.age=age;
}
Foo.portotype.say=function(){
}
//定义父类
class Animal{
public weight;
public height;
}
//定义子类
class Dog extends Animal{
public chishi;
}
//定义子类
class Cat extends Animal{
public chilaoshu;
}
d=new Dog();
c= new Cat();
1.构造函数A的实例的原型指向构造函数B的一个实例,可以说A继承了B
2.如果一个对象想要作为其他对象的原型,建议给该对象设置constructor属性,指向以他为原型的对象的构造函数
//父类 function Animal(weight,height){ this.weight =weight; this.height=height; } Animal.prototype.eat =function(){} //子类 function Person(name,weight,height){ this.name=name; //调用父类,把父类设置的属性添加到子类实例 Animal.call(this,weight,height); } //设置Person实例的原型是Animal的一个实例 Person.prototype=new Animal(); //设置Person实例的原型上的constructor属性指向Person Person.prototype.constructor=Person; Person.prototype.say=function(){}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。