JavaScript是一种属于网络的脚本语言,常用来为网页添加各式各样的动态功能,是一种动态类型、弱类型、基于原型的语言。它包括三个部分:ECMAScript、BOM和DOM。ECMAScript描述了该语言的语法和基本对象。BOM,浏览器对象模型,描述了与浏览器进行交互的方法和接口。DOM,文档对象模型,描述了处理网页内容的方法和接口。js的使用:js代码写在script标签中,其引入方式和css样式的style标签一致。
一、变量、数据类型与运算符
1.变量
声明变量:
- 通过var关键字声明一个或多个变量。 - 声明变量的同时可以给其赋值(直接量,字面量),也可以不赋值,不赋值时默认值为undefined。 - 变量命名遵循一般的命名规范:区分大小写,不能包含特殊字符,大小驼峰命名或下划线命名,不能以数字开头,命名含义明确等。 - 变量在内存中会自动存储于释放。
2.数据类型
js中的数据类型包括:字符串(String)、数字(Number)、布尔(Boolean)、数组(Array)、对象(Object)、空(Null)、未定义(Undefined)。
隐式转换
// 转换为布尔类型var a; // undefined.var test = function(vec){ if(vec){ console.log("true"); }else{ console.log("false"); }};a = null;a = 0; // 0值a = NaN; // NaN值a = ‘‘; // 空字符串test(a);
// 转换成数值型数据var a;// undefined -> NaNvar b = 1;a = null; // null -> 0a = false; // false -> 0a = "123"; // "12" -> 12a = "123abc"; // "123abc" -> NaNconsole.log(typeof a);console.log(b + a);
强制转换
// parseInt(string):将字符串类型转换成数值;// parseFloat(string):将字符串类型转换成浮点型数值;var a = "123";console.log(typeof parseInt(a));console.log(typeof parseFloat(a));
// String()和toString():将其它类型转换成字符串var a = 123;console.log(typeof String(a));console.log(typeof a.toString());
// Boolean:将其它数据类型转换成布尔值。;var a = undefined;console.log(Boolean(a), typeof Boolean(a));
3.运算符
1.算术运算符
+、-、*、/、%、++、--++、--分为前缀形式和后缀形式。前缀先自加(减)再执行运算,后缀先执行运算再自加(减)。
2.赋值运算符和比较运算符
=、+=、-=、*=、/=、%=、.=>、>=、<、<=、==、!=、===、!==
3.逻辑运算符
&&、||、!
4.三元运算符
// exp1?exp2:exp3var a = 1231; // var a;typeof a==="number"?console.log("true"):console.log("false");
5.运算符优先级
运算符 | 描述 |
. [] () | 字段访问、数组下标、函数调用以及表达式分组 |
++ -- - ~ ! delete new typeof void | 一元运算符、返回数据类型、对象创建、未定义值 |
* / % | 乘法、除法、取模 |
+ - + | 加法、减法、字符串连接 |
<< >> >>> | 移位 |
< <= > >= instanceof | 小于、小于等于、大于、大于等于、instanceof |
== != === !== | 等于、不等于、严格相等、非严格相等 |
& | 按位与 |
^ | 按位异或 |
| | 按位或 |
&& | 逻辑与 |
|| | 逻辑或 |
?: | 条件 |
= oP= | 赋值、运算赋值 |
, | 多重求值 |
二、流程控制
1.条件语句
// if(exp){执行代码段};var a = 123; // var a;if(typeof a === "number"){ console.log("true");}
// if(exp){exp为true的代码段}else{exp为false的代码段};var a = 123; // var a;if(typeof a === "number"){ console.log("true");}else { console.log("false");}
// if ... else if ...var readline = require("readline");var rl = readline.createInterface({ input: process.stdin, out: process.stdout,});rl.question("请输入成绩: ", (number) => { if(number > 100){ console.log("输入的成绩不能大于100!"); }else if(number > 80){ console.log("录入成功,A档"); }else if(number > 60){ console.log("录入成功,B档"); }else if(number > 0){ console.log("录入成功,C档"); }else{ console.log("输入的成绩不能小于0!") } rl.close();});rl.on("close", function () { console.log("退出程序!"); process.exit();});
var readline = require("readline"); var rl = readline.createInterface({ input: process.stdin, out: process.stdout, }); rl.question("请输入星期几: ", (day) => { switch(day){ case "1": console.log("今天吃炒面"); break; case "2": console.log("今天吃鱼香肉丝"); break; case "3": console.log("今天吃麻辣香锅盖饭"); break; case "4": console.log("今天吃豆丁胡萝卜"); break; case "5": console.log("今天公司聚餐"); break; case "6": console.log("今天吃泡面"); break; case "7": console.log("今天撸串"); break; default: console.log("input error.") } rl.close(); }); rl.on("close", function () { process.exit(); }
// switch ... case ...var readline = require("readline");var rl = readline.createInterface({ input: process.stdin, out: process.stdout,});rl.question("请输入星期几: ", (day) => { switch(day){ case "1": console.log("今天吃炒面"); break; case "2": console.log("今天吃鱼香肉丝"); break; case "3": console.log("今天吃麻辣香锅盖饭"); break; case "4": console.log("今天吃豆丁胡萝卜"); break; case "5": console.log("今天公司聚餐"); break; case "6": console.log("今天吃泡面"); break; case "7": console.log("今天撸串"); break; default: console.log("input error.") } rl.close();});rl.on("close", function () { process.exit();});
2.循环语句
for 循环
和java中的for循环一致:for(exp1; exp2; exp3){代码块;} - exp1: 无条件的执行第一个表达式 - exp2: 是判断是否能执行循环体的条件 - exp3: 增量操作
// 九九乘法表var str = "";for(var i=1;i<=9;i++){ for(var j=1;j<=i;j++){ str += i + "*" + j + "=" + i*j + " "; if(i === j){ str += "\n"; } }}console.log(str);
while 循环
var arr = function (number) { var arr_list = new Array(); // var arr_list = []; var i = 0; while (i < number){ arr_list[i] = Math.random(); i++; } return arr_list; }; console.log(arr(5))
var arr = function (number) { var arr_list = new Array(); // var arr_list = []; var i = 0; while (i < number){ arr_list[i] = Math.random(); i++; } return arr_list;};console.log(arr(5));
do ... while循环
// 和java中的do ... while 循环一致,先执行依次do内的代码块,再执行while 判断。不管while条件判断是否成功,do都会至少执行一次。var arr = function (number) { var arr_list = new Array(); // var arr_list = []; var i = 0; do { arr_list[i] = Math.random(); i++; }while (i > number); return arr_list;};console.log(arr(5));
三、函数
1.定义
函数通过function关键字定义。function 函数名称([参数1, ...]){代码块; [return 返回值]};也可以通过Function构造器定义函数。
// 通过function 关键字定义函数function hello() { console.log("hello world.")};hello();
匿名函数,即function关键字定义的无函数名称的函数。
// 通过function 关键字定义匿名函数var hello = function () { console.log("hello world.")};hello();
将匿名函数作为参数,传递给另一个函数进行执行,此时其被称为回调函数。回调函数在js中异常强大。
function calc(v1, v2, callback) { v1 = v1 || 1; v2 = v2 || 2; return callback(v1, v2);}calc(3,4, function (v1, v2) { return v1 + v2});
2.参数
函数如果定义了参数,在调用函数的时候没有传值则默认值为undefined。如果传递的参数超过了形参,js会忽略掉多于的参数值。
function calc(v1, v2){ return v1 + v2;}console.log(calc(5, 6, 7));
es5不能直接写形参的默认值,但可以通过arguments对象来实现默认值。同时,arguments对象可以实现可变参数。
function calc(v1, v2){ v1 = v1 || 1; v2 = v2 || 2; return v1 + v2;}console.log(calc());
3.函数调用
function calc(v1, v2, callback) { v1 = v1 || 1; v2 = v2 || 2; return callback(v1, v2);}value1 = calc(3,4, function (v1, v2) { return v1 + v2}); value2 = calc.call(calc, 3, 4, function (v1, v2) { return v1 + v2;}); value3 = calc.apply(calc, [3, 4, function (v1, v2) { return v1 + v2;}]); value4 = (function (v1, v2) { return v1 + v2;})(3, 4);console.group("函数调用的方式");console.log("- 直接调用: " + value1);console.log("- 系统call调用: " + value2);console.log("- 系统apply调用: " + value3);console.log("- 自调用: " + value4);
四、对象
js中对象分为:内建对象、宿主对象和自定义对象。
1.对象创建
直接通过var关键字定义Object对象。
var obj1 = new Object();var obj2 = {};
// 使用字面量来创建一个对象: var obj = {} 和new本质上是一模一样的// 使用字面量创建对象时,可以在创建对象时直接指定对象中的属性// 字面量里面的属性可以加引号,也可以不加引号,建议不加// 如果使用特殊字符或名字则必须加引号var obj = { name: "孙悟空", gender: "男猴", age: 1500, credit: { name1: "孙行者", name2: "齐天大圣" }};console.log(obj);
也可以通过工厂方法创建对象。
function Person(name, age) { var obj = {}; obj.name = name; obj.age = age; obj.sayHello = function () { console.log(obj.name + ", " + obj.age + "years old."); }; return obj;}sun = Person("孙悟空", 2000);sun.sayHello();
2.对象属性操作和方法创建
var obj = new Object(); // new 构造对象, 可使用typeof obj 查看对象// 在对象中保存的值称为属性// 向对象中添加属性:对象.属性名 = 属性值obj.name = "孙悟空";obj.gender = "男猴";obj.age = 18;console.log(obj);// 读取对象中的属性: 对象.属性名// 如果读取的对象中没有该属性,会返回undefinedconsole.log(obj.name);// 修改对象的属性值: 对象.属性名 = 新值obj.age = 24;console.log(obj);// 删除对象属性delete obj.age;console.log(obj);// 自定义obj.fuc = function add(x, y) { return x+y;};console.log(obj);
3.作用域
在js中一共有两种作用域,全局作用域和函数作用域 全局作用域: - 直接编写在script标签内的JS代码 - 在页面打开时创建,在页面关闭时销毁 - 在全局作用域中有一个全局对象window,可以直接使用.它代表的是一个浏览器的窗口,它由浏览器创建 - 在全局作用域中创建的变量都会作为window对象的属性保存 - 在全局作用域中创建的函数都会作为window对象的方法保存 - 全局作用中的变量和函数在页面的任意位置都可以被访问/执行 函数作用域: - 调用函数时创建函数作用域,函数执行完毕之后,函数作用域销毁 - 每调用一次函数就会创建一个新的函数作用域,它们之间是相互独立的 - 全局作用域中访问不到函数作用域,函数作用域中可以访问全局作用域 - 函数作用域会优先查找本作用域中的变量,如果没有就找上一级中的变量 - 函数作用域的a并不影响上一级作用域中的a - 如果不使用var声明,直接写a = 20,就是在操作全局作用域中的a变量 - 如果使用全局作用域中的a变量[在本作用域中已声明a变量],可以用window.a,这在b1中已强调过
全局作用域
console.log(window); // window是个对象 // 使用var关键字声明的变量,会在所有的代码执行之前执行;如果声明变量时不使用var,则变量不会被提前声明console.log(a); // 此时的var a已被声明,它的值是undefined,到下一行时它的值才会是123 var a = 123; // 它相当于window.a = 123console.log(window.a); console.log(abc()); // 可以提前声明和执行console.log(abc2()); // var提前声明的是一个undefined的window属性,不是个函数: abc2 is not a function // 使用function关键字声明的函数,和var的机制一样,是函数声明的提前,它会提前(优先)执行function abc() { // 它相当于window.abc = function (){console.log("abc")} console.log("abc");}console.log(window.abc()); // 使用函数表达式不会被声明提前var abc2 = function() { console.log("abc2");}
局部作用域
var a = 19;var b = 30;function fun() { a = 20; var b = 1000; console.log("a = " + a); // 这里打印的是20 console.log("b = " + b); // 这里打印的是1000 console.log("window.b = " + window.b); // 这里打印的是30}fun();console.log(a); // 这里打印的是20// 定义形参相当于在函数作用域中声明了变量
五、原型
1.this关键字
解析器在调用函数时,会向函数内部传递进一个隐含的参数这个隐含的参数就是this,this指向的是一个对象,这个对象称为函数执行的上下文对象根据函数的调用方式不同,this会指向不同的对象 - 1.以函数的形式调用时,this永远都是window - 2.以方法的形式调用时,this就是调用方法的那个对象
var name = "全局名字";function func(a, b) { console.log("a = " + a + ", b = " + b); console.log(" Object: " + this); console.log(this);}func(123, 456); // this指的是windowfunction func2() { console.log(this.name); console.log(this);}var obj = { name: "孙悟空", sayName: func, // 把函数赋给属性,this指的是obj sayName2: func2 };var obj2 = { name: "猪八戒", sayName: func, // this指的是obj2 sayName2: func2};obj2.sayName(2332, 4523);obj.sayName(234, 789);obj.sayName2(); // this可以支持对象内部的函数去访问对象内部的属性obj2.sayName2(); // 这一点特别像python类中的self
var obj3 = { name: "沙和尚", teacher: "唐僧", address: "流沙河", sayMyTeacher: function3, sayMySelf: function2, say: function1};function function1() { var say = this.sayMySelf() + this.sayMyTeacher(); console.log(say);}function function2() { var say = "大家好,我是" + this.name + ",我老家是" + this.address; return say}function function3() { var say = "。我的师父是" + this.teacher + "老师, 他是个得道高僧"; return say}obj3.say();
2.构造方法的重写
function Person1(name, age, gender) { this.name = name; this.age = age; this.gender = gender; // this.sayName = function() { // console.log("大家好,我系" + this.name); // 这样写每创建一个对象,就会创建一个sayName // } this.sayName = sayName; // 共用同一个方法,它就相当于python中的类方法[类方法只有一份,但每个实例对象都共用]} // 注意这里的写法,一个隐含的this传递给了sayName函数var per1 = new Person1("孙悟空", 18, "男");per1.sayName(); // 在全局作用域中写sayName// 但是它污染了全局作用域的命名空间,也就是全局作用域不能再写sayName函数// 另外这个函数也很不安全,由此引出了"原型"的概念function sayName() { console.log("大家好,我系" + this.name);}
3.原型
1.原型prototype
我们所创建的每一个函数,解析器都会向函数中添加一个属性:prototype如果函数作为普通函数调用prototype,没有任何作用当该函数以构造函数的形式调用[per1]时,它[per1]会有一个隐含的属性__proto__指向其原型对象[Person]每次调用时都会有各自的__proto__指向原型对象的prototype,也就是原型对象中的属性和方法被调用函数"共享"
function Person() {}console.log(Person.prototype); var per1 = new Person();console.log(per1.__proto__ == Person.prototype); // true Person.prototype.a = "我是原型对象中的123456";per1.a = "我是mc中的" +"123456"; var per2 = new Person();console.log(per1.a); // 找到调用函数的属性和方法,直接执行console.log(per2.a); // 如果调用函数没有该属性或方法,会从原型对象中寻找 Person.prototype.sayName = function() { console.log(‘我是原型对象的sayName‘);};per2.sayName = function() { console.log(‘我是per2中的sayName‘);};per1.sayName(); // 和前面的类似per2.sayName(); // 和前面的类似 // 于是现在解决上页的一个全局作用域污染问题: 把对象的函数写在prototype里而不是全局作用域里function MyPerson(name, age, gender) { this.name = name; this.age = age; this.gender = gender; MyPerson.prototype.sayName = function() { // 在自己的prototype空间里写函数 console.log("大家好,我系" + this.name); // 让每个实例都能访问,这才是标准的类方法 }}var mp1 = new MyPerson("孙悟空", 2000, "男猴"); // 注意这里使用的是new MyPerson,构造mp1mp1.sayName(); // 原型对象也有__proto__属性,也会指向原型对象的原型中的prototype// 原型对象的顶层就是Object的对象: obj1.__proto__.__proto__.__proto__ ...
2.原型模拟类和对象
在python中声明一个类和对象:
class Person(object): def __init__(self, name, age): self.name = name self.age = age def sayHello(self): print("{}, {} years old.".format(self.name, self.age)) sun = Person("孙悟空", 2000)sun.sayHello() # 对象可以调用方法,因为方法只有一份且存在类内存中,每个对象只保留了引用Person.sayHello(sun) # 类可以传入一个对象来调用方法,因为方法存在类内存中
在Java中创建一个类和对象:类的方法存在方法区,对象存在堆内存中,多个对象共用它们父类的方法。它需要设置静态方法来实现对象调用。
public class Person { private String name; private int age; Person(String name, int age){ this.name = name; this.age = age; } public void sayHello(){ System.out.println(this.name + ", " + this.age + "years old."); } public static void sayHello(Person obj){ System.out.println(obj.name + ", " + obj.age + "years old."); } public static void main(String[] args){ Person sun = new Person("孙悟空", 2000); Person.sayHello(sun); sun.sayHello(); }}
在js中,对象保存在堆内存中,每创建一个新的对象都会开一个堆内存空间,并把其属性和方法都保存在堆内存中。注意,如果不用原型,每个对象都会将其方法复制一份到自己的堆内存空间中。js中实现类调用实例对象:
function MyPerson(name, age, gender) { this.name = name; this.age = age; this.gender = gender; MyPerson.sayName = MyPerson.prototype.sayName = function (obj) { // 在自己的prototype空间里写函数 obj = obj || this; console.log("大家好,我系" + obj.name + ", 一只火眼金睛的" + obj.gender); // 让每个实例都能访问 }}var mp1 = new MyPerson("孙悟空", 2000, "男猴"); // 注意这里使用的是new MyPerson,构造mp1.sayName();MyPerson.sayName(mp1);
原文地址:https://www.cnblogs.com/kuaizifeng/p/9293408.html
时间: 2024-11-06 03:37:49