web生涯
1.css3@media规则
使用 @media 查询,你可以针对不同的媒体类型定义不同的样式。
@media 可以针对不同的屏幕尺寸设置不同的样式,特别是如果你需要设置设计响应式的页面,@media 是非常有用的。
当你重置浏览器大小的过程中,页面也会根据浏览器的宽度和高度重新渲染页面。
列:如果文档宽度小于 300 像素则修改背景颜色(background-color):
@media screen and (max-width: 300px) {
body {
margin: 0px; padding: 0px; color: rgb(170, 17, 17); font-family: Menlo, Monaco, Consolas, "Andale Mono", "lucida console", "Courier New", monospace; font-size: 13.2px;">lightblue;
}
}
你也可以针对不同的媒体使用不同 stylesheets :
<link rel="stylesheet" media="mediatype and|not|only (media feature)" href="mystylesheet.css">
2.HTML5响应式(自适应)网页设计
指可以自动识别屏幕宽度、并做出相应调整的网页设计
1、允许网页宽度自动调整 在网页代码的头部,加入一行viewport元标签
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no">
1)width=device-width :表示宽度是设备屏幕的宽度
2)initial-scale=1.0:表示初始的缩放比例,1.0就是占网页的100%
3)minimum-scale=1.0:表示最小的缩放比例
4)maximum-scale=1.0:表示最大的缩放比例
5)user-scalable=no:表示用户是否可以调整缩放比例
所有主流浏览器都支持这个设置,包括IE9。对于那些老式浏览器(主要是IE6、7、8),需要使用css3-mediaqueries.js。
<!–[if lt IE 9]><script src=”http://css3-mediaqueries-js.googlecode.com/svn/trunk/css3-mediaqueries.js”></script><![endif]–>
2、不使用绝对宽度
由于网页会根据屏幕宽度调整布局,所以不能使用绝对宽度的布局,也不能使用具有绝对宽度的元素。这一条非常重要。
具体说,CSS代码不能指定像素宽度:width:xxx px;只能指定百分比宽度:width: xx%;或者width:auto;
3、相对大小的字体
字体也不能使用绝对大小(px),而只能使用相对大小(em)。body {font: normal 100% Helvetica, Arial, sans-serif;}
上面的代码指定,字体大小是页面默认大小的100%,即16像素。h1 {font-size: 1.5em;}
然后,h1的大小是默认大小的1.5倍,即24像素(24/16=1.5)。small {font-size: 0.875em;}
small元素的大小是默认大小的0.875倍,即14像素(14/16=0.875)。
4、流动布局(fluid grid)
“流动布局”的含义是,各个区块的位置都是浮动的,不是固定不变的。
.main {float: right;width: 70%;}.leftBar {float: left;width: 25%;}
5、选择加载CSS
自适应网页设计”的核心,就是CSS3引入的Media Query模块。自动探测屏幕宽度,然后加载相应的CSS文件。
<link rel="stylesheet" type="text/css" media="screen and (min-width: 400px) and (max-device-width: 600px)"href="smallScreen.css" />
6、图片的自适应(fluid image)
除了布局和文本,”自适应网页设计”还必须实现图片的自动缩放。
这只要一行CSS代码:img { max-width: 100%;}
这行代码对于大多数嵌入网页的视频也有效,所以可以写成:img, object { max-width: 100%;}
老版本的IE不支持max-width,所以只好写成:img { width: 100%; }
此外,windows平台缩放图片时,可能出现图像失真现象。这时,可以尝试使用IE的专有命令:img { -ms-interpolation-mode: bicubic; }
3.null instanceof Object
instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
object(参数) instanceof constructor(要检测的对象)
alert(typeof(null)); //object alert(null instanceof Object); //false
这是由Javascript规范规定的,Null和Object都是javascript中的数据类型。
Null数据类型只有一个值:null。就像undefined数据类型只有一个值:undefined。
问题出在typeof操作符的定义规范,如下
11.4.3 The typeof Operator The production UnaryExpression : typeof UnaryExpression is evaluated as follows:
1. Evaluate UnaryExpression.
2. If Type(Result(1)) is not Reference, go to step 4.
3. If GetBase(Result(1)) is null, return "undefined".
4. Call GetValue(Result(1)).
5. Return a string determined by Type(Result(4)) according to the following table: Type Result
Undefined "undefined"
Null "object"
Boolean "boolean"
Number "number"
String "string"
Object (native and doesn’t implement [[Call]]) "object"
Object (native and implements [[Call]])
"function" Object (host) Implementation-dependent
可以看到,对于Null类型的值(只有null),规范就是定义返回”object”这个字符串。但是本质上Null和Object不是一个数据类型,null值并不是以Object为原型创建出来的。所以null instanceof Object是false。但从这里也可以看到,null确实是javascript中用来表示空引用的 一个特殊值。使得它不是instanceof Ojbect,而typeof null是“object”。在语义上也是可以理解的。
1 instanceof Number //false
var a = new Number(1);
a instanceof Number // true
instanceof判断一个对象是否是另一个对象的实例,而数字1是基本数据类型,不是对象,
var a = new Number(1);是通过包装类Number把数字1转换成对象,你可以用typeof a,和typeof 1,看看他们返回的值
原始类型 使用instanceof 都返回false 而第一个是使用Number把1包装成了对象
4.类型转换
var aa = function(){return true},
bb = function(){return false};
(function(){
if( (aa() && [])==![] ){
aa = function(){
return false
};
function bb(){return true}
}
})();
console.log("aa"+aa());
console.log("bb"+bb());
alert( [] == ![] )//true
[] == ![]
[] == !true // ! 操作符的优先级高于 == ,所以先执行 ! 操作
[] == false // !true 得到的是 false
[] == 0 //比较规则1:如果值为true或false,则转成1或0来继续比较
[] == 0 //执行左侧的 [] 的 valueOf 方法,而 [] 是对象,所以 [].valueOf() 返回本身 []
"" == 0 //执行左侧的 [] 的 toString 方法,[].toString() 返回 ""
0 == 0 //比较规则2:如果一个值是数字,一个值是字符串,则把字符串转换为数字,再进行比较,"" 转成数字是 0。
- 如果其中一个值是true,则将其转换为1再进行比较。如果其中一个值是false,则将其转换为0再进行比较。
- 如果一个值是对象,另一个值是数字或字符串,则将对象转换为原始值再进行比较。对象通过toString()方法或valueOf()方法转换为原始值。JavaScript语言核心的内置类首先尝试使用valueOf(),在尝试使用toString(),除了日期类,日期类只使用toString()方法,那些不是JavaScript语言核心中的对象则通过各自实现中定义的方法转换为原始值。
有了以上两条作为基础,我们再来看问题。
控制台指出等号右边为布尔值,由第一条可知,它将转换为数字0,也就是数字类型。
!的优先级较==高,先运算==左侧的操作数:[]是对象,会转换成true,然后再转成false(加!的一定是转换成boolean)
== 的左操作数是[],数组(对象处了日期对象,都是对象到数字的转换),碰到==要先调用自己的valueOf()方法=>[](还是本身),然后调用自己的toString()方法=>空字符串=>false (或者空字符串转成0,然后再转成false,但是终归会是false)
false==false
执行类型转换的规则如下:
如果一个运算数是 Boolean 值,在检查相等性之前,把它转换成数字值。false 转换成 0,true 为 1。
如果一个运算数是字符串,另一个是数字,在检查相等性之前,要尝试把字符串转换成数字。
如果一个运算数是对象,另一个是字符串,在检查相等性之前,要尝试把对象转换成字符串。
如果一个运算数是对象,另一个是数字,在检查相等性之前,要尝试把对象转换成数字。
在比较时,该运算符还遵守下列规则:
值 null 和 undefined 相等。
在检查相等性时,不能把 null 和 undefined 转换成其他值。
如果某个运算数是 NaN,等号将返回 false,非等号将返回 true。
如果两个运算数都是对象,那么比较的是它们的引用值。如果两个运算数指向同一对象,那么等号返回 true,否则两个运算数不等。
5.回调地狱
1。回调函数是JavaScript里约定俗成的一个名称。实际上并不存在确定的“回调函数”,只是大家就管那个位置的函数作回调函数。与大多数运行后立刻给出结果的函数不同,使用回调的函数要花一些时间才能得出结果。“异步”这个词就是代表‘要花时间,将来运行’。通常回调函数会用在下载文件、读取文件、或者数据库相关事务等
处理:
a.不要嵌套函数,命名后调用更好
b.使用函数提升
c.创建可重用函数,写成模块,让你更容易读懂代码。把你的代码拆分成小块可以帮助你处理错误,写测试,重构,方便为你的代码写更稳定的API
d.处理回调函数的每一个错误
一些写模块的经验:
-
先把经常重复使用的功能写成一个函数
-
当这个函数写得够大之后,把他移动到另一个文件,用
module.exports暴露它,然后用require引入 -
如果你的代码是通用的,可以写readme文件和
package.json发布到npm或者github -
一个好模块,体积要小,而且针对只一个问题
-
模块中的单个文件不应超过约150行
-
模块不应该有多个级别的嵌套文件夹,其中包含JavaScript文件。如果是这样,它可能做的太多了
让有经验的程序员介绍你一些好用的模块,尝试理解这个模块的功能,如果花了几分钟的话,这个模块可能就不够好了
6.字符串去除空格
去掉字符串前后所有空格:
function Trim(str) { return str.replace(/(^\s*)|(\s*$)/g, ""); } function Trim(str,is_global) { var result; result = str.replace(/(^\s+)|(\s+$)/g,""); if(is_global.toLowerCase()=="g") { result = result.replace(/\s/g,""); } return result;}if (!String.prototype.trim){ /*--------------------------------------- * 清除字符串两端空格,包含换行符、制表符 *---------------------------------------*/ String.prototype.trim = function () { return this.replace(/(^[\s\n\t]+|[\s\n\t]+$)/g, ""); }}var str = " abcd ".trim();7.箭头函数
const Person = {
'name': 'little bear',
'age': 18,
'sayHello': function () {
setInterval(function () {
console.log('我叫' + this.name + '我今年' + this.age + '岁!')
}, 1000)
}
}
Person.sayHello()
上例的输出结果是什么呢?可能对javascript特性不是很熟悉的同学(我自己也是)会认为输出当然是
我叫little bear,今年18岁咯。如果你的答案是这个的话,那么我要恭喜你,答错了。其实上例的输出结果是我叫undefined,今年我undefined岁。为什么会输出这种结果呢?
这是因为setInterval执行的时候,是在全局作用域下的,所有this指向的是全局window,而window上没有name和age,所以当然输出的是undefined咯。不明白的同学可以去看看this的工作原理this。
那么,我们怎么要解决这个问题呢?
通常的写法是缓存this,然后在setInterval中用缓存的this进行操作,如下
const Person = {
'name': 'little bear',
'age': 18,
'sayHello': function () {
let self = this
setInterval(function () {
console.log('我叫' + self.name + '我今年' + self.age + '岁!')
}, 1000)
}
}
const sayHelloFun = Person.sayHello
sayHelloFun()
箭头函数的语法非常简单,看一下最简单的箭头函数表示法
() => console.log('Hello')
之前没有接触过箭头函数的人可能会惊讶于其代码的简洁。对比之前如果要写一个这样的函数
function(){
console.log('hello')
}
从上面的例子中,我们已经可以看出箭头函数的优势。
和普通函数相比,箭头函数主要就是以下两个方面的特点
- 不绑定this,arguments
- 更简化的代码语法
什么叫不绑定this,我个人的理解为箭头函数的this其实就是在定义的时候就确定好的,以后不管怎么调用这个箭头函数,箭头函数的this始终为定义时的this
我们还是以前面的那个setInterval代码为例
const Person = {
'name': 'little bear',
'age': 18,
'sayHello': function () {
setInterval(function () {
console.log('我叫' + this.name + '我今年' + this.age + '岁!')
}, 1000)
}
Person.sayHello()
当Person.sayHello()去执行setInterval的时候,是在全局作用下执行的所有setInterval回调函数的this就为全局对象。es3-5中的函数this的值和调用这个函数的上下文有关。(注意是调用)
我们用箭头函数重写上诉函数
const Person = {
'name': 'little bear',
'age': 18,
'sayHello': () => {
setInterval(() => {
console.log('我叫' + this.name + '我今年' + this.age + '岁!')
}, 1000)
}
Person.sayHello()
大家猜猜结果是什么???
输出的是我叫'little bear',今年18岁嘛?
哈哈,太天真了,我开始也是这样想的,后面输出之后发现结果不对,输出的还是undefined。为什么呢??
因为我把方法写在了对象里,而对象的括号是不能封闭作用域的。所以此时的this还是指向全局对象。
所以,通过以上的错误可以提醒我们,最好不要用箭头函数作为对象的方法。
我们需要重新举一个例子,如下
function Person () {
this.name = 'little bear',
this.age = 18
let self = this
setInterval(function sayHello () {
console.log('我叫' + self.name + '我今年' + self.age + '岁!')
}, 1000)
}
let p = new Person()
缓存this,然后输出,能达到我们想要的结果。
把上述例子改为箭头函数的形式如下
function Person () {
this.name = 'little bear',
this.age = 18
setInterval(() => {
console.log('我叫' + this.name + '我今年' + this.age + '岁')
},1000)
}
let p = new Person()
箭头函数还有一个比较有特点的地方就是其不绑定arguments,即如果你在箭头函数中使用arguments参数不能得到想要的内容。
let arrowfunc = () => console.log(arguments.length)
arrowfunc()
//output
arguments is not defined
所以在箭头函数中我们是不能直接使用arguments对象的,但是如果我们又想获得函数的参数怎么办呢?
我们可以使用剩余参数来取代arguments剩余参数详情
let arrowfunc = (...theArgs) => console.log(theArgs.length)
arrowfunc(1,2)
//output
2
什么时候不能用剪头函数
前面我们已经看到了很多关于es6箭头函数的好处,也看到了箭头函数的一些不足。那么我们应该在什么时候使用箭头函数,而什么时候最好不要使用呢?
1.作为对象的方法
在写这篇博客的例子时,由于本人的水平确实有限,导致了篇头出现的错误。不过我也想由此告诉大家,最好不要在对象的方法中使用箭头函数,这样可能会导致一些问题的产生。除非你很熟悉箭头函数。
2.不能作为构造函数
由于箭头函数的this不绑定的特点,所以不能使用箭头函数作为构造函数,实际上如果这样做了,也会报错。
3.定义原型方法
function Person (name){
this.name = name
}
Person.prototype.sayHello = () => {
console.log(this)
}
var p1 = new Person()
p1.sayHello()
//output
window对象
这里的this指向的是window对象,这点和在对象方法中定义有点像
8.ES6扩展运算符
扩展运算符( spread )是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列
应用
(1)合并数组
- // ES5
- [1, 2].concat(more)
- // ES6
- [1, 2, ...more]
- var arr1 = ['a', 'b'];
- var arr2 = ['c'];
- var arr3 = ['d', 'e'];
- // ES5 的合并数组
- arr1.concat(arr2, arr3);
- // [ 'a', 'b', 'c', 'd', 'e' ]
- // ES6 的合并数组
- [...arr1, ...arr2, ...arr3]
- // [ 'a', 'b', 'c', 'd', 'e' ]
(2)与解构赋值结合
- / ES5
- a = list[0], rest = list.slice(1)
- // ES6
- [a, ...rest] = list
- 下面是另外一些例子。
- const [first, ...rest] = [1, 2, 3, 4, 5];
- first // 1
- rest // [2, 3, 4, 5]
- const [first, ...rest] = [];
- first // undefined
- rest // []:
- const [first, ...rest] = ["foo"];
- first // "foo"
- rest // []
(3)函数的返回值
JavaScript 的函数只能返回一个值,如果需要返回多个值,只能返回数组或对象。扩展运算符提供了解决这个问题的一种变通方法。
- var dateFields = readDateFields(database);
- var d = new Date(...dateFields);
上面代码从数据库取出一行数据,通过扩展运算符,直接将其传入构造函数Date
(4)字符串
- [...'hello']
- // [ "h", "e", "l", "l", "o" ]
9.Object.assign()
Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
如果目标对象中的属性具有相同的键,则属性将被源中的属性覆盖。后来的源的属性将类似地覆盖早先的属性。
const object1 = {
a: 1,
b: 2,
c: 3
};
const object2 = Object.assign({c: 4, d: 5}, object1);
console.log(object2.c, object2.d);
// expected output: 3 5
Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象。该方法使用源对象的[[Get]]和目标对象的[[Set]],所以它会调用相关 getter 和 setter。因此,它分配属性,而不仅仅是复制或定义新的属性。如果合并源包含getter,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到原型,应使用Object.getOwnPropertyDescriptor()和Object.defineProperty() 。
复制一个对象
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
深拷贝问题
针对深拷贝,需要使用其他方法,因为 Object.assign()拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值。
function test() {
'use strict';
let obj1 = { a: 0 , b: { c: 0}};
let obj2 = Object.assign({}, obj1);
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
obj1.a = 1;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
obj2.a = 2;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}
obj2.b.c = 3;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}}
// Deep Clone
obj1 = { a: 0 , b: { c: 0}};
let obj3 = JSON.parse(JSON.stringify(obj1));
obj1.a = 4;
obj1.b.c = 4;
console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}
}
test();
10.数组字符串互相转换
var a, b;
a = new Array(0,1,2,3,4);
b = a.join("-"); //"0-1-2-3-4"
var s = "abc,abcd,aaa";
ss = s.split(",");// 在每个逗号(,)处进行分解 ["abc", "abcd", "aaa"]
var s1 = "helloworld";
ss1 = s1.split(''); //["h", "e", "l", "l", "o", "w", "o", "r", "l", "d"]
11.js的DOM创建删除查找
一、创建节点、追加节点
1、createElement(标签名)创建一个元素节点(具体的一个元素)。
2、appendChild(节点)追加一个节点。
3、createTextNode(节点文本内容)创建一个文本节点
- var oDiv = document.createElement("div");//创建一个div元素,因为是document对象的方法。
- var oDivText = document.createTextNode("666");//创建一个文本节点内容是“666”,因为是document对象的方法。
- oDiv.appendChild(oDivText);//父级.appendChild(子节点);在div元素中添加“666”
- document.body.appendChild(oDiv);//父级.appendChild(子节点);;document.body是指向<body>元素
- document.documentElement.appendChild(createNode);//父级.appendChild(子节点);;document.documentElement是指向<html>元素
二、插入节点
1、appendChild(节点)也是一种插入节点的方式,还可以添加已经存在的元素,会将其元素从原来的位置移到新的位置。
2、insertBefore(a,b)是参照节点,意思是a节点会插入b节点的前面。
- var oDiv = document.createElement("div");//创建一个div元素,因为是document对象的方法。
- var oDiv1 = document.getElementById("div1");
- document.body.insertBefore(oDiv,oDiv1);//在oDiv1节点前插入新创建的元素节点
- ul.appendChild(ul.firstChild); //把ul的第一个元素节点移到ul子节点的末尾
三、删除、移除节点
1、removeChild(节点) 删除一个节点,用于移除删除一个参数(节点)。其返回的被移除的节点,被移除的节点仍在文档中,只是文档中已没有其位置了。
var removeChild = document.body.removeChild(div1);//移除document对象的方法div1
五、查找节点
1、childNodes 包含文本节点和元素节点的子节点。
- for (var i = 0; i < oList.childNodes.length; i++) {//oList是做的ul的对象。
- //nodeType是节点的类型,利用nodeType来判断节点类型,再去控制子节点
- //nodeType==1 是元素节点
- //nodeType==3 是文本节点
- if (oList.childNodes[i].nodeType == 1) {//查找到oList内的元素节点
- console.log(oList.childNodes[i]);//在控制器日志中显示找到的元素节点
- }
- }
B、parentNode:获取父节点
- var oList = document.getElementById('list');//oList是做的ul的对象
- var oChild=document.getElementById('child');//oChild是做的ul中的一个li的对象
- //通过子节点查找父节点//parentNode:获取父节点
- console.log(oChild.parentNode);//在控制器日志中显示父节点
- console.log(oList.children);//在控制器日志中显示oList子节点
- console.log(children.length)//子节点的个数
B、lastChild ; lastElementChild查找最后一个子节点。此存在浏览器兼容问题:lastChild 是IE兼容,lastElementChild是非IE兼容。
C、nextSibling ; nextElementSibling查找下一个兄弟节点。也是存在兼容性问题。
D、previousSibling ; previousElementSibling查找上一个兄弟节点。也是存在兼容性问题。
12.数据存数
localStorage:
是一种你不主动清除它,它会一直将存储数据存储在客户端的存储方式,即使你关闭了客户端(浏览器),属于本地持久层储存
sessionStorage:
用于本地存储一个会话(session)中的数据,一旦会话关闭,那么数据会消失,比如刷新。
localStorage与sessionStorage具有相同的API,以下方法都可以用于sessionStorage
localStorage.name ='vanida;
localStorage["name"]='vanida';
localStorage.setItem("name","vanida");
获取
var name = localStorage["name"]
var name= localStorage.name
var name= localStorage.getItem("name");
localStorage清除特定值方法
//清除name的值
localStorage.removeItem("name");
localStorage.name='';
localStorage清除所有值方法
localStorage.clear()
二、localStorage的优势与局限
localStorage的优势
1、localStorage拓展了cookie的4K限制
2、localStorage会可以将第一次请求的数据直接存储到本地,这个相当于一个5M大小的针对于前端页面的数据库,相比于cookie可以节约带宽,但是这个却是只有在高版本的浏览器中才支持的
localStorage的局限
1、浏览器的大小不统一,并且在IE8以上的IE版本才支持localStorage这个属性
2、目前所有的浏览器中都会把localStorage的值类型限定为string类型,这个在对我们日常比较常见的JSON对象类型需要一些转换
3、localStorage在浏览器的隐私模式下面是不可读取的
4、localStorage本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡
5、localStorage不能被爬虫抓取到
localStorage与sessionStorage的唯一一点区别就是localStorage属于永久性存储,而sessionStorage属于当会话结束的时候,sessionStorage中的键值对会被清空。
13.地理定位
function getLocation(){
if (navigator.geolocation){
navigator.geolocation.getCurrentPosition(showPosition);
}
else{alert("不支持定位")}
}
function showPosition(position){
alert("Latitude: " + position.coords.latitude + "<br />Longitude: " + position.coords.longitude)
}
getLocation();
14.em px rem
px像素(Pixel)。相对长度单位。像素px是相对于显示器屏幕分辨率而言的。一般默认16px
em是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。
EM特点
- 1. em的值并不是固定的;
- 2. em会继承父级元素的字体大小。
rem是CSS3新增的一个相对单位(root em,根em),这个单位引起了广泛关注。这个单位与em有什么区别呢?区别在于使用rem为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素。这个单位可谓集相对大小和绝对大小的优点于一身,通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。
15.call
window.val = 1;
var json = {
val: 10,
dbl: function(){
this.val *=2
}
};
json.dbl();
json.dbl.call(window);
alert(window.val+json.val);
16.变量提升
var name = "World";
(function(){
if(typeof name ==="undefined"){
var name = "Jack";
console.log("GoodBye" + name);
}else{
console.log('hello' + name)
}
})();
17.异步
console.log('one');
setTimeout(function(){
console.log('two')
},0);
console.log('three');
for(var i = 0;i < 10;i++){
setTimeout(function(){
console.log(i);
},0)
}

浙公网安备 33010602011771号