1、JavaScript编程语言准备
JavaScript编程语言准备
和b站黑马程序员6天实战游戏开发微信小程序学习
选择的游戏引擎是CocosCreator ,编程语言是JavaScript,游戏后台采用Java。
JavaScript的基本语言基础:
一、变量声明let与const
let 声明的变量只在 let 命令所在的代码块内有效。
const 声明一个只读的常量,一旦声明,常量的值就不能改变。
1、let的使用
1、只在代码块内有效
for (var a = 0; a < 10; a++) {}
console.log(a);
// 输出结果--> 10
for (let b = 0; b < 10; b++) {}
console.log(b);
// 输出结果--> Uncaught ReferenceError: b is not defined
2、不能重复声明
var a = 1;
var a = 2;
console.log(a)
// 输出结果--> 2
let b = 1;
let b = 2;
console.log(b)
// 输出结果--> Uncaught SyntaxError: Identifier 'b' has already been declared
2、const的使用
const 声明一个只读变量,声明之后不允许改变。意味着,一旦声明必须初始化,否则会报错
const PI = "3.1415926";
console.log(PI)
// 输出结果--> 3.1415926
const GENDER;
// 输出结果--> Uncaught SyntaxError: Missing initializer in const declaration
3、暂时性死区
ES6 明确规定,代码块内如果存在 let 或者 const,代码块会对这些命令声明的变量从块的开始就形成一个封闭作用域。代码块内,在声明变量 PI 之前使用它会报错。
var PI = "a";
if (true) {
console.log(PI)
// 输出结果--> a
}
if(true){
console.log(PI);
// 输出结果--> Uncaught ReferenceError: Cannot access 'PI' before initialization
const PI = "3.1415926";
}
二、基本数据类型Symbol
1、Symbol的基本用法
System具有唯一性,而且调用System()函数,可以传入一个字符串参数
let s1 = Symbol()
let s2 = Symbol('another symbol')
let s3 = Symbol('another symbol')
s1 === s2 // false
s2 === s3 // false
}
2、应用场景1:使用Symbol来作为对象属性名
const PROP_NAME = Symbol()
const PROP_AGE = Symbol()
let obj = {
[PROP_NAME]: "一斤代码"
}
obj[PROP_AGE] = 18
obj[PROP_NAME] // '一斤代码'
obj[PROP_AGE] // 18
随之而来的是另一个非常值得注意的问题:就是当使用了Symbol作为对象的属性key后,在对该对象进行key的枚举时,会有什么不同?在实际应用中,我们经常会需要使用Object.keys()或者for…in来枚举对象的属性名,那在这方面,Symbol类型的key表现的会有什么不同之处呢?来看以下示例代码:
let obj = {
[Symbol('name')]: '一斤代码',
age: 18,
title: 'Engineer'
}
Object.keys(obj) // ['age', 'title']
for (let p in obj) {
console.log(p) // 分别会输出:'age' 和 'title'
}
Object.getOwnPropertyNames(obj) // ['age', 'title']
JSON.stringify(obj) // {"age":18,"title":"Engineer"}
有一些专门针对Symbol的API,比如:
// 使用Object的API
Object.getOwnPropertySymbols(obj) // [Symbol(name)]
// 使用新增的反射API
Reflect.ownKeys(obj) // [Symbol(name), 'age', 'title']
3、应用场景2:使用Symbol来替代常量
const TYPE_AUDIO = 'AUDIO'
const TYPE_VIDEO = 'VIDEO'
const TYPE_IMAGE = 'IMAGE'
// 使用Symbol来替代常量(Symbol的唯一性)
const TYPE_AUDIO = Symbol()
const TYPE_VIDEO = Symbol()
const TYPE_IMAGE = Symbol()
三、解构赋值
1、数组模型的解构
(1) 基本使用:
// 基本用法 a=1,b=2,c=3
let [a, b, c] = [1, 2, 3]
// 可嵌套
let [a, [[b], c]] = [1, [[2], 3]];
// 忽略
let [a, , b] = [1, 2, 3];
// 剩余运算符
let [a, ...b] = [1, 2, 3];
// 默认值
let [a = 3, b = a] = []; // a = 3, b = 3
let [a = 3, b ] = [4,6]; // a = 4, b = 6
// 当解构模式有匹配结果,且匹配结果是 undefined 时,会触发默认值作为返回结果。
let [a = 2] = [undefined]; // a = 2
(2) 如果解构不成功,变量的值就等于undefined。
let [foo] = [];
let [bar, foo] = [1];
(3) 可遍历对象皆可解构
let [a, b, c, d, e] = 'hello';
// a = 'h'
// b = 'e'
// c = 'l'
// d = 'l'
// e = 'o'
2、对象模型的解构
// 基本
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
// foo = 'aaa'
// bar = 'bbb'
let { baz : foo } = { baz : 'ddd' };
// foo = 'ddd'
//可嵌套可忽略
let obj = {p: ['hello', {y: 'world'}] };
let {p: [x, { y }] } = obj;
// x = 'hello'
// y = 'world'
let obj = {p: ['hello', {y: 'world'}] };
let {p: [x, { }] } = obj;
// x = 'hello'
//不完全解构
let obj = {p: [{y: 'world'}] };
let {p: [{ y }, x ] } = obj;
// x = undefined
// y = 'world'
// 剩余运算符
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40};
// a = 10
// b = 20
// rest = {c: 30, d: 40}
// 解构默认值
let {a = 10, b = 5} = {a: 3};
// a = 3; b = 5;
let {a: aa = 10, b: bb = 5} = {a: 3};
// aa = 3; bb = 5;
四、函数常见写法及常用函数Math
1、原生函数常见写法
命名函数
function f1(){
console.log("这个函数就是命名函数");
}
匿名函数
function (){
console.log("这个函数就是匿名函数");
}
//可以通过变量接受来调用, 把匿名函数赋给一个变量
var f2 = function(){
console.log("把匿名函数赋给一个变量");
};
f2();//f2中存储的就是函数代码,用变量名加()就是函数调用
自执行函数
//自执行函数或是自调用函数 声明完了,马上进行调用,只能使用一次。
// 格式一:(函数)(实参)
(function (n1,n2){
console.log("这是匿名函数的自执行的第一种写法,结果为:"+(n1+n2))
})(10,100) // -->110
// 格式二:(函数(实参))
(function (n1,n2){
console.log("这是匿名函数的自执行的第二种写法,结果为:"+(n1+n2))
}(10,100)) // -->110
2、箭头函数(ES6新特性)
基本使用
x => x * x
当箭头函数函数体有多行语句,用 {} 包裹起来,表示代码块,当只有一行语句,并且需要返回结果时,可以省略 {} , 结果会自动返回。
let f = (a,b) => {
let result = a+b;
return result;
}
f(1,2); // 3
箭头函数返回对象写法
当箭头函数要返回对象的时候,为了区分于代码块,要用 () 将对象包裹起来
// 错误写法
let f = (id,name) => {id: id, name: name};
f(18,"播仔"); // SyntaxError: Unexpected token :
// 正确写法
let f = (id,name) => ({id: id, name: name});
f(18,"播仔"); // {id: 18, name: ‘播仔’}
箭头函数的this
1、普通函数的this:指向它的调用者,如果没有调用者则默认指向window。
2、箭头函数体中的 this 对象,是定义函数时的对象,而不是使用函数时的对象。
3、箭头函数中的this,首先从它的父级作用域中找,如果父级作用域还是箭头函数,再往上找,如此直至找到this的指向。
//这里只能用var定义变量,let,const定义的变量,不是绑定在window下。
var str = 'window';
const obj = {
str:'obj',
nativeFn: function(){
console.log(this.str, '当前词法作用域中的this');
return function(){
console.log('原生函数',this.str);
}
},
arrowFn: function(){
console.log(this.str, '当前词法作用域中的this');
return ()=>{
console.log('箭头函数',this.str);
}
}
};
const obj2 = {
str:'obj2'
}
var nativeFn = obj.nativeFn();
var arrowFn = obj.arrowFn();
console.log('函数调用一 **********');
nativeFn();
arrowFn();
console.log('函数调用二 **********');
nativeFn.call(obj2);
arrowFn.call(obj2);
3、Math函数在游戏中的使用
随机数
Math.random() 取[0,1)的随机小数
console.log(Math.random());
取整
// 向上取整
console.log(Math.ceil(12.03));//13
console.log(Math.ceil(-12.92));//-12
// 向下取整
console.log(Math.floor(12.3));//12
console.log(Math.floor(-12.9));//-13
// 四舍五入
console.log(Math.round(16.3)) // 16
console.log(Math.round(16.5)) // 17
console.log(Math.round(-16.5))// -16
console.log(Math.round(-16.51))// -17
绝对值
console.log(Math.abs(-12)) // 12
圆周率和三角函数
假设我们现在做一个二维射击游戏,他的地图就是一个二维笛卡尔坐标,已知敌人和枪手的坐标点,要计算枪手射击角度,我们就需要用到三角函数相关的api
// 枪手
let a = [100,100]
// 敌人
let b = [200,200]
let x = Math.abs(a[0] - b[0])
let y = Math.abs(a[1] - b[1])
// 求斜边
let z = Math.sqrt(x * x + y * y)
// 计算射击角度
let angle = Math.asin(y / z) / Math.PI * 180
console.log(Math.round(angle))
幂计算和开方
Math.pow(10,2) = 100;
Math.sqrt(100) = 10;
五、Map&Set
1、Map 对象
Map 和 Object 的区别:
一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。
Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
Map 的基本使用
// 普通字符串作为key值
let strMap = new Map();
strMap.set("str","key是String类型的值");
let str = strMap.get("str");
console.log(str)
// 对象作为key值
let objMap = new Map();
let keyObj = {};
objMap.set(keyObj, "和键 keyObj 关联的值");
let obj = objMap.get(keyObj);
console.log(obj)
objMap.size // 1
2、Set 对象
Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
和Array互相转换
// Array 转 Set
let mySet = new Set(["value1", "value2", "value3"]);
// 用...操作符,将 Set 转 Array
let myArray = [...mySet];
// String 转 Set
let mySet = new Set('hello'); // Set(4) {"h", "e", "l", "o"}
Set 对象作用
数组去重
let mySet = new Set([1, 2, 3, 4, 4]);
[...mySet]; // [1, 2, 3, 4]
并集
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
let union = new Set([...a, ...b]); // {1, 2, 3, 4}
交集
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
let intersect = new Set([...a].filter(x => b.has(x))); // {2, 3}
差集
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
let difference = new Set([...a].filter(x => !b.has(x))); // {1}
六、面向对象编程
1、面向对象
ES6是支持class关键字的
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
cocos creator 源码 CCClass
function CCClass (options) {
options = options || {};
var name = options.name;
var base = options.extends/* || CCObject*/;
var mixins = options.mixins;
// create constructor
var cls = define(name, base, mixins, options);
if (!name) {
name = cc.js.getClassName(cls);
}
cls._sealed = true;
if (base) {
base._sealed = false;
}
// define Properties
var properties = options.properties;
if (typeof properties === 'function' ||
(base && base.__props__ === null) ||
(mixins && mixins.some(function (x) {
return x.__props__ === null;
}))
) {
if (CC_DEV && options.__ES6__) {
cc.error('not yet implement deferred properties for ES6 Classes');
}
else {
deferredInitializer.push({cls: cls, props: properties, mixins: mixins});
cls.__props__ = cls.__values__ = null;
}
}
else {
declareProperties(cls, name, properties, base, options.mixins, options.__ES6__);
}
// define statics
var statics = options.statics;
if (statics) {
var staticPropName;
if (CC_DEV) {
for (staticPropName in statics) {
if (INVALID_STATICS_DEV.indexOf(staticPropName) !== -1) {
cc.errorID(3642, name, staticPropName,
staticPropName);
}
}
}
for (staticPropName in statics) {
cls[staticPropName] = statics[staticPropName];
}
}
// define functions
for (var funcName in options) {
if (BUILTIN_ENTRIES.indexOf(funcName) >= 0) {
continue;
}
var func = options[funcName];
if (!preprocess.validateMethodWithProps(func, funcName, name, cls, base)) {
continue;
}
// use value to redefine some super method defined as getter
js.value(cls.prototype, funcName, func, true, true);
}
var editor = options.editor;
if (editor) {
if (js.isChildClassOf(base, cc.Component)) {
cc.Component._registerEditorProps(cls, editor);
}
else if (CC_DEV) {
cc.warnID(3623, name);
}
}
return cls;
}